Import 1.3.991.3.99
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:57 +0000 (23 15:10 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:57 +0000 (23 15:10 -0500)
258 files changed:
CREDITS
Documentation/Configure.help
Documentation/SMP.txt
Documentation/devices.tex
Documentation/devices.txt
Documentation/filesystems/affs.txt
Documentation/ioctl-number.txt[new file with mode: 0644]
Documentation/isdn/INTERFACE
Documentation/isdn/README
Documentation/magic-number.txt[new file with mode: 0644]
Documentation/networking/arcnet-hardware.txt
Documentation/networking/framerelay.txt
Documentation/nfsroot.txt
Documentation/oops-tracing.txt
Documentation/ramdisk.txt
Documentation/rtc.txt
MAGIC[deleted file]
MAINTAINERS
Makefile
README
arch/alpha/config.in
arch/alpha/kernel/bios32.c
arch/i386/boot/Makefile
arch/i386/config.in
arch/i386/kernel/irq.c
arch/i386/kernel/setup.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/kernel/time.c
arch/i386/kernel/traps.c
arch/i386/math-emu/errors.c
arch/i386/math-emu/fpu_emu.h
arch/i386/math-emu/fpu_entry.c
arch/i386/math-emu/reg_ld_str.c
arch/i386/math-emu/version.h
arch/m68k/amiga/Makefile
arch/m68k/amiga/amipart.c[deleted file]
arch/m68k/amiga/config.c
arch/m68k/atari/Makefile
arch/m68k/atari/atafb.c
arch/m68k/atari/atapart.c[deleted file]
arch/m68k/atari/config.c
arch/m68k/config.in
arch/m68k/console/fbcon.c
arch/m68k/defconfig
arch/m68k/fpsp040/skeleton.S
arch/m68k/ifpsp060/ilsp.doc
arch/m68k/kernel/console.c
arch/m68k/kernel/head.S
arch/m68k/kernel/setup.c
arch/m68k/kernel/traps.c
arch/m68k/mm/fault.c
arch/m68k/mm/memory.c
arch/mips/config.in
arch/mips/kernel/head.S
arch/mips/kernel/time.c
arch/mips/mm/init.c
arch/ppc/config.in
arch/ppc/kernel/head.S
arch/sparc/boot/README
arch/sparc/kernel/head.S
arch/sparc/kernel/irq.c
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/switch.S
arch/sparc/kernel/wof.S
arch/sparc/mm/srmmu.c
arch/sparc/prom/tree.c
drivers/block/Config.in
drivers/block/Makefile
drivers/block/README.ide
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/ll_rw_blk.c
drivers/block/loop.c
drivers/block/xd.c
drivers/cdrom/aztcd.c
drivers/char/ChangeLog
drivers/char/console.c
drivers/char/fbmem.c
drivers/char/ftape/ftape-read.c
drivers/char/ftape/kernel-interface.c
drivers/char/istallion.c
drivers/char/lp.c
drivers/char/lp_m68k.c
drivers/char/pcxx.c
drivers/char/psaux.c
drivers/char/pty.c
drivers/char/random.c
drivers/char/rtc.c
drivers/char/stallion.c
drivers/char/vc_screen.c
drivers/char/vga.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_net.c
drivers/isdn/isdn_ppp.c
drivers/net/3c501.c
drivers/net/8390.c
drivers/net/8390.h
drivers/net/Makefile
drivers/net/README.eql
drivers/net/README.tunnel
drivers/net/Space.c
drivers/net/arcnet.c
drivers/net/dgrs.c
drivers/net/dgrs_driver.c
drivers/net/dlci.c
drivers/net/dummy.c
drivers/net/eexpress.c
drivers/net/eql.c
drivers/net/eth16i.c
drivers/net/hp100.h
drivers/net/hydra.c[new file with mode: 0644]
drivers/net/hydra.h[new file with mode: 0644]
drivers/net/ibmtr.c
drivers/net/lance32.c
drivers/net/loopback.c
drivers/net/ne.c
drivers/net/new_tunnel.c
drivers/net/ppp.c
drivers/net/sdla.c
drivers/net/seeq8005.c
drivers/net/seeq8005.h
drivers/net/sk_g16.c
drivers/net/slhc.c
drivers/net/slip.c
drivers/net/smc-ultra.c
drivers/sbus/char/sunkeymap.map
drivers/sbus/char/sunserial.c
drivers/scsi/53c7,8xx.c
drivers/scsi/ChangeLog
drivers/scsi/Config.in
drivers/scsi/README.st
drivers/scsi/aha1542.c
drivers/scsi/aic7xxx.c
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma.h
drivers/scsi/eata_generic.h
drivers/scsi/eata_pio.c
drivers/scsi/eata_pio.h
drivers/scsi/fdomain.c
drivers/scsi/hosts.c
drivers/scsi/pas16.c
drivers/scsi/scsi_debug.c
drivers/scsi/sd.c
drivers/scsi/seagate.c
drivers/scsi/sr.c
drivers/scsi/wd33c93.h
drivers/sound/CHANGELOG
drivers/sound/Readme.cards
drivers/sound/ad1848.c
drivers/sound/gus_wave.c
drivers/sound/mpu401.c
drivers/sound/sound_switch.c
fs/Config.in
fs/affs/Makefile
fs/affs/amigaffs.c
fs/affs/amigaffs.h[deleted file]
fs/affs/bitmap.c[new file with mode: 0644]
fs/affs/dir.c
fs/affs/file.c
fs/affs/inode.c
fs/affs/namei.c
fs/affs/symlink.c
fs/block_dev.c
fs/buffer.c
fs/ext/file.c
fs/fat/dir.c
fs/fat/msbuffer.h
fs/isofs/inode.c
fs/isofs/rock.c
fs/locks.c
fs/nfs/nfsroot.c
fs/super.c
fs/sysv/file.c
fs/ufs/ufs_super.c
fs/umsdos/namei.c
fs/vfat/Makefile
fs/vfat/namei.c
fs/xiafs/file.c
include/asm-i386/locks.h
include/asm-m68k/atomic.h
include/asm-m68k/bitops.h
include/asm-m68k/checksum.h
include/asm-m68k/elf.h
include/asm-m68k/pgtable.h
include/asm-m68k/serial.h[new file with mode: 0644]
include/asm-m68k/system.h
include/asm-mips/shmparam.h
include/asm-sparc/floppy.h
include/asm-sparc/head.h
include/asm-sparc/kdebug.h
include/asm-sparc/smp.h
include/asm-sparc/system.h
include/linux/a.out.h
include/linux/affs_fs.h
include/linux/affs_fs_i.h
include/linux/affs_fs_sb.h
include/linux/affs_hardblocks.h[new file with mode: 0644]
include/linux/amigaffs.h[new file with mode: 0644]
include/linux/genhd.h
include/linux/hdreg.h
include/linux/if_arp.h
include/linux/if_frad.h
include/linux/in.h
include/linux/isdn.h
include/linux/isdnif.h
include/linux/kernel.h
include/linux/math_emu.h
include/linux/mc146818rtc.h
include/linux/mroute.h
include/linux/msdos_fs.h
include/linux/netdevice.h
include/linux/skbuff.h
include/linux/string.h
include/net/netlink.h
include/net/route.h
include/net/slhc_vj.h[moved from drivers/net/slhc.h with 100% similarity]
include/net/sock.h
include/net/tcp.h
ipc/msg.c
kernel/module.c
kernel/sched.c
mm/filemap.c
mm/swapfile.c
net/Changes
net/TUNABLE
net/ax25/af_ax25.c
net/ax25/ax25_out.c
net/ax25/ax25_subr.c
net/core/dev.c
net/core/net_alias.c
net/ethernet/eth.c
net/ipv4/Config.in
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/igmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_masq.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/packet.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipx/af_ipx.c
net/netrom/af_netrom.c
net/socket.c
net/unix/af_unix.c
scripts/Menuconfig
scripts/tkcond.c
scripts/tkparse.c

index eab18ac..73ac9b6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -122,6+122,14 @@ E: hennus@sky.ow.nl [My uucp-fed Linux box at home]
 D: Author and maintainer of the QIC-02 tape driver
 S: The Netherlands
 
+N: Thomas Bogendoerfer
+E: tsbogend@bigbug.franken.de
+D: Lance32 driver
+D: strace for Linux/Alpha
+S: Baumgartenweg 5
+S: 91452 Wilhermsdorf
+S: Germany
+
 N: Ross Biro
 E: bir7@leland.Stanford.Edu
 D: Original author of the Linux networking code
@@ -424,14+432,6 @@ S: 906-1001 Bay St.
 S: Toronto, Ontario, M5S 3A6 
 S: Canada
 
-N: Miquel van Smoorenburg
-E: miquels@cistron.nl
-D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
-S: Cistron Internet Services
-S: PO-Box 297
-S: 2400 AG, Alphen aan den Rijn
-S: The Netherlands
-
 N: Danny ter Haar
 E: dth@cistron.nl
 D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;)
@@ -1086,6+1086,14 @@ D: HPFS filesystem
 S: Richardson, Texas
 S: USA
 
+N: Miquel van Smoorenburg
+E: miquels@cistron.nl
+D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
+S: Cistron Internet Services
+S: PO-Box 297
+S: 2400 AG, Alphen aan den Rijn
+S: The Netherlands
+
 N: Scott Snyder
 E: snyder@fnald0.fnal.gov
 D: ATAPI cdrom driver
index a984a50..3e049b0 100644 (file)
@@ -45,7+45,7 @@ CONFIG_EXPERIMENTAL
   internals are usually welcomed by the developers. Unless you intend
   to help test and develop a feature or driver that falls into this 
   category, you should probably say N here, which will cause this 
-  configure script to present you with less choices. If you say Y here,
+  configure script to present you with fewer choices. If you say Y here,
   you will be offered the choice of using features or drivers that are
   currently considered to be in the alpha-test phase.
 
@@ -1261,7+1261,7 @@ CONFIG_SCSI_DTC3280
   kernel whenever you want). If you want to compile it as a module,
   say M here and read Documentation/modules.txt.
 
-EATA-DMA (DPT, NEC, ATT, Olivetti for ISA, EISA, PCI) support
+EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
 CONFIG_SCSI_EATA_DMA
   This is support for the EATA-DMA protocol compliant SCSI Host Adaptors
   like the SmartCache III/IV, SmartRAID controller families and the DPT 
index 783b3ff..2295187 100644 (file)
@@ -14,7+14,7 @@ o     Test for B stepping processors.
 o      Clean up processor specific/independent split.
 o      Document it all.        [PARTLY DONE]
 o      Halt other CPU's on reset/panic doesn't always work.
-o      Dont waste page at 4K - dont need it now.(watch the GDT code).
+o      Don't waste page at 4K - don't need it now.(watch the GDT code).
 o      Dump bootup pages once booted somehow.
 o      Clean up warnings/volatiles.
 o      Fix load_TR() for non contiguous processor ids
index 48e985a..eb4e2e0 100644 (file)
@@ -42,7+42,7 @@ foo \kill}%
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: April 20, 1996}
+\date{Last revised: May 5, 1996}
 \maketitle
 %
 \noindent
@@ -156,6+156,7 @@ least not without contacting me first.
 \major{39}{}{char }{ML-16P experimental I/O board}
 \major{  }{}{block}{Reserved for Linux/AP+}
 \major{40}{}{char }{Matrox Meteor frame grabber}
+\major{  }{}{block}{Syquest EZ135 removable drive}
 \major{41}{}{char }{Yet Another Micro Monitor}
 \major{42}{}{}{Demo/sample use}
 \major{43}{}{char }{isdn4linux virtual modem}
@@ -165,7+166,8 @@ least not without contacting me first.
 \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
 \major{48}{}{char }{SDL RISCom serial card}
 \major{49}{}{char }{SDL RISCom serial card -- alternate devices}
-\major{50}{--59}{}{Unallocated}
+\major{50}{}{char }{Reserved for GLINT}
+\major{51}{--59}{}{Unallocated}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -942,8+944,15 @@ networking device.
 \begin{devicelist}
 \major{40}{}{char }{Matrox Meteor frame grabber}
        \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
+\\
+\major{  }{}{block}{Syquest EZ135 removable drive}
+       \minor{0}{/dev/eza}{First EZ135 drive whole disk}
 \end{devicelist}
 
+\noindent
+Partitions are handled the same way as for IDE disks (see major number
+3).
+
 \begin{devicelist}
 \major{41}{}{char }{Yet Another Micro Monitor}
        \minor{0}{/dev/yamm}{Yet Another Micro Monitor}
index a2dad5f..3ebcd42 100644 (file)
@@ -2,7+2,7 @@
 
             Maintained by H. Peter Anvin <hpa@zytor.com>
 
-                    Last revised: April 20, 1996
+                     Last revised: May 5, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -621,6+621,8 @@ least not without contacting me first.
                and "user level packet I/O."  This board is also
                accessible as a standard networking "eth" device.
 
+    block      Reserved for Linux/AP+
+
  39 char       ML-16P experimental I/O board
                  0 = /dev/ml16pa-a0    First card, first analog channel
                  1 = /dev/ml16pa-a1    First card, second analog channel
@@ -643,7+645,11 @@ least not without contacting me first.
 
  40 char       Matrox Meteor frame grabber
                  0 = /dev/mmetfgrab    Matrox Meteor frame grabber
-    block      Reserved for Linux/AP+
+    block      Syquest EZ135 removable drive
+                 0 = /dev/eza          First EZ135 drive, whole disk
+
+               Partitions are handled in the same way as IDE disks
+               (see major number 3).
 
  41 char       Yet Another Micro Monitor
                  0 = /dev/yamm         Yet Another Micro Monitor
index 996769f..2e9153d 100644 (file)
+Amiga filesystems Overview
+==========================
+
+Not all varieties of the Amiga filesystems are supported.  The Amiga
+currently knows 6 different filesystems:
+
+DOS\0          The old or original filesystem, not really suited for
+               hard disks and normally not used on them, either.
+               Not supported.
+
+DOS\1          The original Fast File System. Supported.
+
+DOS\2          The old "international" filesystem. International means that
+               a bug has been fixed so that accented ("international") letters
+               in file names are case-insensitive, as they ought to be.
+               Not supported.
+
+DOS\3          The "international" Fast File System.  Supported.
+
+DOS\4          The original filesystem with directory cache. The directory
+               cache speeds up directory accesses on floppies considerably,
+               but slowes down file creation/deletion. Doesn't make much
+               sense on hard disks. Not supported.
+
+DOS\5          The Fast File System with directory cache. Not supported.
+
+All of the above filesystems allow block sizes from 512 to 32K bytes.
+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
+speed up almost everything with the expense of wasted disk space. The speed
+gain above 4K seems not really worth the price, so you don't lose too
+much here, either.
+  
+Mount options for the AFFS
+==========================
+
+protect                If this option is set, the protection bits cannot be altered.
+
+uid[=uid]      This sets the uid of the root directory (i. e. the mount point
+               to uid or to the uid of the current user, if the =uid is
+               ommitted.
+
+gid[=gid]      Same as above, but for gid.
+
+setuid[=uid]   This sets the owner of all files and directories in the file
+               system to uid or the uid of the current user, respectively.
+
+setgid[=gid]   Same as above, but for gid.
+
+use_mp         The uid and gid are taken from the now covered mount point
+               instead of the current user or value defined.
+
+mode=mode      Sets the mode flags to the given (octal) value, regardles
+               of the original permissions. Directories will get an x
+               permission, if the corresponding r bit is set.
+               This is useful since most of the plain AmigaOS files
+               will map to 600.
+
+reserved=num   Sets the number of reserved blocks at the start of the
+               partition to num. Default is 2.
+
+root=block     Sets the block number of the root block. This schould never
+               be neccessary.
+
+bs=blksize     Sets the blocksize to blksize. Valid block sizes are 512,
+               1024, 2048 and 4096. Like the root option, this should
+               never be neccessary, as the affs can figure it out itself.
+
+quiet          The file system will not return an error for disallowed
+               mode changes.
+
+Handling of the Users/Groups and protection flags
+=================================================
+
+Amiga -> Linux:
+
+The Amiga protection flags RWEDRWEDHSPARWED are handled as follows:
+
+  - R maps to r for user, group and others. On directories, R implies x.
+
+  - If both W and D are allowed, w will be set.
+
+  - If both R and S are set, x will be set.
+
+  - H, P and E are always retained and ignored under Linux.
+
+  - A is always reset when written.
+
+User id and group id will be used unless set[gu]id are given as mount
+options. Since most of the Amiga file systems are single user systems
+they will be owned by root.
+
+Linux -> Amiga:
+
+The Linux rwxrwxrwx file mode is handled as follows:
+
+  - r permission will set R for user, group and others.
+
+  - w permission will set W and D for user, group and others.
+
+  - x permission of the user will set S for plain files.
+
+  - All other flags (suid, sgid, ...) are ignored and will
+    not be retained.
+    
+Newly created files and directories will get the user and group id
+of the current user and a mode according to the umask.
 Linux can read, but not write, Amiga FFS partitions.
 
 Mount options are
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
new file mode 100644 (file)
index 0000000..5269bbe
--- /dev/null
@@ -0,0 +1,98 @@
+Ioctl Numbers
+6 May 1996
+Michael Chastain
+<mec@duracef.shout.net>
+
+If you are adding new ioctl's to the kernel, you should use the _IO
+macros defined in <linux/ioctl.h>:
+
+    _IO    an ioctl with no parameters
+    _IOW   an ioctl with write parameters (from user's point of view)
+    _IOR   an ioctl with read parameters (from user's point of view)
+    _IOWR  an ioctl with both write and read parameters.
+
+'Write' and 'read' are from the user's point of view.  This is like the
+system calls 'write' and 'read'.  For example, a SET_FOO ioctl would be
+_IOW, although the kernel would actually read data from user space; a
+GET_FOO ioctl would be _IOR, although the kernel would actually write
+data to user space.
+
+The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
+or number from the table below.  If you are writing a driver for a new
+device and need a letter, pick an unused letter.  You can register the
+letter by patching this file and submitting the patch to Linus Torvalds.
+Or you can e-mail me at <mec@duracef.shout.net> and I'll register one
+for you.
+
+The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
+to distinguish ioctls from each other.  The third argument is a size
+of the structure going into the kernel or coming out of the kernel.
+
+Some devices use their major number as the identifier; this is not
+recommended.  Some devices are even more irregular and don't follow
+the convention at all.
+
+Following the convention is good because:
+
+(1) Keeping the ioctl's globally unique helps error checking:
+    if a program calls an ioctl on the wrong device, it will get an
+    error rather than some unexpected behaviour.
+
+(2) The 'strace' build procedure automatically finds ioctl numbers
+    defined with _IO, _IOW, _IOR, or _IOWR.
+
+(3) 'strace' can decode numbers back into useful names when the
+    numbers are unique.
+
+(4) People looking for ioctls can grep for them more easily when
+    the convention is used to define the ioctl numbers.
+
+(5) When following the convention, the driver code can use generic
+    code to call verify_area to validate parameters.
+
+This table is current to Linux 1.3.98.
+
+Ioctl  Include File            Comments
+========================================================
+0x00   linux/fs.h              only FIBMAP, FIGETBSZ
+0x00   linux/random.h          codes in 0x010800NN
+0x00   linux/mc146818rtc.h     conflict!
+0x02   linux/fd.h
+0x03   linux/hdreg.h
+0x04   linux/umsdos_fs.h
+0x06   linux/lp.h
+0x09   linux/md.h
+0x12   linux/fs.h
+0x20   linux/cm206.h
+0x22   linux/scc.h             conflict!
+0x22   scsi/sg.h               conflict!
+'A'    linux/apm_bios.h
+'C'    linux/soundcard.h
+'F'    linux/fb.h
+'I'    linux/isdn.h
+'K'    linux/kd.h
+'L'    linux/loop.h
+'M'    linux/soundcard.h
+'P'    linux/soundcard.h
+'Q'    linux/soundcard.h
+'S'    linux/cdrom.h           conflict!
+'S'    scsi/scsi.h             conflict!
+'S'    scsi/scsi_ioctl.h       conflict!
+'T'    linux/soundcard.h       conflict!
+'T'    asm/ioctls.h            conflict!
+'V'    linux/vt.h
+'Y'    linux/cyclades.h        codes in 0x004359NN
+'a'    various, see http://lrcwww.epfl.ch/linux-atm/magic.html
+'c'    linux/comstats.h
+'f'    linux/ext2_fs.h
+'m'    linux/mtio.h            conflict!
+'m'    linux/soundcard.h       conflict!
+'n'    linux/ncp_fs.h
+'r'    linux/msdos_fs.h
+'s'    linux/cdk.h
+'t'    linux/if_ppp.h          no conflict
+'t'    linux/isdn_ppp.h        no conflict
+'u'    linux/smb_fs.h
+'v'    linux/ext2_fs.h
+0x89   asm/sockios.h           no conflict
+0x89   linux/sockios.h         no conflict
index 7e67956..26e9e32 100644 (file)
@@ -48,7+48,7 @@ Description of the Interface between Linklevel and Hardwarelevel
 
     To be preset by the HL-driver, if it supports sk_buff's. The driver
     should put here the amount of additional space needed in sk-buff's for
-    it's internal purposes. Drivers not supporting sk_buff's should put
+    its internal purposes. Drivers not supporting sk_buff's should put
     initialize this field to 0.
 
   void (*rcvcallb)(int, int, u_char*, int);
@@ -68,7+68,7 @@ Description of the Interface between Linklevel and Hardwarelevel
 
     This field will be set by LL. The HL-driver delivers received data-
     packets by calling this function. Upon calling, the HL-driver must
-    already have it's private data pulled off the head of the sk_buff.
+    already have its private data pulled off the head of the sk_buff.
 
     Parameter:
       int              driver-Id
@@ -83,8+83,8 @@ Description of the Interface between Linklevel and Hardwarelevel
     Parameter:
       isdn_ctrl*
 
-      The struct isdn_ctrl also defined in isdn_if. The exact meaning of it's
-      fields is described together with the descriptions of the possible
+      The struct isdn_ctrl also defined in isdn_if. The exact meanings of its
+      fields are described together with the descriptions of the possible
       events. Here is only a short description of the fields:
 
         driver  = driver Id.
@@ -196,7+196,7 @@ NOTE on writebuf and writebuf_skb:
   char id[20];
        ***CHANGE0.7: New since this version.
 
-   This string has to be preset by the HL-driver. It's purpose is for
+   This string has to be preset by the HL-driver. Its purpose is for
    identification of the driver by the user. Eg.: it is shown in the
    status-info of /dev/isdninfo. Furthermore it is used as Id for binding
    net-interfaces to a specific channel. If a string of length zero is
index 2341837..5d5e339 100644 (file)
@@ -308,7+308,7 @@ README for the ISDN-subsystem
      3.2.1 Teles driver.
 
        The module teles.o can be configured during "insmod'ing" it by
-       appending it's parameters to the insmod-commandline. The following
+       appending its parameters to the insmod-commandline. The following
        syntax is accepted:
 
        io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring
@@ -323,7+323,7 @@ README for the ISDN-subsystem
      3.2.2 ICN driver.
 
        The module icn.o can be configured during "insmod'ing" it by
-       appending it's parameters to the insmod-commandline. The following
+       appending its parameters to the insmod-commandline. The following
        syntax is accepted:
 
        portbase=p membase=m icn_id=idstring icn_id2=idstring2
@@ -347,7+347,7 @@ README for the ISDN-subsystem
 
 4. Device-inodes
 
-   The major and minor-numbers and it's names are described in
+   The major and minor-numbers and its names are described in
    Documentation/devices.txt. The major-numbers are:
 
      43 for the ISDN-tty's.
@@ -494,7+494,7 @@ README for the ISDN-subsystem
    cisco-h  A special-mode for communicating with a Cisco, which is configured
             to do "hdlc"
    ethernet No stripping. Packets are sent with full MAC-header.
-            The Ethernet-address of the interface is faked, from it's
+            The Ethernet-address of the interface is faked, from its
             IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values.
    syncppp  Synchronous PPP
 
@@ -553,7+553,7 @@ README for the ISDN-subsystem
 
    "isdnctrl sdelay <InterfaceName> secs."
    This sets the minimum time an Interface has to be fully loaded, until
-   it sends an dial-request to it's slave.
+   it sends a dial-request to its slave.
 
    "isdnctrl dial <InterfaceName>"
    Forces an interface to start dialing even if no packets are to be
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
new file mode 100644 (file)
index 0000000..085dfc2
--- /dev/null
@@ -0,0 +1,61 @@
+This file is a registry of magic numbers which are in use.  When you
+add a magic number to a structure, you should also add it to this
+file, since it is best if the magic numbers used by various structures
+are unique.
+
+It is a *very* good idea to protect kernel data structures with magic
+numbers.  This allows you to check at run time whether (a) a structure
+has been clobbered, or (b) you've passed the wrong structure to a
+routine.  This last is especially useful --- particularly when you are
+passing pointers to structures via a void * pointer.  The tty code,
+for example, does this frequently to pass driver-specific and line
+discipline-specific structures back and forth.
+
+The way to use magic numbers is to declare then at the beginning of
+the structure, like so:
+
+struct tty_ldisc {
+       int     magic;
+       ...
+};
+
+Please follow this discipline when you are adding future enhancements
+to the kernel!  It has saved me countless hours of debugging,
+especially in the screw cases where an array has been overrun and
+structures following the array have been overwritten.  Using this
+discipline, these cases get detected quickly and safely.
+
+                                       Theodore Ts'o
+                                       31-Mar-94
+
+The magic table is current to Linux 1.3.98.
+
+                                       Michael Chastain
+                                       <mec@duracef.shout.net>
+                                       6 May 1996
+
+
+
+Magic Name          Number      Structure            File
+===========================================================================
+RISCOM8_MAGIC       0x0907      struct riscom_port   drivers/char/riscom8.h
+APM_BIOS_MAGIC      0x4101      struct apm_struct    include/linux/apm_bios.h
+CYCLADES_MAGIC      0x4359      struct cyclades_port include/linux/cyclades.h
+FASYNC_MAGIC        0x4601      struct fasync_struct include/linux/fs.h
+PTY_MAGIC           0x5001      struct pty_struct    drivers/char/pty.c
+PPP_MAGIC           0x5002      struct ppp_struct    include/linux/if_ppp.h
+SERIAL_MAGIC        0x5301      struct async_struct  include/linux/serial.h
+SLIP_MAGIC          0x5302      struct slip          drivers/net/slip.h
+STRIP_MAGIC         0x5303      struct strip         drivers/net/strip.c
+TTY_MAGIC           0x5401      struct tty_struct    include/linux/tty.h
+TTY_DRIVER_MAGIC    0x5402      struct tty_driver    include/linux/tty_driver.h
+TTY_LDISC_MAGIC     0x5403      struct tty_ldisc     include/linux/tty_ldisc.h
+SCC_MAGIC           0x8530      struct scc_channel   include/linux/scc.h
+ISDN_ASYNC_MAGIC    0x49344C01  modem_info           include/linux/isdn.h
+ISDN_NET_MAGIC      0x49344C02  isdn_net_ndev        include/linux/isdn.h
+STLI_BOARDMAGIC     0x4bc6c825  stlibrd_t            include/linux/istallion.h
+STLI_PORTMAGIC      0xe671c7a1  stliport_t           include/linux/istallion.h
+STL_PANELMAGIC      0x7ef621a1  stlpanel_t           include/linux/stallion.h
+STL_BOARDMAGIC      0xa2267f52  stlbrd_t             include/linux/stallion.h
+STL_PORTMAGIC       0x5a7182c9  stlport_t            include/linux/stallion.h
+PCXX_MAGIC          0x5c6df104  struct channel       drivers/char/pcxx.h
index 891a8aa..79d3837 100644 (file)
@@ -140,7+140,7 @@ And now to the cabling.  What you can connect together:
 5. An active hub to passive hub.
 
 Remember, that you can not connect two passive hubs together.  The power loss
-implied by such connection is too high for the net to operate reliably.
+implied by such connection is too high for the net to operate reliably.
 
 An example of a typical ARCnet network:
 
@@ -2256,9+2256,9 @@ to be used. The first 6 switches set the address, the 7th doesn't have any
 function, and the 8th switch is used to select "compatible" or "enhanced".
 When I got my two cards, one of them had this switch set to "enhanced". That
 card didn't work at all, it wasn't even recognized by the driver. The other
-card had this switch set to "compatible" and it behaved absolutely normal. I
+card had this switch set to "compatible" and it behaved absolutely normally. I
 guess that the switch on one of the cards, must have been changed accidently
-when the card was taken out of it's former host. The question remains
+when the card was taken out of its former host. The question remains
 unanswered, what is the purpose of the "enhanced" position?
 
 [Avery's note: "enhanced" probably either disables shared memory (use IO
index 628d4d9..0a0bc4b 100644 (file)
@@ -1,6+1,6 @@
 Frame Relay (FR) support for linux is built into a two tiered system of device 
 drivers.  The upper layer implements RFC1490 FR specification, and uses the
-Data Link Connection Identifier (DLCI) as it's hardware address.  Usually these
+Data Link Connection Identifier (DLCI) as its hardware address.  Usually these
 are assigned by your network supplier, they give you the number/numbers of
 the Virtual Connections (VC) assigned to you.
 
index c37b0ee..43d79a8 100644 (file)
@@ -160,7+160,7 @@ depend on what facilities are available:
        The other two kernel command line parameters cannot be substi-
        tuted with rdev. Therefore, using this method the kernel will
        by default use RARP and/or BOOTP, and if it gets an answer via
-       RARP will mount the directory /tftpboot/<client-ip>/ as it's
+       RARP will mount the directory /tftpboot/<client-ip>/ as its
        root. If it got a BOOTP answer the directory name in that answer
        is used.
 
@@ -169,8+169,8 @@ depend on what facilities are available:
        When using LILO you can specify all necessary command line
        parameters with the 'append=' command in the LILO configuration
        file. However, to use the 'root=' command you also need to
-       setup a dummy device as described in 3.1 above. How to use
-       LILO and it's 'append=' command please refer to the LILO
+       set up a dummy device as described in 3.1 above. For how to use
+       LILO and its 'append=' command please refer to the LILO
        documentation.
 
 3.3) Using loadlin
@@ -187,7+187,7 @@ depend on what facilities are available:
        protocol. As far as I know no commercial bootroms already
        support booting Linux over the network, but there are two
        free implementations of a bootrom available on sunsite.unc.edu
-       and it's mirrors. They are called 'netboot-nfs' and 'etherboot'.
+       and its mirrors. They are called 'netboot-nfs' and 'etherboot'.
        Both contain everything you need to boot a diskless Linux client.
 
 
index 5d8a42f..ed003a1 100644 (file)
@@ -19,7+19,7 @@ happened in).
 Oh, it helps if the report happens on a kernel that is compiled with the 
 same compiler and similar setups.
 
-The other thing to do is disassemble the "Code:" part of the bugreprot: 
+The other thing to do is disassemble the "Code:" part of the bug report: 
 ksymoops will do this too with the correct tools (and new version of 
 ksymoops), but if you don't have the tools you can just do a silly 
 program:
@@ -30,7+30,7 @@ program:
 and compile it with gcc -g and then do "disassemble str" (where the "XX" 
 stuff are the values reported by the Oops - you can just cut-and-paste 
 and do a replace of spaces to "\x" - that's what I do, as I'm too lazy 
-to write a prigram to automate this all).
+to write a program to automate this all).
 
 Finally, if you want to see where the code comes from, you can do
 
index 881b671..5b48c39 100644 (file)
@@ -79,7+79,7 @@ starting at an offset of 400kB, you would use "ramdisk_start=400".
        load_ramdisk=N
        ==============
 
-This parameter tells the kernel whether it is to try and load a
+This parameter tells the kernel whether it is to try to load a
 ramdisk image or not. Specifying "load_ramdisk=1" will tell the
 kernel to load a floppy into the ramdisk. The default value is
 zero, meaning that the kernel should not try to load a ramdisk.
@@ -194,7+194,7 @@ f) Put the ramdisk image onto the floppy, after the kernel. Use an offset
        dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400
 
 g) Use "rdev" to set the boot device, ramdisk offset, prompt flag, etc.
-   For ramdisk_start=400, load_ramdisk=1, ramdisk_start=400, one would
+   For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
    have 2^15 + 2^14 + 400 = 49552.
 
        rdev /dev/fd0 /dev/fd0
index ba9362f..e290b41 100644 (file)
@@ -9,7+9,7 @@ clock that keeps the date and time while your computer is turned off.
 
 However it can also be used to generate signals from a slow 2Hz to a
 relatively fast 8192Hz, in increments of powers of two. These signals
-are reported by interrupt number 8. (Oh! So *thats* what IRQ 8 is
+are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is
 for...) It can also function as a 24hr alarm, raising IRQ 8 when the
 alarm goes off. The alarm can also be programmed to only check any
 subset of the three programmable values, meaning that it could be set to
@@ -88,13+88,12 @@ that will be using this driver.
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
-#include <time.h>
 
 void main(void) {
 
 int i, fd, retval, irqcount = 0;
 unsigned long tmp, data;
-struct tm rtc_tm;
+struct rtc_time rtc_tm;
 
 fd = open ("/dev/rtc", O_RDONLY);
 
diff --git a/MAGIC b/MAGIC
deleted file mode 100644 (file)
index 0eef6fc..0000000
--- a/MAGIC
+++ /dev/null
@@ -1,105 +0,0 @@
-This file is a registry of magic numbers which are in use.  When you
-add a magic number to a structure, you should also add it to this
-file, since it is best if the magic numbers used by various structures
-are unique.
-
-It is a *very* good idea to protect kernel data structures with magic
-numbers.  This allows you to check at run time whether (a) a structure
-has been clobbered, or (b) you've passed the wrong structure to a
-routine.  This last is especially useful --- particularly when you are
-passing pointers to structures via a void * pointer.  The tty code,
-for example, does this frequently to pass driver-specific and line
-discipline-specific structures back and forth.
-
-The way to use magic numbers is to declare then at the beginning of
-the structure, like so:
-
-struct tty_ldisc {
-       int     magic;
-       ...
-};
-
-Please follow this discipline when you are adding future enhancements
-to the kernel!  It has saved me countless hours of debugging,
-especially in the screw cases where an array has been overrun and
-structures following the array have been overwritten.  Using this
-discipline, these cases get detected quickly and safely.
-
-You should also register the magic number used by ioctls in the table
-below.  This allows ioctls on inappropriate devices to fail, rather than
-doing something completely unexpected.  The magic number is the first
-argument to the _IO family of macros (see include/linux/ioctl.h) or
-in general bits 8..15 of the ioctl number.  Where ioctls are done on
-devices with a major device number, it is recommended that you use the
-major device number as the ioctl magic value (e.g. hd, lp).
-
-                                       Theodore Ts'o
-                                       31-Mar-94
-
-The magic table is current to Linux 1.3.35.
-The ioctl table is current to Linux 1.3.35.
-For a complete list of kernel ioctl's, look for 'ioctl-list.X.Y.ZZ' on
-an ftp site, where 'X.Y.ZZ' is the kernel version for the ioctl list.
-
-                                       Michael Chastain
-                                       <mec@duracef.shout.net>
-                                       17-Oct-95
-
-
-
-
-Magic Name          Number  Structure            File
-===========================================================================
-APM_BIOS_MAGIC      0x4101  struct apm_struct    include/linux/apm_bios.h
-CYCLADES_MAGIC      0x4359  struct cyclades_port include/linux/cyclades.h
-FASYNC_MAGIC        0x4601  struct fasync_struct include/linux/fs.h
-PTY_MAGIC           0x5001  struct pty_struct    drivers/char/pty.c
-PPP_MAGIC           0x5002  struct ppp_struct    include/linux/if_ppp.h
-TTY_MAGIC           0x5401  struct tty_struct    include/linux/tty.h
-TTY_DRIVER_MAGIC    0x5402  struct tty_driver    include/linux/tty_driver.h
-TTY_LDISC_MAGIC     0x5403  struct tty_ldisc     include/linux/tty_ldisc.h
-SERIAL_MAGIC        0x5301  struct async_struct  include/linux/serial.h
-SLIP_MAGIC          0x5302  struct slip          drivers/net/slip.h
-SCC_MAGIC           0x8530  struct scc_channel   include/linux/scc.h
-RISCOM8_MAGIC       0x0907  struct riscom_port  drivers/char/riscom8.h
-
-
-
-Ioctl  Include File            Comments
-========================================================
-0x00   linux/fs.h              only FIBMAP, FIGETBSZ
-0x00   linux/random.h          codes in 0x010800NN
-0x02   linux/fd.h
-0x03   linux/hdreg.h
-0x04   linux/umsdos_fs.h
-0x06   linux/lp.h
-0x09   linux/md.h
-0x12   linux/fs.h
-0x20   linux/cm206.h
-0x22   linux/scc.h
-'A'    linux/apm_bios.h
-'C'    linux/soundcard.h
-'I'    linux/isdn.h
-'K'    linux/kd.h
-'L'    linux/loop.h
-'M'    linux/soundcard.h
-'P'    linux/soundcard.h
-'Q'    linux/soundcard.h
-'S'    linux/cdrom.h           conflict!
-'S'    linux/scsi.h            conflict!
-'T'    linux/soundcard.h       conflict!
-'T'    asm/termios.h           conflict!
-'V'    linux/vt.h
-'Y'    linux/cyclades.h        codes in 0x004359NN
-'a'    various, see http://lrcwww.epfl.ch/linux-atm/magic.html
-'f'    linux/ext2_fs.h
-'m'    linux/mtio.h            conflict!
-'m'    linux/soundcard.h       conflict!
-'n'    linux/ncp_fs.h
-'s'    linux/cdk.h
-'t'    linux/if_ppp.h
-'u'    linux/smb_fs.h
-'u'    linux/smb_fs.h
-'v'    linux/ext2_fs.h
-0x89   asm/socket.h            no conflict
-0x89   linux/sockios.h         no conflict
index 1b18d76..53aedf8 100644 (file)
@@ -7,13+7,13 @@ trivial patch so apply some common sense.
 1.     Always _test_ your changes, however small, on at least 4 or
        5 people, preferably many more.
 
-2.     Try and release a few ALPHA test versions to the net. Announce
+2.     Try to release a few ALPHA test versions to the net. Announce
        them onto the kernel channel and await results. This is especially
-       important for device drivers, because often thats the only way
+       important for device drivers, because often that's the only way
        you will find things like the fact version 3 firmware needs
        a magic fix you didn't know about, or some clown changed the
        chips on a board and not its name.  (Don't laugh!  Look at the
-       SMC etherpower for that).
+       SMC etherpower for that.)
 
 3.     Make sure your changes compile correctly in multiple
        configurations.
@@ -30,7+30,7 @@ trivial patch so apply some common sense.
        your driver to get around a problem actual needs to become a
        generalised kernel feature ready for next time.
 
-       PLEASE try and include any credit lines you want added with the
+       PLEASE try to include any credit lines you want added with the
        patch. It avoids people being missed off by mistake and makes
        it easier to know who wants adding and who doesn't.
 
@@ -74,6+74,12 @@ M:   net-patches@lxorguk.ukuu.org.uk
 L:     linux-net@vger.rutgers.edu
 S:     Maintained
 
+8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
+P:     Paul Gortmaker
+M      gpg109@rsphy1.anu.edu.au
+L:     linux-net@vger.rutgers.edu
+S:     Maintained
+
 ETHEREXPRESS NETWORK DRIVER
 P:     Philip Blundell
 M:     pjb27@cam.ac.uk
@@ -226,6+232,12 @@ M: longyear@netcom.com, Cc: longyear@sii.com
 L:     linux-ppp@vger.rutgers.edu
 S:     Maintained
 
+REAL TIME CLOCK DRIVER
+P:     Paul Gortmaker
+M      gpg109@rsphy1.anu.edu.au
+L:     linux-kernel@vger.rutgers.edu
+S:     Maintained
+
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
 P:     Stuart Cheshire
 M:     cheshire@cs.stanford.edu
@@ -288,6+300,12 @@ M: roadcapw@cfw.com
 L:     linux-kernel@vger.rutgers.edu
 S:     Maintained
 
+LANCE AND LANCE32 NETWORK DRIVER
+P:     Thomas Bogendoerfer
+M:     tsbogend@bigbug.franken.de
+L:     linux-net@vger.rutgers.edu
+S:     Maintained
+
 REST:
 P:     Linus Torvalds
 S:     Buried alive in email
index 614339f..d99a636 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6+1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 98
+SUBLEVEL = 99
 
 ARCH = i386
 
diff --git a/READMEb/README
index d95913c..8179783 100644 (file)
--- a/README
+++ b/README
@@ -24,9+24,9 @@ sometimes takes days or even weeks.
 
 WHAT IS LINUX?
 
-  Linux is a Unix clone for 386/486-based PCs written from scratch by
-  Linus Torvalds with assistance from a loosely-knit team of hackers
-  across the Net.  It aims towards POSIX compliance. 
+  Linux is a Unix clone written from scratch by Linus Torvalds with
+  assistance from a loosely-knit team of hackers across the Net.
+  It aims towards POSIX compliance. 
 
   It has all the features you would expect in a modern fully-fledged
   Unix, including true multitasking, virtual memory, shared libraries,
@@ -36,6+36,12 @@ WHAT IS LINUX?
   It is distributed under the GNU General Public License - see the
   accompanying COPYING file for more details. 
 
+ON WHAT HARDWARE DOES IT RUN?
+
+  Linux was first developed for 386/486-based PCs.  These days it also
+  runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga),
+  MIPS and PowerPC.
+
 DOCUMENTATION:
 
  - there is a lot of documentation available both in electronic form on
index 7bc03bf..a7b9757 100644 (file)
@@ -82,7+82,9 @@ fi
 bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO
 if [ "$CONFIG_PCI" = "y" ]; then
   bool 'TGA Console Support' CONFIG_TGA_CONSOLE
-  bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+  fi
 fi
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
index ad28cfe..726d3ed 100644 (file)
@@ -442,7+442,7 @@ unsigned long pcibios_init(unsigned long mem_start,
 }
 
 /*
- * The SRM console *disables* the IDE interface, this code ensures its
+ * The SRM console *disables* the IDE interface, this code ensures it's
  * enabled.
  *
  * This code bangs on a control register of the 87312 Super I/O chip
@@ -565,7+565,7 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl
                                                  PCI_INTERRUPT_LINE, dev->irq);
 #endif
                        /*
-                        * if its a VGA, enable its BIOS ROM at C0000
+                        * if it's a VGA, enable its BIOS ROM at C0000
                         */
                        if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
                          pcibios_write_config_dword(dev->bus->number, dev->devfn,
@@ -799,7+799,7 @@ static inline void sio_fixup(void)
                          dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
                          slot, pin, pirq));
                /*
-                * if its a VGA, enable its BIOS ROM at C0000
+                * if it's a VGA, enable its BIOS ROM at C0000
                 */
                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
                        pcibios_write_config_dword(dev->bus->number, dev->devfn,
index 02e8388..aac33aa 100644 (file)
@@ -90,6+90,7 @@ dep:
 
 clean:
        rm -f bootsect setup
+       rm -f bbootsect
        rm -f zImage tools/build compressed/vmlinux.out
        rm -f bzImage tools/bbuild compressed/bvmlinux.out
        @$(MAKE) -C compressed clean
index 8d04799..8e1691b 100644 (file)
@@ -26,14+26,15 @@ bool 'Networking support' CONFIG_NET
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M
 bool 'PCI bios support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
-  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+  fi
 fi
 bool 'System V IPC' CONFIG_SYSVIPC
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
-  bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
+bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
+
 choice 'Processor type' \
        "386            CONFIG_M386     \
         486            CONFIG_M486     \
index 2bdd0a8..27ca35e 100644 (file)
@@ -370,7+370,7 @@ asmlinkage void do_fast_IRQ(int irq)
 {
        struct irqaction * action = *(irq + irq_action);
 #ifdef __SMP__
-       /* IRQ 13 is allowed - thats a flush tlb */
+       /* IRQ 13 is allowed - that's a flush tlb */
        if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
                panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
 #endif
index 03d2c77..443c10d 100644 (file)
@@ -207,7+207,8 @@ void setup_arch(char **cmdline_p,
 static const char * i486model(unsigned int nr)
 {
        static const char *model[] = {
-               "0", "DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB"
+               "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
+               "10","11","12","13","Am5x85-WT","Am5x86-WB"
        };
        if (nr < sizeof(model)/sizeof(char *))
                return model[nr];
@@ -325,7+326,7 @@ int get_cpuinfo(char * buffer)
                                 }
                         }
                         len += sprintf(buffer+len,
-                                       "\nbogomips:\t: %lu.%02lu\n",
+                                       "\nbogomips\t: %lu.%02lu\n",
                                        CD(loops_per_sec)/500000,
                                        (CD(loops_per_sec)/5000) % 100);
 #ifdef __SMP__
index 1f6fd84..a98d210 100644 (file)
@@ -43,11+43,6 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long
        }
 }
 
-/*
- * FIXME. We don't currently restore emulator state
- */
-#define restore_i387_soft(x) do { } while (0)
-
 static inline void restore_i387_hard(struct _fpstate *buf)
 {
 #ifdef __SMP__
@@ -122,11+117,6 @@ badframe:
        do_exit(SIGSEGV);
 }
 
-/*
- * FIXME. We currently don't save 387 state if we use emulation
- */
-#define save_i387_soft(x) NULL
-
 static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
 {
 #ifdef __SMP__
index 12055a8..8825530 100644 (file)
@@ -56,7+56,7 @@ int smp_threads_ready=0;                              /* Set when the idlers are all forked                   */
 volatile int cpu_number_map[NR_CPUS];                  /* which CPU maps to which logical number               */
 volatile int cpu_logical_map[NR_CPUS];                 /* which logical number maps to which CPU               */
 volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
-volatile unsigned long smp_invalidate_needed;          /* Used for the invalidate map thats also checked in the spinlock */
+volatile unsigned long smp_invalidate_needed;          /* Used for the invalidate map that's also checked in the spinlock */
 struct cpuinfo_x86 cpu_data[NR_CPUS];                  /* Per cpu bogomips and other parameters                */
 static unsigned int num_processors = 1;                        /* Internal processor count                             */
 static unsigned long io_apic_addr = 0xFEC00000;                /* Address of the I/O apic (not yet used)               */
@@ -448,7+448,7 @@ static unsigned char trampoline_data[]={
 /*
  *     Currently trivial. Write the real->protected mode
  *     bootstrap into the page concerned. The caller
- *     has made sure its suitably aligned.
+ *     has made sure it's suitably aligned.
  */
  
 static void install_trampoline(unsigned char *mp)
@@ -1094,7+1094,7 @@ void smp_flush_tlb(void)
 /*     printk("SMI-");*/
        
        /*
-        *      The assignment is safe because its volatile so the compiler cannot reorder it,
+        *      The assignment is safe because it's volatile so the compiler cannot reorder it,
         *      because the i586 has strict memory ordering and because only the kernel lock holder
         *      may issue a tlb flush. If you break any one of those three change this to an atomic
         *      bus locked or.
@@ -1104,7+1104,7 @@ void smp_flush_tlb(void)
        
        /*
         *      Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
-        *      ensure they dont do a spurious flush tlb or miss one.
+        *      ensure they don't do a spurious flush tlb or miss one.
         */
         
        save_flags(flags);
index b80c2c8..1b75c30 100644 (file)
@@ -267,7+267,7 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
            last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
        /* As we return to user mode fire off the other CPU schedulers.. this is 
           basically because we don't yet share IRQ's around. This message is
-          rigged to be safe on the 386 - basically its a hack, so don't look
+          rigged to be safe on the 386 - basically it's a hack, so don't look
           closely for now.. */
        /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
            
index 31210b5..fe0e36d 100644 (file)
@@ -255,18+255,11 @@ void math_error(void)
         */
        __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
        task->flags&=~PF_USEDFPU;
+       stts();
 
        force_sig(SIGFPE, task);
        task->tss.trap_no = 16;
        task->tss.error_code = 0;
-
-       /*
-        * Give the process a clean slate next time they use
-        * the FPU (and if they haven't accepted the SIGFPE before
-        * that, it's their problem..)
-        */
-       stts();
-       task->used_math = 0;
 }
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
index 4e0335e..37c5be7 100644 (file)
@@ -3,9+3,9 @@
  |                                                                           |
  |  The error handling functions for wm-FPU-emu                              |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1996                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -82,7+82,7 @@ void FPU_illegal(void)
 
 
 
-void emu_printall()
+void emu_printall(void)
 {
   int i;
   static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
@@ -166,7+166,8 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
   for ( i = 0; i < 8; i++ )
     {
       FPU_REG *r = &st(i);
-      switch (r->tag)
+      char tagi = r->tag;
+      switch (tagi)
        {
        case TW_Empty:
          continue;
@@ -190,22+191,13 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
                 r->exp - EXP_BIAS + 1);
          break;
        default:
-         printk("Whoops! Error in errors.c      ");
+         printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
+         continue;
          break;
        }
-      printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
+      printk("%s\n", tag_desc[(int) (unsigned) tagi]);
     }
 
-#ifdef OBSOLETE
-  printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
-        FPU_loaded_data.sign ? '-' : '+',
-        (long)(FPU_loaded_data.sigh >> 16),
-        (long)(FPU_loaded_data.sigh & 0xFFFF),
-        (long)(FPU_loaded_data.sigl >> 16),
-        (long)(FPU_loaded_data.sigl & 0xFFFF),
-        FPU_loaded_data.exp - EXP_BIAS + 1);
-  printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
-#endif OBSOLETE
   RE_ENTRANT_CHECK_ON;
 
 }
@@ -365,12+357,8 @@ void exception(int n)
       /*
        * The 80486 generates an interrupt on the next non-control FPU
        * instruction. So we need some means of flagging it.
-       * We use the ES (Error Summary) bit for this, assuming that
-       * this is the way a real FPU does it (until I can check it out),
-       * if not, then some method such as the following kludge might
-       * be needed.
+       * We use the ES (Error Summary) bit for this.
        */
-/*      regs[0].tag |= TW_FPU_Interrupt; */
     }
   RE_ENTRANT_CHECK_ON;
 
@@ -568,7+556,7 @@ asmlinkage int arith_overflow(FPU_REG *dest)
       return !(control_word & CW_Precision);
     }
 
-  return !(control_word & CW_Overflow);
+  return 0;
 
 }
 
@@ -599,7+587,7 @@ asmlinkage int arith_underflow(FPU_REG *dest)
       return !(control_word & CW_Precision);
     }
 
-  return !(control_word & CW_Underflow);
+  return 0;
 
 }
 
index 2cf14a6..dc249e5 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+#include <asm/sigcontext.h>    /* for struct _fpstate */
 #include <linux/math_emu.h>
 #include <linux/linkage.h>
 
index b2777a7..ebe8b68 100644 (file)
 /*---------------------------------------------------------------------------+
  |  fpu_entry.c                                                              |
  |                                                                           |
- | The entry function for wm-FPU-emu                                         |
+ | The entry functions for wm-FPU-emu                                        |
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1996                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
  |                                                                           |
  | See the files "README" and "COPYING" for further copyright and warranty   |
  | information.                                                              |
  +---------------------------------------------------------------------------*/
 
 /*---------------------------------------------------------------------------+
- | math_emulate() is the sole entry point for wm-FPU-emu                     |
+ | math_emulate(), restore_i387_soft() and save_i387_soft() are the only     |
+ | entry points for wm-FPU-emu.                                              |
  +---------------------------------------------------------------------------*/
 
 #include <linux/signal.h>
@@ -159,8+160,9 @@ asmlinkage void math_emulate(long arg)
        {
          /* Make sure that the registers are compatible
             with the assumptions of the emulator. */
-         regs[i].exp = 0;
-         regs[i].sigh = 0x80000000;
+         if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
+                && (regs[i].sigl == 0)) )
+           regs[i].sigh |= 0x80000000;
        }
       finit();
       current->used_math = 1;
@@ -283,24+285,8 @@ do_another_FPU_instruction:
          /*
           *  We need to simulate the action of the kernel to FPU
           *  interrupts here.
-          *  Currently, the "real FPU" part of the kernel (0.99.10)
-          *  clears the exception flags, sets the registers to empty,
-          *  and passes information back to the interrupted process
-          *  via the cs selector and operand selector, so we do the same.
           */
        do_the_FPU_interrupt:
-         instruction_address.selector = status_word();
-         operand_address.selector = tag_word();
-         partial_status = 0;
-         top = 0;
-         {
-           int r;
-           for (r = 0; r < 8; r++)
-             {
-               regs[r].tag = TW_Empty;
-             }
-         }
-
          FPU_EIP = FPU_ORIG_EIP;       /* Point to current FPU instruction. */
 
          RE_ENTRANT_CHECK_OFF;
@@ -688,3+674,22 @@ void math_abort(struct info * info, unsigned int signal)
       printk("ERROR: wm-FPU-emu math_abort failed!\n");
 #endif PARANOID
 }
+
+
+
+void restore_i387_soft(struct _fpstate *buf)
+{
+  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+  frstor(addr_modes, (char *)buf);
+}
+
+
+struct _fpstate * save_i387_soft(struct _fpstate * buf)
+{
+  fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+  fsave(addr_modes, (char *)buf);
+
+  return buf;
+}
index efec9e0..2d6c0fb 100644 (file)
@@ -3,9+3,9 @@
  |                                                                           |
  | All of the functions which transfer data between user memory and FPU_REGs.|
  |                                                                           |
- | Copyright (C) 1992,1993,1994                                              |
- |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
- |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
+ | Copyright (C) 1992,1993,1994,1996                                         |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
@@ -466,6+466,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
 
   if (st0_tag == TW_Valid)
     {
+      int precision_loss;
       int exp;
       FPU_REG tmp;
 
@@ -474,8+475,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
 
       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
        {
-         int precision_loss;
-
          /* A denormal will always underflow. */
 #ifndef PECULIAR_486
          /* An 80486 is supposed to be able to generate
@@ -518,6+517,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
        {
          if ( tmp.sigl & 0x000007ff )
            {
+             precision_loss = 1;
              switch (control_word & CW_RC)
                {
                case RC_RND:
@@ -541,8+541,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
          
              if ( increment )
                {
-                 set_precision_flag_up();
-
                  if ( tmp.sigl >= 0xfffff800 )
                    {
                      /* the sigl part overflows */
@@ -566,9+564,9 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
                      tmp.sigl += 0x00000800;
                    }
                }
-             else
-               set_precision_flag_down();
            }
+         else
+           precision_loss = 0;
          
          l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
          l[1] = ((tmp.sigh >> 11) & 0xfffff);
@@ -590,6+588,13 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
            }
          else
            {
+             if ( precision_loss )
+               {
+                 if ( increment )
+                   set_precision_flag_up();
+                 else
+                   set_precision_flag_down();
+               }
              /* Add the exponent */
              l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
            }
@@ -661,6+666,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
 
   if (st0_tag == TW_Valid)
     {
+      int precision_loss;
       int exp;
       FPU_REG tmp;
 
@@ -669,8+675,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
 
       if ( exp < SINGLE_Emin )
        {
-         int precision_loss;
-
          /* A denormal will always underflow. */
 #ifndef PECULIAR_486
          /* An 80486 is supposed to be able to generate
@@ -715,6+719,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
              unsigned long sigh = tmp.sigh;
              unsigned long sigl = tmp.sigl;
              
+             precision_loss = 1;
              switch (control_word & CW_RC)
                {
                case RC_RND:
@@ -740,8+745,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
          
              if (increment)
                {
-                 set_precision_flag_up();
-
                  if ( sigh >= 0xffffff00 )
                    {
                      /* The sigh part overflows */
@@ -758,10+761,11 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
                }
              else
                {
-                 set_precision_flag_down();
                  tmp.sigh &= 0xffffff00;  /* Finish the truncation */
                }
            }
+         else
+           precision_loss = 0;
 
          templ = (tmp.sigh >> 8) & 0x007fffff;
 
@@ -780,7+784,17 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
              templ = 0x7f800000;
            }
          else
-           templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+           {
+             if ( precision_loss )
+               {
+                 if ( increment )
+                   set_precision_flag_up();
+                 else
+                   set_precision_flag_down();
+               }
+             /* Add the exponent */
+             templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+           }
        }
     }
   else if (st0_tag == TW_Zero)
index e0bb665..d966ab1 100644 (file)
  |                                                                           |
  |                                                                           |
  | Copyright (C) 1992,1993,1994,1996                                         |
- |                     W. Metzenthen, 22 Parker St, Ormond, Vic 3163,        |
- |                     Australia.  E-mail   billm@jacobi.maths.monash.edu.au |
+ |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ |                  E-mail   billm@jacobi.maths.monash.edu.au                |
  |                                                                           |
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version 1.21"
+#define FPU_VERSION "wm-FPU-emu version 1.22"
index 7f49061..0e80259 100644 (file)
@@ -8,7+8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := amiga.o
-O_OBJS  := config.o amikeyb.o amiints.o amipart.o \
+O_OBJS  := config.o amikeyb.o amiints.o \
           chipram.o amisound.o amifb.o zorro.o
 OX_OBJS = ksyms.o
 
diff --git a/arch/m68k/amiga/amipart.c b/arch/m68k/amiga/amipart.c
deleted file mode 100644 (file)
index 6a1625e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * linux/amiga/amipart.c
- *
- * Amiga partition checking driver for 680x0 Linux
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- */
-
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-
-#include <asm/amigardb.h>
-#include <asm/machdep.h>
-
-extern int current_minor;
-
-static ulong checksum (ulong *ptr, int len)
-{
-       ulong sum;
-       int cnt;
-
-       for (sum = 0, cnt = 0; cnt < len; cnt++)
-               sum += ptr[cnt];
-
-       return sum;
-}
-
-/* XXX */
-/* int current_minor = 0; */
-
-void amiga_check_partition(struct gendisk *hd, kdev_t dev)
-{
-       int i, minor = current_minor, m_lim = current_minor + hd->max_p;
-       struct buffer_head *bh;
-       struct RigidDiskBlock *rdb;
-       struct PartitionBlock *pb;
-       ulong bnum, partsect;
-
-       for (bnum = 0; bnum < RDB_LOCATION_LIMIT/2; bnum++) {
-               if (!(bh = bread(dev,bnum,1024))) {
-                       printk (" unable to read block %ld\n", bnum);
-                       return;
-               }
-#ifdef DEBUG
-               printk ("block read, press mousebutton to continue\n");
-               waitbut();
-#endif
-               rdb = (struct RigidDiskBlock *)bh->b_data;
-               if (rdb->rdb_ID == IDNAME_RIGIDDISK)
-                       break;
-               rdb = (struct RigidDiskBlock *)&bh->b_data[512];
-               if (rdb->rdb_ID == IDNAME_RIGIDDISK)
-                       break;
-               brelse (bh);
-       }
-       if (bnum == RDB_LOCATION_LIMIT/2) {
-               /* no RDB on the disk! */
-               printk (" unable to find RigidDiskBlock\n");
-               return;
-       }
-
-       /* checksum the RigidDiskBlock */
-       if (checksum ((ulong *)rdb, rdb->rdb_SummedLongs) != 0) {
-               printk (" RDB checksum bad\n");
-               return;
-       }
-
-       printk("  %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
-
-       partsect = rdb->rdb_PartitionList;
-       brelse (bh);
-
-       for (i = 1; minor < m_lim && partsect != 0xffffffff; minor++, i++)
-       {
-               ulong *env;
-
-               if (!(bh = bread(dev,partsect/2,1024))) {
-                       printk (" block %ld read failed\n", partsect);
-                       return;
-               }
-#ifdef DEBUG
-               printk ("block read, press mousebutton to continue\n");
-               waitbut();
-#endif
-               pb = (struct PartitionBlock *)bh->b_data;
-               if (partsect & 1)
-                       pb = (struct PartitionBlock *)&bh->b_data[512];
-               if (pb->pb_ID != IDNAME_PARTITION) {
-                       printk (" block %ld Not a partition block (%#lx)\n",
-                               partsect, pb->pb_ID);
-                       brelse (bh);
-                       return;
-               }
-               if (checksum ((ulong *)pb, pb->pb_SummedLongs) != 0) {
-                       printk (" block %ld checksum bad\n", partsect);
-                       brelse (bh);
-                       return;
-               }
-
-               env = pb->pb_Environment;
-
-               hd->part[minor].start_sect = env[DE_LOWCYL]
-                       * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
-               hd->part[minor].nr_sects = (env[DE_UPPERCYL]
-                                           - env[DE_LOWCYL] + 1)
-                       * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
-
-               printk(" %s%c%d", hd->major_name,
-                      'a'+(minor >> hd->minor_shift), i);
-
-               partsect = pb->pb_Next;
-               brelse (bh);
-       }
-
-       printk ("\n");
-}
index 6637407..1564b67 100644 (file)
@@ -49,7+49,6 @@ extern void a3000_gettod (int *, int *, int *, int *, int *, int *);
 extern void a2000_gettod (int *, int *, int *, int *, int *, int *);
 extern int amiga_hwclk (int, struct hwclk_time *);
 extern int amiga_set_clock_mmss (unsigned long);
-extern void amiga_check_partition (struct gendisk *hd, unsigned int dev);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_BLK_DEV_FD
 extern int amiga_floppy_init (void);
@@ -288,7+287,6 @@ void config_amiga(void)
   }
   mach_hwclk           = amiga_hwclk;
   mach_set_clock_mmss  = amiga_set_clock_mmss;
-  mach_check_partition = amiga_check_partition;
   mach_mksound         = amiga_mksound;
 #ifdef CONFIG_BLK_DEV_FD
   mach_floppy_init     = amiga_floppy_init;
index b3643af..c84cb6c 100644 (file)
@@ -11,7+11,7 @@ EXTRA_CFLAGS := -Wa,-m68030
 
 O_TARGET := atari.o
 O_OBJS  := config.o atakeyb.o ataints.o \
-            atapart.o stdma.o atasound.o joystick.o stram.o atafb.o
+            stdma.o atasound.o joystick.o stram.o atafb.o
 OX_OBJS = ksyms.o
 
 include $(TOPDIR)/Rules.make
index 3320795..75ecd16 100644 (file)
@@ -1399,7+1399,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
        if (hw->ste_mode || mon_type!=F_MON_VGA)
                var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
        else
-               /* cant use this in ste_mode, because hbb is +1 off */
+               /* can't use this in ste_mode, because hbb is +1 off */
                var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
        var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
 
diff --git a/arch/m68k/atari/atapart.c b/arch/m68k/atari/atapart.c
deleted file mode 100644 (file)
index 72ba09b..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/atari/atapart.c
- *
- * Atari partition checking driver for 680x0 Linux
- * Written by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
- *
- * 5/3/94 Roman Hodek:
- *   Added some sanity checks
- *   Linux device names start from 1 not 0, so I changed the initial value
- *   for i to 1.
- *
- * 10/09/94 Guenther Kelleter:
- *   Added support for ICD/Supra partition info.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file README.legal in the main directory of this archive
- * for more details.
- */
-
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-
-#include <asm/atari_rootsec.h>
-
-/* ++guenther: this should be settable by the user ("make config")?.
- */
-#define ICD_PARTS
-
-extern int current_minor;
-
-void
-atari_check_partition (struct gendisk *hd, unsigned int dev)
-{
-  int i, minor = current_minor, m_lim = current_minor + hd->max_p;
-  struct buffer_head *bh;
-  struct rootsector *rs;
-  struct partition_info *pi;
-  ulong extensect;
-#ifdef ICD_PARTS
-  int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
-#endif
-
-  bh = bread (dev, 0, 1024);
-  if (!bh)
-    {
-      printk (" unable to read block 0\n");
-      return;
-    }
-
-  rs = (struct rootsector *) bh->b_data;
-  printk ("  %s%c:", hd->major_name, 'a' + (minor >> hd->minor_shift));
-
-  pi = &rs->part[0];
-  for (i = 1; pi < &rs->part[4] && minor < m_lim; i++, minor++, pi++)
-    {
-      if (pi->flg & 1)
-  /* active partition */
-  {
-    if (memcmp (pi->id, "XGM", 3) == 0)
-      /* extension partition */
-      {
-        struct rootsector *xrs;
-        struct buffer_head *xbh;
-        ulong partsect;
-
-#ifdef ICD_PARTS
-        part_fmt = 1;
-#endif
-        partsect = extensect = pi->st;
-        while (1)
-      {
-        xbh = bread (dev, partsect / 2, 1024);
-        if (!xbh)
-          {
-            printk (" block %ld read failed\n", partsect);
-            return;
-          }
-        if (partsect & 1)
-          xrs = (struct rootsector *) &xbh->b_data[512];
-        else
-          xrs = (struct rootsector *) &xbh->b_data[0];
-
-               /* ++roman: sanity check: bit 0 of flg field must be set */
-               if (!(xrs->part[0].flg & 1)) {
-                       printk( "\nFirst sub-partition in extended partition is not valid!\n" );
-                       break;
-               }
-               
-        hd->part[minor].start_sect = partsect + xrs->part[0].st;
-        hd->part[minor].nr_sects = xrs->part[0].siz;
-        printk (" %s%c%d", hd->major_name,
-            'a' + (minor >> hd->minor_shift), i);
-
-               if (!(xrs->part[1].flg & 1)) {
-                       /* end of linked partition list */
-                       brelse( xbh );
-                       break;
-               }
-               if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
-                       printk( "\nID of extended partition is not XGM!\n" );
-                       brelse( xbh );
-                       break;
-               }
-               
-               partsect = xrs->part[1].st + extensect;
-        brelse (xbh);
-        i++;
-        minor++;
-        if (minor >= m_lim) {
-                       printk( "\nMaximum number of partitions reached!\n" );
-                       break;
-               }
-      }
-      }
-    else
-      {
-        /* we don't care about other id's */
-        hd->part[minor].start_sect = pi->st;
-        hd->part[minor].nr_sects = pi->siz;
-        printk (" %s%c%d", hd->major_name,
-            'a' + (minor >> hd->minor_shift), i);
-
-      }
-  }
-    }
-#ifdef ICD_PARTS
-  if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
-  {
-    pi = &rs->icdpart[0];
-    /* 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 )
-    {
-      for (i = 1; pi < &rs->icdpart[8] && minor < m_lim; i++, minor++, pi++)
-      {
-        /* accept only GEM,BGM,RAW partitions */
-        if (pi->flg & 1 && 
-            (memcmp (pi->id, "GEM", 3) == 0 ||
-             memcmp (pi->id, "BGM", 3) == 0 ||
-             memcmp (pi->id, "RAW", 3) == 0) )
-        {
-          part_fmt = 2;
-          hd->part[minor].start_sect = pi->st;
-          hd->part[minor].nr_sects = pi->siz;
-          printk (" %s%c%d", hd->major_name,
-              'a' + (minor >> hd->minor_shift), i);
-        }
-      }
-    }
-  }
-#endif
-  brelse (bh);
-
-  printk ("\n");
-}
-
index fc7ad0c..3dd07cc 100644 (file)
@@ -60,7+60,6 @@ extern int atari_mste_hwclk (int, struct hwclk_time *);
 extern int atari_hwclk (int, struct hwclk_time *);
 extern int atari_mste_set_clock_mmss (unsigned long);
 extern int atari_set_clock_mmss (unsigned long);
-extern void atari_check_partition (struct gendisk *hd, unsigned int dev);
 extern void atari_mksound( unsigned int count, unsigned int ticks );
 extern void atari_reset( void );
 #ifdef CONFIG_BLK_DEV_FD
@@ -214,7+213,6 @@ void config_atari(void)
     mach_disable_irq     = atari_disable_irq;
     mach_get_irq_list   = atari_get_irq_list;
     mach_gettimeoffset   = atari_gettimeoffset;
-    mach_check_partition = atari_check_partition;
     mach_mksound         = atari_mksound;
     mach_reset           = atari_reset;
 #ifdef CONFIG_BLK_DEV_FD
index 86e1ef7..ab023d2 100644 (file)
@@ -143,6+143,17 @@ fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
 fi
+if [ "$CONFIG_ATARI" = y ]; then
+  tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
+  tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
+  tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
+fi
+if [ "$CONFIG_AMIGA" = y ]; then
+  tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+  bool 'GVP IO-Extender support' CONFIG_GVPIOEXT
+  tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+fi
+bool 'Support for user serial device modules' CONFIG_USERIAL
 bool 'Watchdog Timer Support'  CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
index 77e81b2..fdb4391 100644 (file)
@@ -721,7+721,7 @@ fail:
  *
  * Not a great fan of assembler for the sake of it, but I think
  * that these routines are at least 10 times faster than their C
- * equivalents for large blits, and thats important to the lowest level of
+ * equivalents for large blits, and that's 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
  * asynchrony.
index 8f23f7e..3650350 100644 (file)
@@ -17,7+17,7 @@ CONFIG_AMIGA=y
 # CONFIG_MAC is not set
 CONFIG_FPSP_040=y
 # CONFIG_IFPSP_060 is not set
-# CONFIG_NET is not set
+CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
index 7dbf253..b5a4a6e 100644 (file)
@@ -452,7+452,7 @@ Lmustsched:
        moveq   #-1,%d0
        movel   %d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
        bral    SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
-       
+
 
 |
 |      mem_write --- write to user or supervisor address space
index 880273e..560ffdb 100644 (file)
@@ -126,7+126,7 @@ An example of using the "cmp2" instruction is as follows:
 Exception reporting:
 --------------------
 If the instruction being emulated is a divide and the source
-operand is a zero, then the library routine, as it's last
+operand is a zero, then the library routine, as its last
 instruction, executes an implemented divide using a zero
 source operand so that an "Integer Divide-by-Zero" exception
 will be taken. Although the exception stack frame will not
index d922a14..5075a5a 100644 (file)
@@ -2049,7+2049,7 @@ void console_print(const char * b)
    /* undraw cursor first */
    hide_cursor(currcons);
 
-   /* Contrived structure to try and emulate original need_wrap behaviour
+   /* Contrived structure to try to emulate original need_wrap behaviour
     * Problems caused when we have need_wrap set on '\n' character */
    
    while ((c = *(b++)) != 0) {
index 8c90db2..b58587a 100644 (file)
 ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
 ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari 
 ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
+** 96/04/26 G|nther Kelleter: fixed identity mapping for Falcon with
+**                            Magnum- and FX-alternate ram
 **
 ** This file is subject to the terms and conditions of the GNU General Public
 ** License.  See the file README.legal in the main directory of this archive
@@ -146,6+148,16 @@ ENTRY(_start)
        movew   #0x2700,%sr
 
 /*
+ * Setup initial stack pointer
+ */
+       lea     %pc@(SYMBOL_NAME(_start)),%sp
+
+/* clear the fpu */
+       lea     %pc@(mmu),%a0
+       clrl    %a0@
+       frestore %a0@
+
+/*
  * Copy bootinfo from position after BSS to final resting place
  */
        lea     %pc@(SYMBOL_NAME(_end)),%a0
@@ -651,8+663,8 @@ Lamimmu68040:
        
        .word   0xf4d8          /* CINVA I/D */
        .word   0xf518          /* pflusha      */
-       .long   0x4e7bc807      /* movec a5,srp */
-       .long   0x4e7bc806      /* movec a5,urp */
+       .long   0x4e7bc807      /* movec a4,srp */
+       .long   0x4e7bc806      /* movec a4,urp */
        movel   #(TC_ENABLE+TC_PAGE4K),%d0
 
        /* setup registers for jumping MMU enabling code */
@@ -723,12+735,36 @@ Lmapphysnotamiga:
        /* cleanup is needed; note it */
        moveq   #1,%d5
 
+       /* tt0 doesn't work if physical and virtual address of kernel is in
+        * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
+        */
        movel   %a0,%d2
        andl    #0xff000000,%d2         /* logical address base */
+       jeq     1f
        orw     #0x8143,%d2             /* add in magic bits */
        lea     %pc@(mmu),%a0
        movel   %d2,%a0@
        pmove   %a0@,%tt0
+       jra     Lnophys2
+1:
+       /* Transparent translation through kernel pointer table
+        * Requires that this code until after MMU enabling lies in
+        * the 256K page around %a0
+        */
+       movel   %a0,%d2
+       moveq   #ROOT_INDEX_SHIFT,%d1
+       lsrl    %d1,%d2
+       movel   %a4@(%d2:l:4),%d0
+       andw    #0xfff0,%d0
+       movel   %d0,%a1
+       movel   %a0,%d2
+       andl    #0x01ffffff,%d2
+       moveq   #(ROOT_INDEX_SHIFT-7),%d1
+       lsrl    %d1,%d2
+       movel   %a0,%d0
+       addql   #PAGEDESC,%d0
+       movel   %a1@(%d2:l:4),%a2       /* save old_entry */
+       movel   %d0,%a1@(%d2:l:4)
 
 Lnophys2:
        /*
@@ -832,11+868,28 @@ LdoneMMUenable:
        cmpl    #MACH_ATARI,%d4
        jne     Lnoclean
 
+       movel   %a3,%d2
+       andl    #0xff000000,%d2
+       jeq     1f
        /* clear transparent translation register */
        lea     %pc@(mmu),%a0
        clrl    %a0@
        pmove   %a0@,%tt0
        jra     Lnoclean
+1:
+       movel   %a3,%d2
+       moveq   #ROOT_INDEX_SHIFT,%d1
+       lsrl    %d1,%d2
+       movel   %a4@(%d2:l:4),%d0
+       andw    #0xfff0,%d0
+       subl    %a3,%d0         /* to virtual address */
+       movel   %d0,%a0
+       movel   %a3,%d2
+       andl    #0x01ffffff,%d2
+       moveq   #(ROOT_INDEX_SHIFT-7),%d1
+       lsrl    %d1,%d2
+       movel   %a2,%a0@(%d2:l:4)       /* restore old entry */
+       jra     Lnoclean
 
 Lclean030:
        movel   %a0,%d2         /* a0 contains physical start address */
@@ -1177,7+1230,11 @@ showtest:
        rts
 #endif
 
-       .align 512      /*
+#ifdef __ELF__
+       .align 512
+#else
+       .align 9
+#endif                 /*
                         * MMU root-pointers need to be 512-byte
                         * aligned on the 680[46]0 - Jes
                         */
index b15e3e4..7424802 100644 (file)
@@ -62,7+62,6 @@ unsigned long (*mach_gettimeoffset) (void);
 void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
 int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_check_partition) (struct gendisk *, unsigned int);
 void (*mach_mksound)( unsigned int count, unsigned int ticks );
 void (*mach_reset)( void );
 void (*waitbut)(void) = dummy_waitbut;
@@ -296,10+295,6 @@ int get_hardware_list(char *buffer)
 #endif
     } /* boot_info.machtype */
 
-#if 0 /* ++1.3++ */
-    len += get_serial_list (buffer + len);
-#endif /* ++1.3++ */
-
     return(len);
 }
 
@@ -324,21+319,6 @@ unsigned long arch_kbd_init(void)
        return mach_keyb_init();
 }
 
-int rs_init(void)
-{
-       return 0;
-}
-
-struct serial_struct;
-int register_serial(struct serial_struct *req)
-{
-    return -1;
-}
-
-void unregister_serial(int line)
-{
-}
-
 void arch_gettod(int *year, int *mon, int *day, int *hour,
                 int *min, int *sec)
 {
index 97e010d..4261e60 100644 (file)
@@ -392,7+392,7 @@ static inline void bus_error030 (struct frame *fp)
                        }
                        printk ("BAD KERNEL BUSERR\n");
                        die_if_kernel("Oops",&fp->ptregs,0);
-                       send_sig(SIGSEGV, current, 1);
+                       force_sig(SIGSEGV, current);
                        user_space_fault = 0;
                }
        } else {
@@ -447,7+447,7 @@ static inline void bus_error030 (struct frame *fp)
                            !(ssw & RW) ? "write" : "read", addr,
                            fp->ptregs.pc);
                    die_if_kernel("Oops",&fp->ptregs,mmusr);
-                   send_sig(SIGSEGV, current, 1);
+                   force_sig(SIGSEGV, current);
                    return;
            } else {
 #ifdef DEBUG
@@ -478,7+478,7 @@ static inline void bus_error030 (struct frame *fp)
                    printk("Unknown SIGSEGV - 1\n");
 #endif
                    die_if_kernel("Oops",&fp->ptregs,mmusr);
-                   send_sig(SIGSEGV, current, 1);
+                   force_sig(SIGSEGV, current);
                    return;
            }
 
@@ -576,7+576,7 @@ static inline void bus_error030 (struct frame *fp)
                printk("Unknown SIGSEGV - 2\n");
 #endif
                die_if_kernel("Oops",&fp->ptregs,mmusr);
-               send_sig(SIGSEGV, current, 1);
+               force_sig(SIGSEGV, current);
                return;
        } else {
 #ifdef DEBUG
@@ -609,7+609,7 @@ static inline void bus_error030 (struct frame *fp)
                printk("Unknown SIGSEGV - 3\n");
 #endif
                die_if_kernel("Oops",&fp->ptregs,mmusr);
-               send_sig(SIGSEGV, current, 1);
+               force_sig(SIGSEGV, current);
                return;
        }
 
@@ -644,7+644,7 @@ asmlinkage void buserr_c(struct frame *fp)
 #if DEBUG
          printk("Unknown SIGSEGV - 4\n");
 #endif
-         send_sig(SIGSEGV, current, 1);
+         force_sig(SIGSEGV, current);
        }
 }
 
@@ -871,7+871,7 @@ asmlinkage void trap_c(struct frame *fp)
                break;
        }
 
-       send_sig (sig, current, 1);
+       force_sig (sig, current);
 }
 
 asmlinkage void set_esp0 (unsigned long ssp)
index 4152bb4..87e5489 100644 (file)
@@ -93,7+93,7 @@ good_area:
 bad_area:
        if (user_mode(regs)) {
                /* User memory access */
-               send_sig (SIGSEGV, current, 1);
+               force_sig (SIGSEGV, current);
                return 1;
        }
 
index 49aa454..e7157b2 100644 (file)
@@ -506,7+506,7 @@ void cache_push_v (unsigned long vaddr, int len)
                      : : "i" (FLUSH_I)
                      : "d0");
 }
-
+#if 1
 void flush_cache_all(void)
 {
     if (m68k_is040or060 >= 4)
@@ -515,26+515,53 @@ void flush_cache_all(void)
        asm volatile ("movec %/cacr,%/d0\n\t"
                      "oriw %0,%/d0\n\t"
                      "movec %/d0,%/cacr"
-                     : : "i" (FLUSH_I)
+                     : : "i" (FLUSH_I_AND_D)
                      : "d0");
 }
 
-void flush_page_to_ram (unsigned long addr)
+void flush_cache_mm(struct mm_struct *mm){
+
+    if (mm == current->mm)
+        flush_cache_all();
+}
+
+void flush_cache_range(struct mm_struct *mm, unsigned long start,
+                      unsigned long end){
+    if (mm == current->mm)
+        cache_push_v(start, end-start);
+}
+
+void flush_cache_page (struct vm_area_struct *vma, unsigned long vaddr)
 {
-    if (m68k_is040or060 == 4)
-        pushv040(addr);
+    if (m68k_is040or060 >= 4)
+        pushv040(vaddr); /*
+                         * the 040 always invalidates the I-cache when
+                         * pushing its contents to ram.
+                         */
+
+    /* 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_AND_D)
+                     : "d0");
+}
 
-    else if (m68k_is040or060 == 6)
-        push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */
+void flush_page_to_ram (unsigned long vaddr)
+{
+    if (m68k_is040or060 >= 4)
+        pushcl040(VTOP(vaddr));
 
     /* 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)
+                     : : "i" (FLUSH_I_AND_D)
                      : "d0");
 }
+#endif
 
 #undef clear040
 #undef push040
index d2acd3d..3c4fb86 100644 (file)
@@ -45,7+45,9 @@ bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 bool 'Networking support' CONFIG_NET
 #bool 'PCI bios support' CONFIG_PCI
 #if [ "$CONFIG_PCI" = "y" ]; then
-#  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+#  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+#  fi
 #fi
 bool 'System V IPC' CONFIG_SYSVIPC
 endmenu
index 6a5d518..a43761a 100644 (file)
                eret
                /*
                 * Workaround for R4000 bug.  For explanation see MIPS
-                * docs.  Note that this that obscure that it wont almost
-                * never happen.  Well, but Mips writes about it's bugs.
+                * docs.  Note that this is so obscure that it will almost
+                * never happen.  Well, but Mips writes about its bugs.
                 */
                nop
                eret
index ec2bb53..2583dfa 100644 (file)
@@ -202,7+202,7 @@ static void timer_interrupt(int irq, struct pt_regs * regs)
            last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
        /* As we return to user mode fire off the other CPU schedulers.. this is 
           basically because we don't yet share IRQ's around. This message is
-          rigged to be safe on the 386 - basically its a hack, so don't look
+          rigged to be safe on the 386 - basically it's a hack, so don't look
           closely for now.. */
        smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); 
 }
index 9da156c..52feb57 100644 (file)
@@ -168,7+168,7 @@ void __copy_page(unsigned long from, unsigned long to)
        {
                /*
                 * The page copied most is the COW empty_zero_page.  Since we
-                * know it's contents we can avoid the writeback reading of
+                * know its contents we can avoid the writeback reading of
                 * the page.  Speeds up the standard case a lot.
                 */
                __zeropage(to);
index d8717f8..813fd20 100644 (file)
@@ -29,7+29,9 @@ bool 'Networking support' CONFIG_NET y
 #bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
 bool 'PCI bios support' CONFIG_PCI y
 if [ "$CONFIG_PCI" = "y" ]; then
-  bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n
+  fi
   if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
     bool '   PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y
   fi
index dadbec4..ba82353 100644 (file)
@@ -1287,8+1287,8 @@ _GLOBAL(flush_data_cache)
        
 /*
  * This routine switches between two different tasks.  The process
- * state of one is saved on it's kernel stack.  Then the state
- * of the other is restored from it's kernel stack.  The memory
+ * state of one is saved on its kernel stack.  Then the state
+ * of the other is restored from its kernel stack.  The memory
  * management hardware is updated to the second process's state.
  * Finally, we can return to the second process, via the 'return'.
  *
index 48c93dd..189a72d 100644 (file)
@@ -4,7+4,7 @@ is real ugly and it knows too much.  It must be able to not only boot
 off of the root partition but also be able to netboot.  This means
 that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it
 can remote mount the root directory to fetch the kernel.  Also it must
-be able to ARP for it's IP address and who it's boot server is.  I
+be able to ARP for its IP address and who its boot server is.  I
 think I'm getting sick.
 
 Regardless for now I will concentrate on the low-level stuff necessary
index c6cffe4..8f4356f 100644 (file)
@@ -497,7+497,7 @@ copy_prom_lvl14:
                std     %g4, [%g3 + 0x8]        ! Copy proms handler
 
 /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
- * MMU so we can remap ourselves properly.  DONT TOUCH %l0 thru %l5 in these
+ * MMU so we can remap ourselves properly.  DON'T TOUCH %l0 thru %l5 in these
  * remapping routines, we need their values afterwards!
  */
                /* Now check whether we are already mapped, if we
@@ -571,7+571,7 @@ srmmu_remap:
                /* Grrr, why does it seem like every other load/store
                 * on the sun4m is in some ASI space...
                 * Fine with me, let's get the pointer to the level 1
-                * page table directory and fetch it's entry.
+                * page table directory and fetch its entry.
                 */
                lda     [%g4] ASI_M_BYPASS, %o1         ! This is a level 1 ptr
                srl     %o1, 0x4, %o1                   ! Clear low 4 bits
index edf5001..90da459 100644 (file)
@@ -81,7+81,7 @@ void (*set_irq_udt)(int);
  * equally sucky but at least we'll never try to free statically allocated
  * space or call kmalloc before kmalloc_init :(.
  * 
- * In fact its the timer10 that attaches first.. then timer14
+ * In fact it's the timer10 that attaches first.. then timer14
  * then kmalloc_init is called.. then the tty interrupts attach.
  * hmmm....
  *
index 5e10f57..6f9b4c5 100644 (file)
                THIS SOFTWARE IS NOT COPYRIGHTED
 
    HP offers the following for use in the public domain.  HP makes no
-   warranty with regard to the software or it's performance and the
+   warranty with regard to the software or its performance and the
    user accepts the software "AS IS" with all faults.
 
    HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
index 1832d72..77e2bb4 100644 (file)
@@ -41,10+41,10 @@ unsigned long *irq_rcvreg = &dummy;
 /* These tables only apply for interrupts greater than 15..
  * 
  * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but thats how I've done it.
+ * this may be useful or it may not.. but that's how I've done it.
  * and it won't clash with what OBP is telling us about devices.
  *
- * take an encoded intr value and lookup if its valid
+ * take an encoded intr value and lookup if it's valid
  * then get the mask bits that match from irq_mask
  */
 static unsigned char irq_xlate[32] = {
index 1153b5e..82eb2fb 100644 (file)
@@ -66,7+66,7 @@ C_LABEL(sparc_switch_to):
 
 #ifdef __SMP__
        /* Because of nasty register windows this is the only way
-        * to start a processor into it's cpu_idle() thread.
+        * to start a processor into its cpu_idle() thread.
         */
 
        .globl  C_LABEL(sparc_cpusched)
index 0aaf199..1b9ed11 100644 (file)
@@ -130,7+130,7 @@ spwin_exist_uwins:
        /* Wow, user windows have to be dealt with, this is dirty
         * and messy as all hell.  And difficult to follow if you
         * are approaching the infamous register window trap handling
-        * problem for the first time. DONT LOOK!
+        * problem for the first time. DON'T LOOK!
         *
         * Note that how the execution path works out, the new %wim
         * will be left for us in the global temporary register,
index 6725145..600dd1d 100644 (file)
@@ -1834,7+1834,7 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
        }
 #endif
        if(!num_contexts) {
-               prom_printf("Something wrong, cant find cpu node in paging_init.\n");
+               prom_printf("Something wrong, can't find cpu node in paging_init.\n");
                prom_halt();
        }
                
index f5a0fb4..510142d 100644 (file)
@@ -83,7+83,7 @@ prom_getproperty(int node, char *prop, char *buffer, int bufsize)
        return prom_nodeops->no_getprop(node, prop, buffer);
 }
 
-/* Acquire an integer property and return it's value.  Returns -1
+/* Acquire an integer property and return its value.  Returns -1
  * on failure.
  */
 int
index 9488f17..ddc581d 100644 (file)
@@ -42,7+42,7 @@ if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
 fi
 
-bool 'XT harddisk support' CONFIG_BLK_DEV_XD
+tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
   tristate '   Linear (append) mode' CONFIG_MD_LINEAR
index caec304..6651498 100644 (file)
@@ -99,6+99,10 @@ endif
 
 ifeq ($(CONFIG_BLK_DEV_XD),y)
 L_OBJS += xd.o
+else
+  ifeq ($(CONFIG_BLK_DEV_XD),m)
+  M_OBJS += xd.o
+  endif
 endif
 
 ifeq ($(CONFIG_BLK_DEV_MD),y)
index 7812581..7650bd7 100644 (file)
@@ -485,7+485,7 @@ In <41ip85$gf9@park.uvsc.edu>, Terry Lambert <terry@cs.weber.edu> writes:
 I agreed that you might be able to concoct a benchmark that was affected,
 but it has had no real world effect for me or a lot of other people.  Disabling
 IDE prefetch has the effect of a small increase in PCI bus busy at a time
-when the CPU is giving all it's CPU cycles to the IDE driver (because the
+when the CPU is giving all its CPU cycles to the IDE driver (because the
 RZ1000 can't run DMA and the driver has to be in a PIO loop) and therefore
 the CPU can't do much of anything else anyway.
 
index 0d58006..4cf9e7a 100644 (file)
  *  - added command line and machine based default for "silent" df0
  *
  *  december 1995 adapted for 1.2.13pl4 by Joerg Dorchain
- *  - works but I think its inefficient. (look in redo_fd_request)
+ *  - works but I think it's inefficient. (look in redo_fd_request)
  *    But the changes were very efficient. (only three and a half lines)
  *
  *  january 1995 added special ioctl for tracking down read/write problems
@@ -675,7+675,7 @@ unsigned char track,   /* 0-80 */
               len_desc;/* 2 */
 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
+                           adding a pad byte so data won't fit
                            and this cost about 3h to discover.... */
 unsigned char gap1[22];     /* for longword-alignedness (0x4e) */
 };
@@ -1780,3+1780,12 @@ int amiga_floppy_init(void)
 
   return 0;
 }
+
+#ifndef MODULE
+/*
+ * This is just a dummy function to keep fs/super.c happy.
+ */
+void floppy_eject(void)
+{
+}
+#endif
index 20de509..a4a2a30 100644 (file)
@@ -1945,4+1945,12 @@ void cleanup_module (void)
        timer_table[FLOPPY_TIMER].fn = 0;
        kfree (DMABuffer);
 }
+#else
+/*
+ * This is just a dummy function to keep fs/super.c happy.
+ */
+void floppy_eject(void)
+{
+}
 #endif
+
index 36eb4bc..dd7201a 100644 (file)
@@ -206,18+206,18 @@ void set_device_ro(kdev_t dev,int flag)
        else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
 }
 
-static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index)
+static inline void drive_stat_acct(int cmd, unsigned long nr_sectors,
+                                   short disk_index)
 {
        kstat.dk_drive[disk_index]++;
        if (cmd == READ) {
                kstat.dk_drive_rio[disk_index]++;
                kstat.dk_drive_rblk[disk_index] += nr_sectors;
-       }
-       else if (cmd == WRITE) {
+       } else if (cmd == WRITE) {
                kstat.dk_drive_wio[disk_index]++;
                kstat.dk_drive_wblk[disk_index] += nr_sectors;
        } else
-               printk("drive_stat_acct: cmd not R/W?\n");
+               printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
 }
 
 /*
@@ -289,9+289,15 @@ static void make_request(int major,int rw, struct buffer_head * bh)
        if (blk_size[major])
                if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
                        bh->b_state = 0;
-                       printk("attempt to access beyond end of device\n");
-                       printk("%s: rw=%d, want=%d, limit=%d\n", kdevname(bh->b_rdev),
-                        rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]);
+                        /* This may well happen - the kernel calls bread()
+                           without checking the size of the device, e.g.,
+                           when mounting a device. */
+                       printk(KERN_INFO
+                               "attempt to access beyond end of device\n");
+                       printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n",
+                               kdevname(bh->b_rdev), rw,
+                               (sector + count)>>1,
+                               blk_size[major][MINOR(bh->b_rdev)]);
                        return;
                }
        /* Uhhuh.. Nasty dead-lock possible here.. */
@@ -330,7+336,8 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                        max_req = (NR_REQUEST * 2) / 3;
                        break;
                default:
-                       printk("make_request: bad block dev cmd, must be R/W/RA/WA\n");
+                       printk(KERN_ERR "make_request: bad block dev cmd,"
+                               " must be R/W/RA/WA\n");
                        unlock_buffer(bh);
                        return;
        }
@@ -442,13+449,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
                bh++;
                if (--nr <= 0)
                        return;
-       };
+       }
 
        dev = NULL;
        if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
                dev = blk_dev + major;
        if (!dev || !dev->request_fn) {
-               printk(
+               printk(KERN_ERR
        "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
                kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
                goto sorry;
@@ -465,7+472,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
        /* Verify requested block sizes.  */
        for (i = 0; i < nr; i++) {
                if (bh[i] && bh[i]->b_size != correct_size) {
-                       printk("ll_rw_block: device %s: "
+                       printk(KERN_NOTICE "ll_rw_block: device %s: "
                               "only %d-char blocks implemented (%lu)\n",
                               kdevname(bh[0]->b_dev),
                               correct_size, bh[i]->b_size);
@@ -484,7+491,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
        }
 
        if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
-               printk("Can't write to read-only device %s\n",
+               printk(KERN_NOTICE "Can't write to read-only device %s\n",
                       kdevname(bh[0]->b_dev));
                goto sorry;
        }
@@ -519,7+526,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
        struct semaphore sem = MUTEX_LOCKED;
 
        if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
-               printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
+               printk(KERN_NOTICE "ll_rw_swap_file: trying to swap to"
+                                   " nonexistent block-device\n");
                return;
        }
        switch (rw) {
@@ -527,7+535,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
                        break;
                case WRITE:
                        if (is_read_only(dev)) {
-                               printk("Can't swap to read-only device %s\n",
+                               printk(KERN_NOTICE
+                                       "Can't swap to read-only device %s\n",
                                        kdevname(dev));
                                return;
                        }
@@ -547,7+556,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
                        if (major==MD_MAJOR &&
                            md_map (MINOR(dev), &rdev,
                                    &rsector, buffersize >> 9)) {
-                               printk ("Bad md_map in ll_rw_page_size\n");
+                               printk (KERN_ERR
+                                        "Bad md_map in ll_rw_page_size\n");
                                return;
                        }
 #endif
index 3c8bfa5..68096f6 100644 (file)
@@ -133,12+133,12 @@ static void figure_loop_size(struct loop_device *lo)
        int     size;
 
        if (S_ISREG(lo->lo_inode->i_mode))
-               size = (lo->lo_inode->i_size - lo->lo_offset) / 1024;
+               size = (lo->lo_inode->i_size - lo->lo_offset) / BLOCK_SIZE;
        else {
-               if (blk_size[MAJOR(lo->lo_device)])
-                       size = ((blk_size[MAJOR(lo->lo_device)]
-                                [MINOR(lo->lo_device)]) -
-                               (lo->lo_offset/1024));
+               kdev_t lodev = lo->lo_device;
+               if (blk_size[MAJOR(lodev)])
+                       size = blk_size[MAJOR(lodev)][MINOR(lodev)] -
+                                lo->lo_offset / BLOCK_SIZE;
                else
                        size = MAX_DISK_SIZE;
        }
@@ -307,11+307,15 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
 static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
 {
        struct loop_info info;
+       int err;
 
        if (!lo->lo_inode)
                return -ENXIO;
        if (!arg)
                return -EINVAL;
+       err = verify_area(VERIFY_READ, arg, sizeof(info));
+       if (err)
+               return err;
        memcpy_fromfs(&info, arg, sizeof(info));
        if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
@@ -349,11+353,15 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
 static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
 {
        struct loop_info        info;
+       int err;
        
        if (!lo->lo_inode)
                return -ENXIO;
        if (!arg)
                return -EINVAL;
+       err = verify_area(VERIFY_WRITE, arg, sizeof(info));
+       if (err)
+               return err;
        memset(&info, 0, sizeof(info));
        info.lo_number = lo->lo_number;
        info.lo_device = kdev_t_to_nr(lo->lo_inode->i_dev);
index f1b8103..455a26b 100644 (file)
  *   interrupts enabled and Linus didn't want to enable them in that first
  *   phase. xd_geninit() is the place to do these kinds of things anyway,
  *   he says.
+ *
+ * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
+ *
  */
 
 
@@ -64,6+67,7 @@ XD_INFO xd_info[XD_MAXDRIVES];
 
 static XD_SIGNATURE xd_sigs[] = {
        { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */
+       { 0x000B,"CRD18A   Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */
        { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */
        { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
        { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
@@ -89,7+93,11 @@ static struct gendisk xd_gendisk = {
        6,              /* Bits to shift to get real from partition */
        1 << 6,         /* Number of partitions per real */
        XD_MAXDRIVES,   /* maximum number of real */
-       xd_geninit,     /* init function */
+#ifdef MODULE
+       NULL,           /* called from init_module */
+#else
+        xd_geninit,     /* init function */
+#endif
        xd,             /* hd struct */
        xd_sizes,       /* block sizes */
        0,              /* number */
@@ -727,3+735,23 @@ static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylind
                printk("xd_setparam: error setting characteristics for drive %d\n",drive);
 }
 
+
+#ifdef MODULE
+int init_module(void)
+{
+       int error = xd_init();
+       if (!error)
+       {
+               printk(KERN_INFO "XD: Loaded as a module.\n");
+               xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+       }
+        
+       return error;
+}
+
+void cleanup_module(void)
+{
+       unregister_blkdev(MAJOR_NR, "xd");
+}
+#endif /* MODULE */
+
index 9c25513..18e4f23 100644 (file)
                 Werner Zimmermann, April 29, 96
         V2.40   Reorganized the placement of functions in the source code file
                 to reflect the layered approach; did not actually change code
-                Werner Zimmermann, Mai 1, 96
+                Werner Zimmermann, May 1, 96
 */
 #include <linux/module.h>
 #include <linux/errno.h>
index d517ac4..f2b9a26 100644 (file)
@@ -1,6+1,6 @@
 Wed Apr 24 14:02:04 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
-       * random.c (add_timer_randomness): Use 2nd derivitive as well to
+       * random.c (add_timer_randomness): Use 2nd derivative as well to
                better estimate entropy.
 
                (rand_initialize): Explicitly initialize all the pointers
index 964efa1..f718e45 100644 (file)
@@ -864,7+864,7 @@ static void csi_m(int currcons)
                                toggle_meta = 0;
                                break;
                        case 11: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select first alternate font, let's
+                                 * Select first alternate font, lets
                                  * chars < 32 be displayed as ROM chars.
                                  */
                                translate = set_translate(IBMPC_MAP);
index 5756f0a..488ea1a 100644 (file)
@@ -45,6+45,10 @@ static inline int PROC_CONSOLE(void)
        if (!current->tty)
                return fg_console;
 
+       if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+               /* XXX Should report error here? */
+               return fg_console;
+
        if (MINOR(current->tty->device) < 1)
                return fg_console;
 
@@ -180,6+184,18 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        if (i) return i;
                }
                return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
+       case FBIOPAN_DISPLAY:
+               i = verify_area(VERIFY_WRITE, (void *) arg, 
+                               sizeof(struct fb_var_screeninfo));
+               if (i) return i;
+               memcpy_fromfs(&var, (void *) arg, sizeof(var));
+               i=fb->fb_pan_display(&var, PROC_CONSOLE());
+               memcpy_tofs((void *) arg, &var, sizeof(var));
+               fbidx=GET_FB_IDX(inode->i_rdev);
+               vidx=GET_FB_VAR_IDX(inode->i_rdev);
+               if (! i && vidx)
+                       registered_fb_var[fbidx][vidx-1]=var;
+               return i;
        default:
                return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
        }
@@ -199,8+215,11 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
        vma->vm_offset += fix.smem_start;
        if (vma->vm_offset & ~PAGE_MASK)
                return -ENXIO;
-       if (boot_info.cputype & CPU_68040)
+       if (m68k_is040or060) {
                pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+               /* Use write-through cache mode */
+               pgprot_val(vma->vm_page_prot) |= _PAGE_CACHE040W;
+       }
        if (remap_page_range(vma->vm_start, vma->vm_offset,
                             vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
index 5161526..3d9b396 100644 (file)
@@ -606,8+606,8 @@ int _ftape_read(char *buff, int req_len)
                 *  get more than 29 Kb from it (As it only contains this much).
                 *  This works only for sequential access, so random access should
                 *  stay away from this `last' segment.
-                *  Note: ftape_seg_pos points to the next segment what will be
-                *        read, so it's one too hight here!
+                *  Note: ftape_seg_pos points to the next segment that will be
+                *        read, so it's one too high here!
                 */
                if (!eof_mark && ftape_seg_pos - 1 >= ftape_last_segment.id) {
                        TRACEi(5, "remaining of last segment:", remaining);
index e9981dc..fcb2f46 100644 (file)
 /*      Global vars.
  */
 
-/* Allocating a 96Kb DMAable buffer in one chunk wont work due to
+/* Allocating a 96Kb DMAable buffer in one chunk won't work due to
  * memory fragmentation.  To avoid this, it is broken up into
  * NR_BUFFERS chunks of 32Kbyte. --khp
  */
index 2cb6fd0..2cc26a9 100644 (file)
@@ -3386,7+3386,7 @@ static int stli_initecp(stlibrd_t *brdp)
        }
 
 /*
- *     The per-board operations structure is all setup, so now lets go
+ *     The per-board operations structure is all set up, so now let's go
  *     and get the board operational. Firstly initialize board configuration
  *     registers. Then if we are using the higher 1Mb support then set up
  *     the memory mapping info so we can get at the boards shared memory.
@@ -3542,7+3542,7 @@ static int stli_initonb(stlibrd_t *brdp)
        }
 
 /*
- *     The per-board operations structure is all setup, so now lets go
+ *     The per-board operations structure is all set up, so now let's go
  *     and get the board operational. Firstly initialize board configuration
  *     registers. Then if we are using the higher 1Mb support then set up
  *     the memory mapping info so we can get at the boards shared memory.
index deb7c35..1c4742f 100644 (file)
@@ -183,14+183,14 @@ static inline int lp_write_interrupt(unsigned int minor, const char * buf, int c
                                if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
                                         LP_STAT(minor).maxrun = lp_table[minor].runchars;
                                status = LP_S(minor);
-                               if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
-                                       printk(KERN_INFO "lp%d off-line\n", minor);
-                                       if (LP_F(minor) & LP_ABORT)
-                                               return rc?rc:-EIO;
-                               } else if ((status & LP_POUTPA)) {
+                               if ((status & LP_POUTPA)) {
                                        printk(KERN_INFO "lp%d out of paper\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
                                                return rc?rc:-ENOSPC;
+                               } else if (!(status & LP_PSELECD)) {
+                                       printk(KERN_INFO "lp%d off-line\n", minor);
+                                       if (LP_F(minor) & LP_ABORT)
+                                               return rc?rc:-EIO;
                                } else if (!(status & LP_PERRORP)) {
                                        printk(KERN_ERR "lp%d printer error\n", minor);
                                        if (LP_F(minor) & LP_ABORT)
@@ -248,18+248,18 @@ static inline int lp_write_polled(unsigned int minor, const char * buf, int coun
                                 LP_STAT(minor).maxrun = lp_table[minor].runchars;
                        status = LP_S(minor);
 
-                       if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
-                               printk(KERN_INFO "lp%d off-line\n", minor);
+                       if (status & LP_POUTPA) {
+                               printk(KERN_INFO "lp%d out of paper\n", minor);
                                if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-EIO;
+                                       return temp-buf?temp-buf:-ENOSPC;
                                current->state = TASK_INTERRUPTIBLE;
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
                                schedule();
                        } else
-                       if (status & LP_POUTPA) {
-                               printk(KERN_INFO "lp%d out of paper\n", minor);
+                       if (!(status & LP_PSELECD)) {
+                               printk(KERN_INFO "lp%d off-line\n", minor);
                                if(LP_F(minor) & LP_ABORT)
-                                       return temp-buf?temp-buf:-ENOSPC;
+                                       return temp-buf?temp-buf:-EIO;
                                current->state = TASK_INTERRUPTIBLE;
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
                                schedule();
index 42eeed3..8610862 100644 (file)
@@ -236,13+236,13 @@ static int lp_write_interrupt(struct inode *inode, struct file *file,
           been printed at all. */
        
        if (lp_table[dev].lp_has_pout(dev)) {
-         printk("lp%d: paper-out\n",dev);
+         printk(KERN_NOTICE "lp%d: paper-out\n",dev);
          if (!rc) rc = -ENOSPC;
        } else if (!lp_table[dev].lp_is_online(dev)) {
-         printk("lp%d: off-line\n",dev);
+         printk(KERN_NOTICE "lp%d: off-line\n",dev);
          if (!rc) rc = -EIO;
        } else if (lp_table[dev].lp_is_busy(dev)) {
-         printk("lp%d: on fire\n",dev);
+         printk(KERN_NOTICE "lp%d: on fire\n",dev);
          if (!rc) rc = -EIO;
        }
        if (lp_table[dev].flags & LP_ABORT)
@@ -294,14+294,14 @@ static int lp_write_polled(struct inode *inode, struct file *file,
 #endif
                } else { /* if printer timed out */
                        if (lp_table[dev].lp_has_pout(dev)) {
-                               printk("lp%d: out of paper\n",dev);
+                               printk(KERN_NOTICE "lp%d: out of paper\n",dev);
                                if (lp_table[dev].flags & LP_ABORT)
                                        return temp - buf ? temp-buf : -ENOSPC;
                                current->state = TASK_INTERRUPTIBLE;
                                current->timeout = jiffies + LP_TIMEOUT_POLLED;
                                schedule();
                        } else if (!lp_table[dev].lp_is_online(dev)) {
-                               printk("lp%d: off-line\n",dev);
+                               printk(KERN_NOTICE "lp%d: off-line\n",dev);
                                if (lp_table[dev].flags & LP_ABORT)
                                        return temp - buf ? temp-buf : -EIO;
                                current->state = TASK_INTERRUPTIBLE;
@@ -310,7+310,7 @@ static int lp_write_polled(struct inode *inode, struct file *file,
                        } else
                        /* not offline or out of paper. on fire? */
                        if (lp_table[dev].lp_is_busy(dev)) {
-                               printk("lp%d: on fire\n",dev);
+                               printk(KERN_NOTICE "lp%d: on fire\n",dev);
                                if (lp_table[dev].flags & LP_ABORT)
                                        return temp - buf ? temp-buf : -EFAULT;
                                current->state = TASK_INTERRUPTIBLE;
@@ -447,7+447,7 @@ int lp_init(void)
 
 #if WHICH_DRIVER == FORCE_POLLING
        lp_irq = 0;
-       printk("lp_init: lp using polling driver\n");
+       printk(KERN_INFO "lp_init: lp using polling driver\n");
 #else
 
 #ifdef CONFIG_AMIGA
@@ -462,13+462,13 @@ int lp_init(void)
 #endif
 
        if (lp_irq)
-               printk("lp_init: lp using interrupt\n");
+               printk(KERN_INFO "lp_init: lp using interrupt\n");
        else
 
 #if WHICH_DRIVER == PREFER_INTERRUPT
-               printk("lp_init: lp using polling driver\n");
+               printk(KERN_INFO "lp_init: lp using polling driver\n");
 #else
-               printk("lp_init: cant get interrupt, and polling driver not configured\n");
+               printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n");
 #endif
 #endif
 
index 2e5bd4c..5666b2a 100644 (file)
    19200 = 57600
    38400 = 115K
    The driver supports the native 57.6K and 115K Baudrates under Linux, but
-   some distributions like Slackware 3.0 dont like these high baudrates.
+   some distributions like Slackware 3.0 don't like these high baudrates.
 */
 
 #include <linux/mm.h>
@@ -1602,7+1602,7 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
        {
                ch->digiext.digi_flags |= DIGI_FAST;
                res |= FEP_HUPCL;
-               /* This gets strange but if we dont do this we will get 78600
+               /* This gets strange but if we don't do this we will get 78600
                 * instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
                 * FAST mode. 115200 is mapped to 75. We need to map it to 110 to
                 * do 115K
index 1e1a3e8..363b593 100644 (file)
@@ -315,13+315,13 @@ static int open_aux(struct inode * inode, struct file * file)
                aux_count--;
                return -EBUSY;
        }
+       MOD_INC_USE_COUNT;
        poll_aux_status();
        outb_p(AUX_ENABLE,AUX_COMMAND);         /* Enable Aux */
        aux_write_dev(AUX_ENABLE_DEV);          /* enable aux device */
        aux_write_cmd(AUX_INTS_ON);             /* enable controller ints */
        poll_aux_status();
        aux_ready = 0;
-       MOD_INC_USE_COUNT;
        return 0;
 }
 
index 2066fa8..b004a33 100644 (file)
@@ -181,7+181,9 @@ static void pty_flush_buffer(struct tty_struct *tty)
 
 int pty_open(struct tty_struct *tty, struct file * filp)
 {
+#if PTY_SLAVE_WAITS_ON_OPEN
        struct wait_queue wait = { current, NULL };
+#endif
        int     retval;
        int     line;
        struct  pty_struct *pty;
index 262d320..9873f8a 100644 (file)
  *     fi
  *     dd if=/dev/urandom of=/etc/random-seed count=1
  *
- * and the following lines in an approproate script which is run as
+ * and the following lines in an appropriate script which is run as
  * the system is shutdown:
  * 
  *     # Carry a random seed from shut-down to start-up
@@ -574,7+574,7 @@ void add_blkdev_randomness(int major)
 #define HASH_TRANSFORM SHATransform
 
 /*
- * SHA transform algorith, taken from code written by Peter Gutman,
+ * SHA transform algorithm, taken from code written by Peter Gutman,
  * and apparently in the public domain.
  */
 
@@ -615,7+615,7 @@ void SHATransform(__u32 *digest, __u32 *data)
     E = digest[ 4 ];
     memcpy( eData, data, 16*sizeof(__u32));
 
-    /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+    /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
     subRound( A, B, C, D, E, f1, K1, eData[  0 ] );
     subRound( E, A, B, C, D, f1, K1, eData[  1 ] );
     subRound( D, E, A, B, C, f1, K1, eData[  2 ] );
index 5e18b96..4d04711 100644 (file)
  *
  */
 
-#define RTC_VERSION            "1.05"
+#define RTC_VERSION            "1.06"
 
 #define RTC_IRQ        8       /* Can't see this changing soon.        */
 #define RTC_IO_BASE    0x70    /* Or this...                           */
 #include <asm/segment.h>
 #include <asm/system.h>
 
-#include <time.h>
-
 /*
  *     We sponge a minor off of the misc major. No need slurping
  *     up another valuable major dev number for this.
@@ -81,14+79,14 @@ static int rtc_ioctl(struct inode *inode, struct file *file,
 static int rtc_select(struct inode *inode, struct file *file,
                        int sel_type, select_table *wait);
 
-void get_rtc_time (struct tm *rtc_tm);
-void get_rtc_alm_time (struct tm *alm_tm);
+void get_rtc_time (struct rtc_time *rtc_tm);
+void get_rtc_alm_time (struct rtc_time *alm_tm);
 void rtc_dropped_irq(unsigned long data);
 
-inline void set_rtc_irq_bit(unsigned char bit);
-inline void mask_rtc_irq_bit(unsigned char bit);
+void set_rtc_irq_bit(unsigned char bit);
+void mask_rtc_irq_bit(unsigned char bit);
 
-unsigned char rtc_is_updating(void);
+static inline unsigned char rtc_is_updating(void);
 
 /*
  *     Bits in rtc_status. (7 bits of room for future expansion)
@@ -221,10+219,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                         * than 64Hz of interrupts on a multi-user machine.
                         */
                        if ((rtc_freq > 64) && (!suser()))
-                               return -EPERM;
-
-                       if (rtc_freq == 0)
-                               return -EINVAL;
+                               return -EACCES;
 
                        if (!(rtc_status & RTC_TIMER_ON)) {
                                rtc_status |= RTC_TIMER_ON;
@@ -247,39+242,39 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                case RTC_ALM_READ:      /* Read the present alarm time */
                {
                        /*
-                        * This returns a struct tm. Reading >= 0xc0 means
-                        * "don't care" or "match all". Only the tm_hour,
+                        * This returns a struct rtc_time. Reading >= 0xc0
+                        * means "don't care" or "match all". Only the tm_hour,
                         * tm_min, and tm_sec values are filled in.
                         */
                        int retval;
-                       struct tm alm_tm;
+                       struct rtc_time alm_tm;
 
-                       retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+                       retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
                        if (retval != 0 )
                                return retval;
 
                        get_rtc_alm_time(&alm_tm);
 
-                       memcpy_tofs((struct tm*)arg, &alm_tm, sizeof(struct tm));
+                       memcpy_tofs((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time));
                        
                        return 0;
                }
                case RTC_ALM_SET:       /* Store a time into the alarm */
                {
                        /*
-                        * This expects a struct tm. Writing 0xff means
+                        * This expects a struct rtc_time. Writing 0xff means
                         * "don't care" or "match all". Only the tm_hour,
                         * tm_min and tm_sec are used.
                         */
                        int retval;
                        unsigned char hrs, min, sec;
-                       struct tm alm_tm;
+                       struct rtc_time alm_tm;
 
-                       retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+                       retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
                        if (retval != 0 )
                                return retval;
 
-                       memcpy_fromfs(&alm_tm, (struct tm*)arg, sizeof(struct tm));
+                       memcpy_fromfs(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
 
                        hrs = alm_tm.tm_hour;
                        min = alm_tm.tm_min;
@@ -313,33+308,33 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                case RTC_RD_TIME:       /* Read the time/date from RTC  */
                {
                        int retval;
-                       struct tm rtc_tm;
+                       struct rtc_time rtc_tm;
                        
-                       retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+                       retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
                        if (retval !=0 )
                                return retval;
 
                        get_rtc_time(&rtc_tm);
-                       memcpy_tofs((struct tm*)arg, &rtc_tm, sizeof(struct tm));
+                       memcpy_tofs((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time));
                        return 0;
                }
                case RTC_SET_TIME:      /* Set the RTC */
                {
                        int retval;
-                       struct tm rtc_tm;
+                       struct rtc_time rtc_tm;
                        unsigned char mon, day, hrs, min, sec, leap_yr;
                        unsigned char save_control, save_freq_select;
                        unsigned int yrs;
                        unsigned long flags;
                        
                        if (!suser())
-                               return -EPERM;
+                               return -EACCES;
 
-                       retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+                       retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
                        if (retval !=0 )
                                return retval;
 
-                       memcpy_fromfs(&rtc_tm, (struct tm*)arg, sizeof(struct tm));
+                       memcpy_fromfs(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
 
                        yrs = rtc_tm.tm_year + 1900;
                        mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
@@ -424,7+419,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                         * than 64Hz of interrupts on a multi-user machine.
                         */
                        if ((arg > 64) && (!suser()))
-                               return -EPERM;
+                               return -EACCES;
 
                        while (arg > (1<<tmp))
                                tmp++;
@@ -432,7+427,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        /*
                         * Check that the input was really a power of 2.
                         */
-                       if ((arg != 0) && (arg != (1<<tmp)))
+                       if (arg != (1<<tmp))
                                return -EINVAL;
 
                        rtc_freq = arg;
@@ -440,13+435,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        save_flags(flags);
                        cli();
                        val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
-
-                       if (arg == 0) {
-                               CMOS_WRITE(val, RTC_FREQ_SELECT);
-                               restore_flags(flags);
-                               return 0;
-                       }
-
                        val |= (16 - tmp);
                        CMOS_WRITE(val, RTC_FREQ_SELECT);
                        restore_flags(flags);
@@ -557,9+545,10 @@ int rtc_init(void)
        rtc_wait = NULL;
        save_flags(flags);
        cli();
-       rtc_freq = CMOS_READ(RTC_FREQ_SELECT) & 0x0F;
+       /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
+       CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
        restore_flags(flags);
-       rtc_freq = (rtc_freq ? (65536/(1<<rtc_freq)) : 0);
+       rtc_freq = 1024;
        return 0;
 }
 
@@ -599,7+588,7 @@ void rtc_dropped_irq(unsigned long data)
 int get_rtc_status(char *buf)
 {
        char *p;
-       struct tm tm;
+       struct rtc_time tm;
        unsigned char batt, ctrl;
        unsigned long flags;
 
@@ -650,7+639,7 @@ int get_rtc_status(char *buf)
                "DST_enable\t: %s\n"
                "BCD\t\t: %s\n"
                "24hr\t\t: %s\n"
-               "sqare_wave\t: %s\n"
+               "square_wave\t: %s\n"
                "alarm_IRQ\t: %s\n"
                "update_IRQ\t: %s\n"
                "periodic_IRQ\t: %s\n"
@@ -672,7+661,7 @@ int get_rtc_status(char *buf)
 /*
  * Returns true if a clock update is in progress
  */
-inline unsigned char rtc_is_updating(void)
+static inline unsigned char rtc_is_updating(void)
 {
        unsigned long flags;
        unsigned char uip;
@@ -684,7+673,7 @@ inline unsigned char rtc_is_updating(void)
        return uip;
 }
 
-void get_rtc_time(struct tm *rtc_tm)
+void get_rtc_time(struct rtc_time *rtc_tm)
 {
 
        unsigned long flags, uip_watchdog = jiffies;
@@ -733,7+722,7 @@ void get_rtc_time(struct tm *rtc_tm)
 
        /*
         * Account for differences between how the RTC uses the values
-        * and how they are defined in a struct tm;
+        * and how they are defined in a struct rtc_time;
         */
        if (rtc_tm->tm_year <= 69)
                rtc_tm->tm_year += 100;
@@ -741,7+730,7 @@ void get_rtc_time(struct tm *rtc_tm)
        rtc_tm->tm_mon--;
 }
 
-void get_rtc_alm_time(struct tm *alm_tm)
+void get_rtc_alm_time(struct rtc_time *alm_tm)
 {
        unsigned long flags;
        unsigned char ctrl;
@@ -775,7+764,7 @@ void get_rtc_alm_time(struct tm *alm_tm)
  * We also clear out any old irq data after an ioctl() that
  * meddles the interrupt enable/disable bits.
  */
-inline void mask_rtc_irq_bit(unsigned char bit)
+void mask_rtc_irq_bit(unsigned char bit)
 {
        unsigned char val;
        unsigned long flags;
@@ -790,7+779,7 @@ inline void mask_rtc_irq_bit(unsigned char bit)
        rtc_irq_data = 0;
 }
 
-inline void set_rtc_irq_bit(unsigned char bit)
+void set_rtc_irq_bit(unsigned char bit)
 {
        unsigned char val;
        unsigned long flags;
index 2e0195b..c58a1f2 100644 (file)
@@ -495,7+495,7 @@ void cleanup_module()
 /*
  *     Free up all allocated resources used by the ports. This includes
  *     memory and interrupts. As part of this process we will also do
- *     a hangup on every open port - to try and flush out any processes
+ *     a hangup on every open port - to try to flush out any processes
  *     hanging onto ports.
  */
        i = tty_unregister_driver(&stl_serial);
@@ -2383,7+2383,7 @@ static int stl_mapirq(int irq)
 /*****************************************************************************/
 
 /*
- *     Try and find and initialize all the ports on a panel. We don't care
+ *     Try to find and initialize all the ports on a panel. We don't care
  *     what sort of board these ports are on - since the port io registers
  *     are almost identical when dealing with ports.
  */
@@ -2861,7+2861,7 @@ static int stl_initbrds()
 
 #ifdef CONFIG_PCI
 /*
- *     If the PCI BIOS support is compiled in then lets go looking for
+ *     If the PCI BIOS support is compiled in then let's go looking for
  *     ECH-PCI boards.
  */
        stl_findpcibrds();
index 52f9a40..df9af35 100644 (file)
@@ -149,7+149,7 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, int count)
                org = screen_pos(cons, p, viewed);
                while (count-- > 0) {
                        scr_writew((scr_readw(org) & 0xff00) |
-                                  get_user(buf++), org);
+                                  get_user((const unsigned char*)buf++), org);
                        org++;
                }
        } else {
@@ -175,7+175,7 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, int count)
                }
                if (count > 0)
                        scr_writew((scr_readw(org) & 0xff00) |
-                                  get_user(buf++), org);
+                                  get_user((const unsigned char*)buf++), org);
        }
        written = buf - buf0;
        file->f_pos += written;
index ad6a150..0fe5305 100644 (file)
  * Colour palette handling, by Simon Tatham
  * 17-Jun-95 <sgt20@cam.ac.uk>
  *
+ * if 512 char mode is already enabled don't re-enable it,
+ * because it causes screen to flicker, by Mitja Horvat
+ * 5-May-96 <mitja.horvat@guest.arnes.si>
+ *
  */
 
 #include <linux/sched.h>
@@ -308,6+312,7 @@ int
 set_get_font(char * arg, int set, int ch512)
 {
 #ifdef CAN_LOAD_EGA_FONTS
+       static int ch512enabled = 0;
        int i;
        char *charmap;
        int beg;
@@ -432,8+437,11 @@ set_get_font(char * arg, int set, int ch512)
        outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
        outb_p( 0x06, gr_port_reg );
        outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
-       if (set)                        /* attribute controller */
+
+       /* if 512 char mode is already enabled don't re-enable it. */
+       if ((set)&&(ch512!=ch512enabled))       /* attribute controller */
          {
+           ch512enabled=ch512;
            /* 256-char: enable intensity bit
               512-char: disable intensity bit */
            inb_p( video_port_status ); /* clear address flip-flop */
index 761a8d9..99600a6 100644 (file)
@@ -489,7+489,7 @@ static int isdn_status_callback(isdn_ctrl * c)
                                 break;
                        if ((mi = dev->m_idx[i]) >= 0) {
                                /* Schedule CONNECT-Message to any tty, waiting for it and
-                                * set DCD-bit of it's modem-status.
+                                * set DCD-bit of its modem-status.
                                 */
                                if (dev->mdm.info[mi].flags &
                                    (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
index 6f9d76b..ba93884 100644 (file)
  * Correct ARP-handling for ETHERNET-encapsulation.
  *
  * Revision 1.2  1996/01/22 05:05:12  fritz
- * Changed returncode-logic for isdn_net_start_xmit() and it's
+ * Changed returncode-logic for isdn_net_start_xmit() and its
  * helper-functions.
  * Changed handling of buildheader for RAWIP and ETHERNET-encapsulation.
  *
@@ -195,7+195,7 @@ isdn_net_autohup()
 /*
  * Handle status-messages from ISDN-interfacecard.
  * This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the lowlevel-driver.
+ * isdn_status_callback, which itself is called from the low-level driver.
  * Return: 1 = Event handled, 0 = not for us or unknown Event.
  */
 int
@@ -1200,7+1200,7 @@ isdn_net_rebuild_header(void *buff, struct device *dev, ulong dst,
                         return 0;
                 }
                 /*
-                 *      Try and get ARP to resolve the header.
+                 *      Try to get ARP to resolve the header.
                  */
 #ifdef CONFIG_INET       
                 ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0;
@@ -1775,7+1775,7 @@ isdn_net_force_dial(char *name)
 }
 
 /*
- * Allocate a new network-interface and initialize it's data structures.
+ * Allocate a new network-interface and initialize its data structures.
  */
 char *
 isdn_net_new(char *name, struct device *master)
index 994ed9a..eab7e46 100644 (file)
@@ -802,10+802,12 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        isdn_net_local *lp = nd->queue;
        int proto = PPP_IP;     /* 0x21 */
        struct ippp_struct *ipt = ippp_table[lp->ppp_minor];
+#if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP)
        struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor];
+#endif
 
         /* If packet is to be resent, it has already been processed and
-         * therefore it's first bytes are already initialized. In this case
+         * therefore its first bytes are already initialized. In this case
          * send it immediately ...
          */
         if (*((unsigned long *)skb->data) != 0)
index 623546f..4c8e7c9 100644 (file)
     
        The combination of slow receive restart and no real multicast
     filter makes the board unusable with a kernel compiled for IP
-    multicasting in a real multicast environment. Thats down to the board, 
+    multicasting in a real multicast environment. That's down to the board, 
     but even with no multicast programs running a multicast IP kernel is
     in group 224.0.0.1 and you will therefore be listening to all multicasts.
     One nv conference running over that ethernet and you can give up.
index 05c8963..aee0038 100644 (file)
   This is not a complete driver, it must be combined with board-specific
   code such as ne.c, wd.c, 3c503.c, etc.
 
+  Seeing how at least eight drivers use this code, (not counting the
+  PCMCIA ones either) it is easy to break some card by what seems like
+  a simple innocent change. Please contact me or Donald if you think
+  you have found something that needs changing. -- PG
+
+
   Changelog:
 
   Paul Gortmaker       : remove set_bit lock, other cleanups.
   Paul Gortmaker       : add ei_get_8390_hdr() so we can pass skb's to 
                          ei_block_input() for eth_io_copy_and_sum().
+  Paul Gortmaker       : exchange static int ei_pingpong for a #define,
+                         also add better Tx error handling.
 
-  */
 
-static const char *version =
-    "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-/*
-  Braindamage remaining:
-  Much of this code should have been cleaned up, but every attempt 
-  has broken some clone part.
-  
   Sources:
   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
   */
 
-#include <linux/module.h>
+static const char *version =
+    "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -87,18+89,10 @@ int ei_debug = EI_DEBUG;
 #else
 int ei_debug = 1;
 #endif
-#ifdef EI_PINGPONG
-static int ei_pingpong = 1;
-#else
-static int ei_pingpong = 0;
-#endif
-
-/* Max number of packets received at one Intr.
-   Currently this may only be examined by a kernel debugger. */
-static int high_water_mark = 0;
 
 /* Index to functions. */
 static void ei_tx_intr(struct device *dev);
+static void ei_tx_err(struct device *dev);
 static void ei_receive(struct device *dev);
 static void ei_rx_overrun(struct device *dev);
 
@@ -141,8+135,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
 {
     int e8390_base = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
-    int length, send_length;
-    
+    int length, send_length, output_page;
+
 /*
  *  We normally shouldn't be called if dev->tbusy is set, but the
  *  existing code does anyway. If it has been too long since the
@@ -161,6+155,12 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
                        return 1;
                }
 
+               /*
+                * Note that if the Tx posted a TX_ERR interrupt, then the
+                * error will have been handled from the interrupt handler.
+                * and not here.
+                */
+
                printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
                   dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
                   (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
@@ -199,53+199,77 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
 
     send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
 
-    if (ei_local->pingpong) {
-               int output_page;
-               if (ei_local->tx1 == 0) {
-                       output_page = ei_local->tx_start_page;
-                       ei_local->tx1 = send_length;
-                       if (ei_debug  &&  ei_local->tx2 > 0)
-                               printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
-                                          dev->name, ei_local->tx2, ei_local->lasttx,
-                                          ei_local->txing);
-               } else if (ei_local->tx2 == 0) {
-                       output_page = ei_local->tx_start_page + 6;
-                       ei_local->tx2 = send_length;
-                       if (ei_debug  &&  ei_local->tx1 > 0)
-                               printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
-                                          dev->name, ei_local->tx1, ei_local->lasttx,
-                                          ei_local->txing);
-               } else {        /* We should never get here. */
-                       if (ei_debug)
-                               printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",
-                                       dev->name, dev->interrupt, ei_local->tx1, 
-                                       ei_local->tx2, ei_local->lasttx);
-                       ei_local->irqlock = 0;
-                       dev->tbusy = 1;
-                       outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-                       return 1;
-               }
-               ei_block_output(dev, length, skb->data, output_page);
-               if (! ei_local->txing) {
-                       ei_local->txing = 1;
-                       NS8390_trigger_send(dev, send_length, output_page);
-                       dev->trans_start = jiffies;
-                       if (output_page == ei_local->tx_start_page)
-                               ei_local->tx1 = -1, ei_local->lasttx = -1;
-                       else
-                               ei_local->tx2 = -1, ei_local->lasttx = -2;
-               } else
-                       ei_local->txqueue++;
-
-               dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
-    } else {  /* No pingpong, just a single Tx buffer. */
-               ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
-               ei_local->txing = 1;
-               NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
-               dev->trans_start = jiffies;
-               dev->tbusy = 1;
+#ifdef EI_PINGPONG
+
+    /*
+     * We have two Tx slots available for use. Find the first free
+     * slot, and then perform some sanity checks. With two Tx bufs,
+     * you get very close to transmitting back-to-back packets. With
+     * only one Tx buf, the transmitter sits idle while you reload the
+     * card, leaving a substantial gap between each transmitted packet.
+     */
+
+    if (ei_local->tx1 == 0) {
+       output_page = ei_local->tx_start_page;
+       ei_local->tx1 = send_length;
+       if (ei_debug  &&  ei_local->tx2 > 0)
+               printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+                       dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+    } else if (ei_local->tx2 == 0) {
+       output_page = ei_local->tx_start_page + TX_1X_PAGES;
+       ei_local->tx2 = send_length;
+       if (ei_debug  &&  ei_local->tx1 > 0)
+               printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+                       dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+    } else {   /* We should never get here. */
+       if (ei_debug)
+               printk("%s: No Tx buffers free! irq=%d tx1=%d tx2=%d last=%d\n",
+                       dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+       ei_local->irqlock = 0;
+       dev->tbusy = 1;
+       outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+       return 1;
     }
-    
+
+    /*
+     * Okay, now upload the packet and trigger a send if the transmitter
+     * isn't already sending. If it is busy, the interrupt handler will
+     * trigger the send later, upon receiving a Tx done interrupt.
+     */
+
+    ei_block_output(dev, length, skb->data, output_page);
+    if (! ei_local->txing) {
+       ei_local->txing = 1;
+       NS8390_trigger_send(dev, send_length, output_page);
+       dev->trans_start = jiffies;
+       if (output_page == ei_local->tx_start_page) {
+               ei_local->tx1 = -1;
+               ei_local->lasttx = -1;
+       } else {
+               ei_local->tx2 = -1;
+               ei_local->lasttx = -2;
+       }
+    } else
+       ei_local->txqueue++;
+
+    dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
+
+#else  /* EI_PINGPONG */
+
+    /*
+     * Only one Tx buffer in use. You need two Tx bufs to come close to
+     * back-to-back transmits. Expect a 20 -> 25% performance hit on
+     * reasonable hardware if you only use one Tx buffer.
+     */
+
+    ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+    ei_local->txing = 1;
+    NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+    dev->trans_start = jiffies;
+    dev->tbusy = 1;
+
+#endif /* EI_PINGPONG */
+
     /* Turn 8390 interrupts back on. */
     ei_local->irqlock = 0;
     outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -305,18+329,17 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                /* Push the next to-transmit packet through. */
                if (interrupts & ENISR_TX) {
                        ei_tx_intr(dev);
-               } else if (interrupts & ENISR_COUNTERS) {
+               } else if (interrupts & ENISR_TX_ERR) {
+                       ei_tx_err(dev);
+               }
+
+               if (interrupts & ENISR_COUNTERS) {
                        ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
                        ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
                        ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
                        outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
                }
                
-               /* Ignore the transmit errs and reset intr for now. */
-               if (interrupts & ENISR_TX_ERR) {
-                       outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
-               }
-
                /* Ignore any RDC interrupts that make it back to here. */
                if (interrupts & ENISR_RDC) {
                        outb_p(ENISR_RDC, e8390_base + EN0_ISR);
@@ -340,6+363,43 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
     return;
 }
 
+/*
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ */
+
+static void ei_tx_err(struct device *dev)
+{
+    int e8390_base = dev->base_addr;
+    unsigned char txsr = inb_p(e8390_base+EN0_TSR);
+    unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+    printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+    if (txsr & ENTSR_ABT)
+               printk("excess-collisions ");
+    if (txsr & ENTSR_ND)
+               printk("non-deferral ");
+    if (txsr & ENTSR_CRS)
+               printk("lost-carrier ");
+    if (txsr & ENTSR_FU)
+               printk("FIFO-underrun ");
+    if (txsr & ENTSR_CDH)
+               printk("lost-heartbeat ");
+    printk("\n");
+#endif
+
+    outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+    if (tx_was_aborted)
+               ei_tx_intr(dev);
+
+}
+
 /* We have finished a transmit: check for errors and then trigger the next
    packet to be sent. */
 static void ei_tx_intr(struct device *dev)
@@ -349,58+409,68 @@ static void ei_tx_intr(struct device *dev)
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
     
     outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
-    
-    if (ei_local->pingpong) {
-               ei_local->txqueue--;
-               if (ei_local->tx1 < 0) {
-                       if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
-                               printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
-                                          ei_local->name, ei_local->lasttx, ei_local->tx1);
-                       ei_local->tx1 = 0;
-                       dev->tbusy = 0;
-                       if (ei_local->tx2 > 0) {
-                               ei_local->txing = 1;
-                               NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
-                               dev->trans_start = jiffies;
-                               ei_local->tx2 = -1,
-                               ei_local->lasttx = 2;
-                       } else
-                               ei_local->lasttx = 20, ei_local->txing = 0;
-               } else if (ei_local->tx2 < 0) {
-                       if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
-                               printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
-                                          ei_local->name, ei_local->lasttx, ei_local->tx2);
-                       ei_local->tx2 = 0;
-                       dev->tbusy = 0;
-                       if (ei_local->tx1 > 0) {
-                               ei_local->txing = 1;
-                               NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
-                               dev->trans_start = jiffies;
-                               ei_local->tx1 = -1;
-                               ei_local->lasttx = 1;
-                       } else
-                               ei_local->lasttx = 10, ei_local->txing = 0;
-               } else
-                       printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
-                                  dev->name, ei_local->lasttx);
-    } else {
-               ei_local->txing = 0;
-               dev->tbusy = 0;
-    }
+
+#ifdef EI_PINGPONG
+
+    /*
+     * There are two Tx buffers, see which one finished, and trigger
+     * the send of another one if it exists.
+     */
+    ei_local->txqueue--;
+    if (ei_local->tx1 < 0) {
+       if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+               printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
+                          ei_local->name, ei_local->lasttx, ei_local->tx1);
+       ei_local->tx1 = 0;
+       dev->tbusy = 0;
+       if (ei_local->tx2 > 0) {
+               ei_local->txing = 1;
+               NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+               dev->trans_start = jiffies;
+               ei_local->tx2 = -1,
+               ei_local->lasttx = 2;
+       } else
+               ei_local->lasttx = 20, ei_local->txing = 0;
+    } else if (ei_local->tx2 < 0) {
+       if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
+               printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+                          ei_local->name, ei_local->lasttx, ei_local->tx2);
+       ei_local->tx2 = 0;
+       dev->tbusy = 0;
+       if (ei_local->tx1 > 0) {
+               ei_local->txing = 1;
+               NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+               dev->trans_start = jiffies;
+               ei_local->tx1 = -1;
+               ei_local->lasttx = 1;
+       } else
+               ei_local->lasttx = 10, ei_local->txing = 0;
+    } else
+       printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
+                  dev->name, ei_local->lasttx);
+
+#else  /* EI_PINGPONG */
+    /*
+     *  Single Tx buffer: mark it free so another packet can be loaded.
+     */
+    ei_local->txing = 0;
+    dev->tbusy = 0;
+#endif
 
     /* Minimize Tx latency: update the statistics after we restart TXing. */
-       if (status & ENTSR_COL) ei_local->stat.collisions++;
+    if (status & ENTSR_COL)
+       ei_local->stat.collisions++;
     if (status & ENTSR_PTX)
-               ei_local->stat.tx_packets++;
+       ei_local->stat.tx_packets++;
     else {
-               ei_local->stat.tx_errors++;
-               if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
-               if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
-               if (status & ENTSR_FU)  ei_local->stat.tx_fifo_errors++;
-               if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
-               if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
-       }
-    
+       ei_local->stat.tx_errors++;
+       if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
+       if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+       if (status & ENTSR_FU)  ei_local->stat.tx_fifo_errors++;
+       if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
+       if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+    }
+
     mark_bh (NET_BH);
 }
 
@@ -410,7+480,8 @@ static void ei_receive(struct device *dev)
 {
     int e8390_base = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
-    int rxing_page, this_frame, next_frame, current_offset;
+    unsigned char rxing_page, this_frame, next_frame;
+    unsigned short current_offset;
     int rx_pkt_count = 0;
     struct e8390_pkt_hdr rx_frame;
     int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
@@ -502,13+573,6 @@ static void ei_receive(struct device *dev)
                ei_local->current_page = next_frame;
                outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
     }
-    /* If any worth-while packets have been received, netif_rx()
-       has done a mark_bh(NET_BH) for us and will work on them
-       when we get to the bottom-half routine. */
-
-       /* Record the maximum Rx packet queue. */
-       if (rx_pkt_count > high_water_mark)
-               high_water_mark = rx_pkt_count;
 
     /* We used to also ack ENISR_OVER here, but that would sometimes mask
     a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
@@ -607,7+671,6 @@ int ethdev_init(struct device *dev)
                        return -ENOMEM;
                memset(dev->priv, 0, sizeof(struct ei_device));
                ei_local = (struct ei_device *)dev->priv;
-               ei_local->pingpong = ei_pingpong;
     }
     
     dev->hard_start_xmit = &ei_start_xmit;
index 56716e7..9cc0ddc 100644 (file)
 
 #define TX_2X_PAGES 12
 #define TX_1X_PAGES 6
-#define TX_PAGES (ei_status.pingpong ? TX_2X_PAGES : TX_1X_PAGES)
+
+/* Should always use two Tx slots to get back-to-back transmits. */
+#define EI_PINGPONG
+
+#ifdef EI_PINGPONG
+#define TX_PAGES TX_2X_PAGES
+#else
+#define TX_PAGES TX_1X_PAGES
+#endif
 
 #define ETHER_ADDR_LEN 6
 
@@ -56,7+64,6 @@ struct ei_device {
   unsigned txing:1;            /* Transmit Active */
   unsigned irqlock:1;          /* 8390's intrs disabled when '1'. */
   unsigned dmaing:1;           /* Remote DMA Active */
-  unsigned pingpong:1;         /* Using the ping-pong driver */
   unsigned char tx_start_page, rx_start_page, stop_page;
   unsigned char current_page;  /* Read pointer in buffer  */
   unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
index bd81722..7967de6 100644 (file)
@@ -466,6+466,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_HYDRA),y)
+L_OBJS += hydra.o
+else
+  ifeq ($(CONFIG_HYDRA),m)
+  M_OBJS += hydra.o
+  endif
+endif
+
 ifeq ($(CONFIG_SDLA),y)
 L_OBJS += sdla.o
 else
index 6e49219..08cded5 100644 (file)
   my testing so far, the Livingston PortMaster 2e's load-balancing is a
   good 1 to 2 KB/s slower than the test machine working with a 28.8 Kbps
   and 14.4 Kbps connection.  However, I am not sure that it really is
-  the PortMaster, or if its Linux's TCP drivers. I'm told that Linux's
+  the PortMaster, or if it's Linux's TCP drivers. I'm told that Linux's
   TCP implementation is pretty fast though.--)
 
 
index 4550227..407635b 100644 (file)
@@ -6,7+6,7 @@ Protocol Tunneling:
        A network tunneling driver encapsulates packets of one 
 protocol type within packets of another protocol type.  It sends
 them out over the network to a relay (or destination) where the
-packet is unwrapped and is forwarded to it's ultimate destination.
+packet is unwrapped and is forwarded to its ultimate destination.
 Packet tunneling is useful in situations where you want to route
 packets of a non-standard protocol type over the common network.
 A good example of this is 'IPX encapsulation', in which IPX packets
@@ -41,7+41,7 @@ only support IP encapsulated in IP.
 based on the Linux loopback driver written (in part) by Ross Biro,
 Fred N. van Kempen, and Donald Becker.  After the driver is 
 loaded, it can be set up as any other network interface, using 
-ifconfig.  The tunnel device is given it's own IP address, which
+ifconfig.  The tunnel device is given its own IP address, which
 can match that of the machine, and also is given a pointopoint
 address.  This pointopoint address is the address of the machine
 providing the decapsulating endpoint for the IP tunnel.  After
@@ -54,7+54,7 @@ network traffic from leaving the local endpoint.
        The decapsulating endpoint must have loaded the ipip.o
 decapsulator module for it to understand IP-in-IP encapsulation.
 This module takes any IP-in-IP packet that is destined for the local
-machine, unwraps it, and sends it on it's way, using standard 
+machine, unwraps it, and sends it on its way, using standard 
 routing rules.  The current implementation of IP decapsulation does
 no checking on the packet, other than making sure wrapper is bound
 for the local machine.
@@ -106,11+106,11 @@ tunnel interface is wrapped and sent to the pointopoint address
 and every incoming IP-in-IP packet bound for the local machine is
 unwrapped and re-routed normally.
 The only difference in the two machines setup shown above is that 
-machine A set it's tunnel address to one existing on machine B's
+machine A set its tunnel address to one existing on machine B's
 network, while B set a route to machine A's tunnel device address
 through the tunnel.  This is because machine A wants to have a new
 address on network B, and machine B is simply acting as a proxy 
-for machine A.  Machine A needs it's tunnel address to be on network 
+for machine A.  Machine A needs its tunnel address to be on network 
 B so that when packets from machine B are unwrapped, the Linux 
 routing system knows that the address is a local one.  Due to a 
 feature of Linux, any packets received locally, bound for another
index c6c146e..edcb431 100644 (file)
@@ -77,6+77,7 @@ 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 *);
+extern int hydra_probe(struct device *);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -203,6+204,9 @@ ethif_probe(struct device *dev)
 #ifdef CONFIG_ARIADNE          /* Village Tronic Ariadne Ethernet Board */
        && ariadne_probe(dev)
 #endif
+#ifdef CONFIG_HYDRA            /* Hydra Systems Amiganet Ethernet board */
+       && hydra_probe(dev)
+#endif
 #ifdef CONFIG_SUNLANCE
        && sparc_lance_probe(dev)
 #endif
index 0c2a69e..ad2d8fa 100644 (file)
@@ -2678,7+2678,7 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
        }
 
        /*
-        * Try and get ARP to resolve the header.
+        * Try to get ARP to resolve the header.
         */
 #ifdef CONFIG_INET      
        BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
@@ -3132,7+3132,7 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
        }
 
        /*
-        * Try and get ARP to resolve the header.
+        * Try to get ARP to resolve the header.
         */
 #ifdef CONFIG_INET      
        return arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
index 96be192..a2d93ea 100644 (file)
@@ -193,7+193,7 @@ check_board_dma(struct device *dev)
        ulong   x;
 
        /*
-        *      If Space.c says not to use DMA, or if its not a PLX based
+        *      If Space.c says not to use DMA, or if it's not a PLX based
         *      PCI board, or if the expansion ROM space is not PCI
         *      configured, then return false.
         */
@@ -250,10+250,10 @@ check_board_dma(struct device *dev)
  *     Initiate DMA using PLX part on PCI board.  Spin the
  *     processor until completed.  All addresses are physical!
  *
- *     If pciaddr is NULL, then its a chaining DMA, and lcladdr is
+ *     If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
  *     the address of the first DMA descriptor in the chain.
  *
- *     If pciaddr is not NULL, then its a single DMA.
+ *     If pciaddr is not NULL, then it's a single DMA.
  *
  *     In either case, "lcladdr" must have been fixed up to make
  *     sure the MSB isn't set using the S2DMA macro before passing
@@ -373,13+373,13 @@ again:
        /*
         *      There are three modes here for doing the packet copy.
         *      If we have DMA, and the packet is "long", we use the
-        *      chaining mode of DMA.  If its shorter, we use single
+        *      chaining mode of DMA.  If it's shorter, we use single
         *      DMA's.  Otherwise, we use memcpy().
         */
        if (priv->use_dma && priv->dmadesc_h && len > 64)
        {
                /*
-                *      If we can use DMA and its a long frame, copy it using
+                *      If we can use DMA and it's a long frame, copy it using
                 *      DMA chaining.
                 */
                DMACHAIN        *ddp_h; /* Host virtual DMA desc. pointer */
@@ -451,7+451,7 @@ again:
        else if (priv->use_dma)
        {
                /*
-                *      If we can use DMA and its a shorter frame, copy it
+                *      If we can use DMA and it's a shorter frame, copy it
                 *      using single DMA transfers.
                 */
                uchar           *phys_p;
index 96be192..a2d93ea 100644 (file)
@@ -193,7+193,7 @@ check_board_dma(struct device *dev)
        ulong   x;
 
        /*
-        *      If Space.c says not to use DMA, or if its not a PLX based
+        *      If Space.c says not to use DMA, or if it's not a PLX based
         *      PCI board, or if the expansion ROM space is not PCI
         *      configured, then return false.
         */
@@ -250,10+250,10 @@ check_board_dma(struct device *dev)
  *     Initiate DMA using PLX part on PCI board.  Spin the
  *     processor until completed.  All addresses are physical!
  *
- *     If pciaddr is NULL, then its a chaining DMA, and lcladdr is
+ *     If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
  *     the address of the first DMA descriptor in the chain.
  *
- *     If pciaddr is not NULL, then its a single DMA.
+ *     If pciaddr is not NULL, then it's a single DMA.
  *
  *     In either case, "lcladdr" must have been fixed up to make
  *     sure the MSB isn't set using the S2DMA macro before passing
@@ -373,13+373,13 @@ again:
        /*
         *      There are three modes here for doing the packet copy.
         *      If we have DMA, and the packet is "long", we use the
-        *      chaining mode of DMA.  If its shorter, we use single
+        *      chaining mode of DMA.  If it's shorter, we use single
         *      DMA's.  Otherwise, we use memcpy().
         */
        if (priv->use_dma && priv->dmadesc_h && len > 64)
        {
                /*
-                *      If we can use DMA and its a long frame, copy it using
+                *      If we can use DMA and it's a long frame, copy it using
                 *      DMA chaining.
                 */
                DMACHAIN        *ddp_h; /* Host virtual DMA desc. pointer */
@@ -451,7+451,7 @@ again:
        else if (priv->use_dma)
        {
                /*
-                *      If we can use DMA and its a shorter frame, copy it
+                *      If we can use DMA and it's a shorter frame, copy it
                 *      using single DMA transfers.
                 */
                uchar           *phys_p;
index 2e21cdf..157dd5a 100644 (file)
@@ -286,10+286,6 @@ int dlci_add(struct dlci_add *new)
    int                 err, i;
    char                buf[10];
 
-   err = verify_area(VERIFY_READ, new, sizeof(*new));
-   if (err)
-      return(err);
-
    err = verify_area(VERIFY_WRITE, new, sizeof(*new));
    if (err)
       return(err);
index 4cc00d9..1135fbb 100644 (file)
        misguided packets.
 
                        Nick Holloway, 27th May 1994
-       [I tweaked this explanation a little but thats all]
+       [I tweaked this explanation a little but that's all]
                        Alan Cox, 30th May 1994
 */
 
index 1c2915a..ff1e11d 100644 (file)
@@ -903,7+903,7 @@ static unsigned short eexp_hw_lasttxstat(struct device *dev)
 
 /* 
  * This should never happen. It is called when some higher
- * routine detects the CU has stopped, to try and restart
+ * routine detects the CU has stopped, to try to restart
  * it from the last packet we knew we were working on,
  * or the idle loop if we had finished for the time.
  */
index b1dd14e..5c6e38d 100644 (file)
@@ -66,7+66,7 @@ static const char *version =
  * printk's trimmed out.
  *
  * Revision 3.6  1995/01/19  21:49:56  guru
- * This is working pretty well. I gained 1 K/s in speed.. now its just
+ * This is working pretty well. I gained 1 K/s in speed.. now it's just
  * robustness and printk's to be diked out.
  *
  * Revision 3.5  1995/01/18  22:29:59  guru
index 501cc5f..ee484c3 100644 (file)
@@ -400,7+400,7 @@ static int eth16i_probe1(struct device *dev, short ioaddr)
   /* 
      Now it seems that we have found a ethernet chip in this particular
      ioaddr. The MB86985 chip has this feature, that when you read a 
-     certain register it will increase it's io base address to next
+     certain register it will increase its io base address to next
      configurable slot. Now when we have found the chip, first thing is
      to make sure that the chip's ioaddr will hold still here.
   */
index 9092280..1ebca56 100644 (file)
 #define HP100_EE_EN            0x1000  /* 0:Disable,1:Enable EEPROM writing */
 #define HP100_BM_WRITE         0x0800  /* 0:Slave, 1:Bus Master for Tx data */
 #define HP100_BM_READ          0x0400  /* 0:Slave, 1:Bus Master for Rx data */
-#define HP100_TRI_INT          0x0200  /* 0:Dont, 1:Do tri-state the int */
+#define HP100_TRI_INT          0x0200  /* 0:Don't, 1:Do tri-state the int */
 #define HP100_MEM_EN           0x0040  /* Config program set this to */
                                         /*   0:Disable, 1:Enable mem map. */
                                         /*   See MMAP_DIS. */
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
new file mode 100644 (file)
index 0000000..5e3b2cd
--- /dev/null
@@ -0,0 +1,655 @@
+/* Linux/68k Hydra Amiganet board driver v2.1 BETA                          */
+/* copyleft by Topi Kanerva (topi@susanna.oulu.fi)                          */
+/* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi)          */
+
+/* The code is mostly based on the linux/68k Ariadne driver                 */
+/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */
+/* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)       */
+
+/* This file is subject to the terms and conditions of the GNU General      */
+/* Public License.  See the file README.legal in the main directory of the  */
+/* Linux/68k distribution for more details.                                 */
+
+/* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a    */
+/* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM  */
+/* and 10BASE-2 (thin coax) and AUI connectors.                             */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+
+#include "hydra.h"
+
+
+#define HYDRA_DEBUG
+#undef HAVE_MULTICAST
+
+#define HYDRA_VERSION "v2.1 BETA"
+
+struct device *init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp);
+
+#undef HYDRA_DEBUG        /* define this for (lots of) debugging information */
+
+#if 0                         /* currently hardwired to one transmit buffer */
+ #define TX_RING_SIZE  5
+ #define RX_RING_SIZE  16
+#else
+ #define TX_RING_SIZE 1
+ #define RX_RING_SIZE 8
+#endif
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+
+/*
+ *   let's define here nice macros for writing and reading NIC registers
+ *
+ * the CIA accesses here are uses to make sure the minimum time
+ * requirement between NIC chip selects is met.
+ */
+#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val)))
+#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg)))))
+
+/* mask value for the interrupts we use */
+#define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)
+
+/* only broadcasts, no promiscuous mode for now */
+#define NIC_RCRBITS (0)
+
+/*
+ *   Private Device Data
+ */
+struct hydra_private
+    {
+    u_char *hydra_base;
+    u_char *hydra_nic_base;
+    u_short tx_page_start;
+    u_short rx_page_start;
+    u_short rx_page_stop;
+    u_short next_pkt;
+    struct enet_statistics stats;
+    };
+
+static int hydra_open(struct device *dev);
+static int hydra_start_xmit(struct sk_buff *skb, struct device *dev);
+static void hydra_interrupt(int irq, struct pt_regs *fp, void *data);
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase);
+static int hydra_close(struct device *dev);
+static struct enet_statistics *hydra_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+/* this is now coherent to the C version below, */
+/* compile the source with -D__USE_ASM__ if you */
+/* want it - it'll only be some 10% faster thou */
+
+#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
+
+static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
+    {
+    __asm__("   move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t"
+           "   cmpi.l #2,%/d0 \n\t"
+           "1: bcs.s  2f \n\t"
+            "   move.w %/a0@+,%/a1@+ \n\t"
+           "   subq.l #2,%/d0 \n\t"
+           "   bra.s  1b \n\t"
+           "2: cmpi.l #1,%/d0 \n\t"
+           "   bne.s  3f \n\t"
+           "   move.w %/a0@,%/d0 \n\t"
+           "   swap.w %/d0 \n\t"
+           "   move.b %/d0,%/a1@ \n\t"
+           "3: moveq  #0,%/d0 \n\t"
+         :
+         : "g" (dest), "g" (src), "g" (len)
+         : "a1", "a0", "d0");
+    return;
+}
+
+#else
+
+/* hydra memory can only be read or written as words or longwords.  */
+/* that will mean that we'll have to write a special memcpy for it. */
+/* this one here relies on the fact that _writes_ to hydra memory   */
+/* are guaranteed to be of even length. (reads can be arbitrary)    */
+
+static void memcpyw(u_short *dest, u_short *src, int len)
+{
+  if(len & 1)
+    len++;
+
+  while (len >= 2) {
+    *(dest++) = *(src++);
+    len -= 2;
+  }
+    
+}
+
+#endif
+
+unsigned long hydra_probe(struct device *dev)
+    {
+    struct hydra_private *priv;
+    u_long board;
+    int key;
+    struct ConfigDev *cd;
+    int j;
+
+#ifdef HYDRA_DEBUG
+ printk("hydra_probe(%x)\n", dev);
+#endif
+
+    if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) {
+       cd = zorro_get_board(key);
+       if((board = (u_long) cd->cd_BoardAddr))
+           {
+           for(j = 0; j < ETHER_ADDR_LEN; j++)
+                dev->dev_addr[j] = *((u_char *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
+           
+           printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
+                  dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+                  dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+           init_etherdev(dev, 0, NULL);
+           
+           dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
+           priv = (struct hydra_private *)dev->priv;
+           memset(priv, 0, sizeof(struct hydra_private));
+           
+           priv->hydra_base = (u_char *) ZTWO_VADDR(board);
+           priv->hydra_nic_base = (u_char *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
+           
+           dev->open = &hydra_open;
+           dev->stop = &hydra_close;
+           dev->hard_start_xmit = &hydra_start_xmit;
+           dev->get_stats = &hydra_get_stats;
+#ifdef HAVE_MULTICAST
+           dev->set_multicast_list = &hydra_set_multicast_list;
+#endif
+           zorro_config_board(key, 0);
+           return(0);
+            }
+        }
+    return(ENODEV);
+    }
+
+
+static int hydra_open(struct device *dev)
+  {
+    struct hydra_private *priv = (struct hydra_private *)dev->priv;
+    static int interruptinstalled = 0;
+    u_char volatile *nicbase = priv->hydra_nic_base;
+#ifdef HAVE_MULTICAST
+    int i;
+#endif
+    
+#ifdef HYDRA_DEBUG
+ printk("hydra_open(0x%x)\n", dev);
+#endif
+
+    /* first, initialize the private structure */
+    priv->tx_page_start = 0;   /* these are 256 byte buffers for NS8390 */
+    priv->rx_page_start = 6;
+    priv->rx_page_stop  = 62;  /* these values are hard coded for now */
+
+    /* Reset the NS8390 NIC */
+    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+
+    /* be sure that the NIC is in stopped state */
+    while(!(READ_REG(NIC_ISR) & ISR_RST));
+
+    /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
+    WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+
+    /* clear remote byte count registers */
+    WRITE_REG(NIC_RBCR0, 0);
+    WRITE_REG(NIC_RBCR1, 0);
+
+    /* accept packets addressed to this card and also broadcast packets */
+    WRITE_REG(NIC_RCR, NIC_RCRBITS);
+
+    /* enable loopback mode 1 */
+    WRITE_REG(NIC_TCR, TCR_LB1);
+
+    /* initialize receive buffer ring */
+    WRITE_REG(NIC_PSTART, priv->rx_page_start);
+    WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+    WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+
+    /* clear interrupts */
+    WRITE_REG(NIC_ISR, 0xff);
+
+    /* enable interrupts */
+    WRITE_REG(NIC_IMR, NIC_INTS);
+
+    /* set the ethernet hardware address */
+    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
+
+    WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
+    WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
+    WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
+    WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
+    WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
+    WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
+
+#ifdef HAVE_MULTICAST
+    /* clear multicast hash table */
+    for(i = 0; i < 8; i++)
+      WRITE_REG(NIC_MAR0 + 2*i, 0);
+#endif
+
+    priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+    WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+
+    /* goto page 0, start NIC */
+    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+    /* take interface out of loopback */
+    WRITE_REG(NIC_TCR, 0);
+
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    dev->start = 1;
+    
+    if(!interruptinstalled) {
+      if(!add_isr(IRQ_AMIGA_PORTS, hydra_interrupt, 0, dev,
+                                 "Hydra Ethernet"))
+       return(-EAGAIN);
+      interruptinstalled = 1;
+    }
+
+    return(0);
+  }
+
+
+static int hydra_close(struct device *dev)
+{
+  struct hydra_private *priv = (struct hydra_private *)dev->priv;
+  u_char volatile *nicbase = priv->hydra_nic_base;
+  int n = 5000;
+
+  dev->start = 0;
+  dev->tbusy = 1;
+
+#ifdef HYDRA_DEBUG
+  printk("%s: Shutting down ethercard\n", dev->name);
+  printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
+#endif
+
+  WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+
+  /* wait for NIC to stop (what a nice timeout..) */
+  while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
+    
+  return(0);
+}
+
+
+static void hydra_interrupt(int irq, struct pt_regs *fp, void *data)
+    {
+    u_char volatile *nicbase;
+  
+    struct device *dev = (struct device *) data;
+    struct hydra_private *priv;
+    u_short intbits;
+
+    if(dev == NULL)
+        {
+        printk("hydra_interrupt(): irq for unknown device\n");
+        return;
+        }
+
+/* this is not likely a problem - i think */
+    if(dev->interrupt)
+        printk("%s: re-entering the interrupt handler\n", dev->name);
+
+    dev->interrupt = 1;
+
+    priv = (struct hydra_private *) dev->priv;
+    nicbase = (u_char *) priv->hydra_nic_base;
+
+    /* select page 0 */
+    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+
+    intbits = READ_REG(NIC_ISR) & NIC_INTS;
+    if(intbits == 0)
+        {
+        dev->interrupt = 0;
+        return;
+        }
+
+       /* acknowledge all interrupts, by clearing the interrupt flag */
+       WRITE_REG(NIC_ISR, intbits);
+
+       if((intbits & ISR_PTX) && !(intbits & ISR_TXE))
+           {
+           dev->tbusy = 0;
+           mark_bh(NET_BH);
+           }
+       
+       if((intbits & ISR_PRX) && !(intbits & ISR_RXE))/* packet received OK */
+             hydra_rx(dev, priv, nicbase);
+
+        if(intbits & ISR_TXE)
+           priv->stats.tx_errors++;
+
+        if(intbits & ISR_RXE)
+           priv->stats.rx_errors++;
+
+       if(intbits & ISR_CNT) {
+         /*
+          * read the tally counters and (currently) ignore the values
+          * might be useful because of bugs of some versions of the 8390 NIC
+          */
+#ifdef HYDRA_DEBUG
+         printk("hydra_interrupt(): ISR_CNT\n");
+#endif
+         (void)READ_REG(NIC_CNTR0);
+         (void)READ_REG(NIC_CNTR1);
+         (void)READ_REG(NIC_CNTR2);
+       }
+       
+       if(intbits & ISR_OVW)
+           {
+            #ifdef HYDRA_DEBUG
+           WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+/* another one just too much for me to comprehend - basically this could  */
+/* only occur because of invalid access to hydra ram, thus invalidating  */
+/* the interrupt bits read - in average usage these do not occur at all */
+           printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
+                intbits, READ_REG(NIC_CURR));
+           WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+            #endif
+           
+
+           /* overwrite warning occured, stop NIC & check the BOUNDARY pointer */
+           /* FIXME - real overwrite handling needed !! */
+
+           printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
+           WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+           while(!(READ_REG(NIC_ISR) & ISR_RST));
+           /* wait for NIC to reset */
+           WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+           WRITE_REG(NIC_RBCR0, 0);
+           WRITE_REG(NIC_RBCR1, 0);
+           WRITE_REG(NIC_RCR, NIC_RCRBITS);
+           WRITE_REG(NIC_TCR, TCR_LB1);
+           WRITE_REG(NIC_PSTART, priv->rx_page_start);
+           WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+           WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+           WRITE_REG(NIC_ISR, 0xff);
+           WRITE_REG(NIC_IMR, NIC_INTS);
+/* currently this _won't_ reset my hydra, even though it is */
+/* basically the same code as in the board init - any ideas? */
+
+           priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+           WRITE_REG(NIC_CURR, priv->next_pkt);    /* set the next buf for current */
+           
+           WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+           
+           WRITE_REG(NIC_TCR, 0);
+           }
+
+    dev->interrupt = 0;
+    return;
+    }
+
+
+/*
+ * packet transmit routine
+ */
+static int hydra_start_xmit(struct sk_buff *skb, struct device *dev)
+    {
+    struct hydra_private *priv = (struct hydra_private *)dev->priv;
+    u_char volatile *nicbase = priv->hydra_nic_base;
+    int len, len1;
+
+       /* Transmitter timeout, serious problems. */
+
+    if(dev->tbusy)
+       {
+        int tickssofar = jiffies - dev->trans_start;
+       if(tickssofar < 20)
+           return(1);
+       WRITE_REG(NIC_CR, CR_STOP);
+       printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
+       priv->stats.tx_errors++;
+
+
+       dev->tbusy = 0;
+       dev->trans_start = jiffies;
+
+       return(0);
+       }
+
+
+    if(skb == NULL)
+        {
+       dev_tint(dev);
+       return(0);
+       }
+
+    if((len = skb->len) <= 0)
+       return(0);
+
+    /* fill in a tx ring entry */
+    
+#ifdef HYDRA_DEBUG
+ printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+       {
+               int i;
+               u_char *ptr = &((u_char *)skb->data)[6];
+               for (i = 0; i < 6; i++)
+                       printk("%02x", ptr[i]);
+       }
+       printk(" to ");
+       {
+               int i;
+               u_char *ptr = (u_char *)skb->data;
+               for (i = 0; i < 6; i++)
+                       printk("%02x", ptr[i]);
+       }
+       printk(" data 0x%08x len %d\n", (int)skb->data, len);
+#endif
+
+    /*
+     * make sure that the packet size is at least the minimum
+     * allowed ethernet packet length.
+     * (possibly should also clear the unused space...)
+     * note: minimum packet length is 64, including CRC
+     */
+    len1 = len;
+    if(len < (ETHER_MIN_LEN-4))
+       len = (ETHER_MIN_LEN-1);
+
+    /* make sure we've got an even number of bytes to copy to hydra's mem */
+    if(len & 1) len++;
+
+    if((u_long)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
+      printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = %0x\n", (priv->hydra_base+(priv->tx_page_start<<8)));
+
+    /* copy the packet data to the transmit buffer
+       in the ethernet card RAM */
+    memcpyw((u_short *)(priv->hydra_base + (priv->tx_page_start << 8)),
+           (u_short *)skb->data, len);
+    /* clear the unused space */
+/*    for(; len1<len; len1++)
+      (u_short)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
+*/
+    dev_kfree_skb(skb, FREE_WRITE);
+
+    priv->stats.tx_packets++;
+
+    cli();
+    /* make sure we are on the correct page */
+    WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+    /* here we configure the transmit page start register etc */
+    /* notice that this code is hardwired to one transmit buffer */
+    WRITE_REG(NIC_TPSR, priv->tx_page_start);
+    WRITE_REG(NIC_TBCR0, len & 0xff);
+    WRITE_REG(NIC_TBCR1, len >> 8);
+
+    /* commit the packet to the wire */
+    WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
+    sti();
+
+    dev->trans_start = jiffies;
+
+    return(0);
+    }
+
+
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase)
+    {
+    u_short volatile *board_ram_ptr;
+    struct sk_buff *skb;
+    int hdr_next_pkt, pkt_len, len1, boundary;
+
+
+    /* remove packet(s) from the ring and commit them to TCP layer */
+    WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
+    while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
+      {
+       board_ram_ptr = (u_short *)(priv->hydra_base + (priv->next_pkt << 8));
+       
+#ifdef HYDRA_DEBUG
+       printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
+#endif
+       
+       /* the following must be done with two steps, or
+          GCC optimizes it to a byte access to Hydra memory,
+          which doesn't work... */
+       hdr_next_pkt = board_ram_ptr[0];
+       hdr_next_pkt >>= 8;
+       
+       pkt_len = board_ram_ptr[1];
+       pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
+       
+#ifdef HYDRA_DEBUG
+       printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
+#endif
+       
+       if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
+         {
+           /* note that board_ram_ptr is u_short */
+           /* CRC is not included in the packet length */
+           
+           pkt_len -= 4;
+           skb = dev_alloc_skb(pkt_len+2);
+           if(skb == NULL)
+             {
+               printk("%s: memory squeeze, dropping packet.\n", dev->name);
+               priv->stats.rx_dropped++;
+             }
+           else
+             {
+               skb->dev = dev;
+               skb_reserve(skb, 2);
+               
+               if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
+                 {
+                   /* here, the packet is wrapped */
+                   len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
+                   
+                   memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1);
+                   memcpyw((u_short *)skb_put(skb, pkt_len-len1),  (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
+                   
+#ifdef HYDRA_DEBUG
+                   printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
+#endif
+                 }  /* ... here, packet is not wrapped */
+               else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len);
+             }
+           /* if(skb == NULL) ... */
+         }
+       else
+         {
+           WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+           printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
+/*
+this is the error i kept getting until i switched to 0.9.10. it still doesn't
+mean that the bug would have gone away - so be alarmed. the packet is likely
+being fetched from a wrong memory location - but why - dunno
+   
+note-for-v2.1: not really problem anymore. hasn't been for a long time.
+*/
+           
+           WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+           /* should probably reset the NIC here ?? */
+           
+           hydra_open(dev);  /* FIXME - i shouldn't really be doing this. */
+           return;
+         }
+       
+       /* now, update the next_pkt pointer */
+       if(hdr_next_pkt < priv->rx_page_stop) priv->next_pkt = hdr_next_pkt;
+       else printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
+       
+       /* update the boundary pointer */
+       boundary = priv->next_pkt - 1;
+       if(boundary < priv->rx_page_start)
+         boundary = priv->rx_page_stop - 1;
+       
+       /* set NIC to page 0 to update the NIC_BNDRY register */
+       WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+       WRITE_REG(NIC_BNDRY, boundary);
+       
+       /* select page1 to access the NIC_CURR register */
+       WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+       
+       
+       skb->protocol = eth_type_trans(skb, dev);
+       netif_rx(skb);
+       priv->stats.rx_packets++;
+       
+      }
+    return;
+    }
+    
+
+static struct enet_statistics *hydra_get_stats(struct device *dev)
+{
+       struct hydra_private *priv = (struct hydra_private *)dev->priv;
+#if 0
+       u_char *board = priv->hydra_base; 
+
+       short saved_addr;
+#endif
+/* currently does nothing :) i'll finish this later */
+
+       return(&priv->stats);
+}
+
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+    {
+    struct hydra_private *priv = (struct hydra_private *)dev->priv;
+    u_char *board = priv->hydra_base;
+
+    /* yes, this code is also waiting for someone to complete.. :) */
+    /* (personally i don't care about multicasts at all :) */
+    return;
+    }
+#endif
+
diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h
new file mode 100644 (file)
index 0000000..0a0919e
--- /dev/null
@@ -0,0 +1,177 @@
+/*     $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $     */
+
+/*
+ * Copyright (c) 1994 Timo Rossi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by  Timo Rossi
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The Hydra Systems card uses the National Semiconductor
+ * 8390 NIC (Network Interface Controller) chip, located
+ * at card base address + 0xffe1. NIC registers are accessible
+ * only at odd byte addresses, so the register offsets must
+ * be multiplied by two.
+ *
+ * Card address PROM is located at card base + 0xffc0 (even byte addresses)
+ *
+ * RAM starts at the card base address, and is 16K or 64K.
+ * The current Amiga NetBSD hydra driver is hardwired for 16K.
+ * It seems that the RAM should be accessed as words or longwords only.
+ *
+ */
+
+/* adapted for Linux by Topi Kanerva 03/29/95
+   with original author's permission          */
+
+#define HYDRA_NIC_BASE 0xffe1
+
+/* Page0 registers */
+
+#define NIC_CR     0       /* Command register   */
+#define NIC_PSTART (1*2)   /* Page start (write) */
+#define NIC_PSTOP  (2*2)   /* Page stop (write)  */
+#define NIC_BNDRY  (3*2)   /* Boundary pointer   */
+#define NIC_TSR    (4*2)   /* Transmit status (read) */
+#define NIC_TPSR   (4*2)   /* Transmit page start (write) */
+#define NIC_NCR    (5*2)   /* Number of collisions, read  */
+#define NIC_TBCR0  (5*2)   /* Transmit byte count low (write)  */
+#define NIC_FIFO   (6*2)   /* FIFO reg. (read)   */
+#define NIC_TBCR1  (6*2)   /* Transmit byte count high (write) */
+#define NIC_ISR    (7*2)   /* Interrupt status register */
+#define NIC_RBCR0  (0xa*2) /* Remote byte count low (write)  */
+#define NIC_RBCR1  (0xb*2) /* Remote byte count high (write) */
+#define NIC_RSR    (0xc*2) /* Receive status (read)  */
+#define NIC_RCR    (0xc*2) /* Receive config (write) */
+#define NIC_CNTR0  (0xd*2) /* Frame alignment error count (read) */
+#define NIC_TCR    (0xd*2) /* Transmit config (write)  */
+#define NIC_CNTR1  (0xe*2) /* CRC error counter (read) */
+#define NIC_DCR    (0xe*2) /* Data config (write) */
+#define NIC_CNTR2  (0xf*2) /* missed packet counter (read) */
+#define NIC_IMR    (0xf*2) /* Interrupt mask reg. (write)  */
+
+/* Page1 registers */
+
+#define NIC_PAR0   (1*2)   /* Physical address */
+#define NIC_PAR1   (2*2)
+#define NIC_PAR2   (3*2)
+#define NIC_PAR3   (4*2)
+#define NIC_PAR4   (5*2)
+#define NIC_PAR5   (6*2)
+#define NIC_CURR   (7*2)   /* Current RX ring-buffer page */
+#define NIC_MAR0   (8*2)   /* Multicast address */
+#define NIC_MAR1   (9*2)
+#define NIC_MAR2   (0xa*2)
+#define NIC_MAR3   (0xb*2)
+#define NIC_MAR4   (0xc*2)
+#define NIC_MAR5   (0xd*2)
+#define NIC_MAR6   (0xe*2)
+#define NIC_MAR7   (0xf*2)
+
+/* Command register definitions */
+
+#define CR_STOP   0x01 /* Stop -- software reset command */
+#define CR_START  0x02 /* Start */
+#define CR_TXP   0x04 /* Transmit packet */
+
+#define CR_RD0    0x08 /* Remote DMA cmd */
+#define CR_RD1    0x10
+#define CR_RD2    0x20
+
+#define CR_NODMA  CR_RD2
+
+#define CR_PS0    0x40 /* Page select */
+#define CR_PS1    0x80
+
+#define CR_PAGE0  0
+#define CR_PAGE1  CR_PS0
+#define CR_PAGE2  CR_PS1
+
+/* Interrupt status reg. definitions */
+
+#define ISR_PRX   0x01 /* Packet received without errors */
+#define ISR_PTX   0x02 /* Packet transmitted without errors */
+#define ISR_RXE   0x04 /* Receive error  */
+#define ISR_TXE   0x08 /* Transmit error */
+#define ISR_OVW   0x10 /* Ring buffer overrrun */
+#define ISR_CNT   0x20 /* Counter overflow    */
+#define ISR_RDC   0x40 /* Remote DMA compile */
+#define ISR_RST   0x80 /* Reset status      */
+
+/* Data config reg. definitions */
+
+#define DCR_WTS   0x01 /* Word transfer select  */
+#define DCR_BOS   0x02 /* Byte order select     */
+#define DCR_LAS   0x04 /* Long address select   */
+#define DCR_LS    0x08 /* Loopback select       */
+#define DCR_AR    0x10 /* Auto-init remote      */
+#define DCR_FT0   0x20 /* FIFO threshold select */
+#define DCR_FT1   0x40
+
+/* Transmit config reg. definitions */
+
+#define TCR_CRC  0x01 /* Inhibit CRC */
+#define TCR_LB0  0x02 /* Loopback control */
+#define TCR_LB1  0x04
+#define TCR_ATD  0x08 /* Auto transmit disable */
+#define TCR_OFST 0x10 /* Collision offset enable */
+
+/* Transmit status reg. definitions */
+
+#define TSR_PTX  0x01 /* Packet transmitted */
+#define TSR_COL  0x04 /* Transmit collided */
+#define TSR_ABT  0x08 /* Transmit aborted */
+#define TSR_CRS  0x10 /* Carrier sense lost */
+#define TSR_FU   0x20 /* FIFO underrun */
+#define TSR_CDH  0x40 /* CD Heartbeat */
+#define TSR_OWC  0x80 /* Out of Window Collision */
+
+/* Receiver config register definitions */
+
+#define RCR_SEP  0x01 /* Save errored packets */
+#define RCR_AR   0x02 /* Accept runt packets */
+#define RCR_AB   0x04 /* Accept broadcast */
+#define RCR_AM   0x08 /* Accept multicast */
+#define RCR_PRO  0x10 /* Promiscuous mode */
+#define RCR_MON  0x20 /* Monitor mode */
+
+/* Receiver status register definitions */
+
+#define RSR_PRX  0x01 /* Packet received without error */
+#define RSR_CRC  0x02 /* CRC error */
+#define RSR_FAE  0x04 /* Frame alignment error */
+#define RSR_FO   0x08 /* FIFO overrun */
+#define RSR_MPA  0x10 /* Missed packet */
+#define RSR_PHY  0x20 /* Physical address */
+#define RSR_DIS  0x40 /* Received disabled */
+#define RSR_DFR  0x80 /* Deferring (jabber) */
+
+/* Hydra System card address PROM offset */
+
+#define HYDRA_ADDRPROM 0xffc0
+
+
index 5100d8c..df0a857 100644 (file)
@@ -333,7+333,7 @@ int tok_probe(struct device *dev)
        ti->mmio= t_mmio;
 
        dev->priv = ti;     /* this seems like the logical use of the
-                         field ... lets try some empirical tests
+                         field ... let's try some empirical tests
                          using the token-info structure -- that
                          should fit with out future hope of multiple
                          adapter support as well /dwm   */
index da8418a..953f5ea 100644 (file)
  *     This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "lance32.c:v0.02 17.3.96 tsbogend@bigbug.franken.de\n";
+static const char *version = "lance32.c:v0.10 28.4.96 tsbogend@bigbug.franken.de\n";
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -55,6+55,11 @@ int lance32_debug = 1;
  *         only tested on Alpha Noname Board
  * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
  *         tested on a ASUS SP3G
+ * v0.10:  fixed a odd problem with the 79C794 in a Compaq Deskpro XL
+ *         looks like the 974 doesn't like stopping and restarting in a
+ *         short period of time; now we do a reinit of the lance; the
+ *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ *         and hangs the machine (thanks to Klaus Liedl for debugging)
  */
 
 
@@ -320,7+325,11 @@ lance32_open(struct device *dev)
                           (u32) virt_to_bus(lp->rx_ring),
                           (u32) virt_to_bus(&lp->init_block));
 
+       lp->init_block.mode = 0x0000;
+       lp->init_block.filter[0] = 0x00000000;
+       lp->init_block.filter[1] = 0x00000000;
        lance32_init_ring(dev);
+    
        /* Re-initialize the LANCE, and start it when done. */
        outw(0x0001, ioaddr+LANCE_ADDR);
        outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
@@ -404,12+413,9 @@ lance32_init_ring(struct device *dev)
                lp->tx_ring[i].status = 0;
        }
 
-       lp->init_block.mode = 0x0000;
         lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
        for (i = 0; i < 6; i++)
                lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.filter[0] = 0x00000000;
-       lp->init_block.filter[1] = 0x00000000;
        lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
        lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
 }
@@ -417,11+423,21 @@ lance32_init_ring(struct device *dev)
 static void
 lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
 {
+        int i;
+       int ioaddr = dev->base_addr;
+    
        lance32_purge_tx_ring(dev);
        lance32_init_ring(dev);
     
-       outw(0x0000,    dev->base_addr + LANCE_ADDR);
-       outw(csr0_bits, dev->base_addr + LANCE_DATA);
+       outw(0x0000, ioaddr + LANCE_ADDR);
+        /* ReInit Ring */
+        outw(0x0001, ioaddr + LANCE_DATA);
+       i = 0;
+       while (i++ < 100)
+               if (inw(ioaddr+LANCE_DATA) & 0x0100)
+                       break;
+
+       outw(csr0_bits, ioaddr + LANCE_DATA);
 }
 
 static int
@@ -459,7+475,7 @@ lance32_start_xmit(struct sk_buff *skb, struct device *dev)
                        printk("\n");
                }
 #endif
-               lance32_restart(dev, 0x0043, 1);
+               lance32_restart(dev, 0x0042, 1);
 
                dev->tbusy=0;
                dev->trans_start = jiffies;
@@ -794,32+810,25 @@ lance32_get_stats(struct device *dev)
 static void lance32_set_multicast_list(struct device *dev)
 {
        short ioaddr = dev->base_addr;
-
-       outw(0, ioaddr+LANCE_ADDR);
-       outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.  */
+       struct lance32_private *lp = (struct lance32_private *)dev->priv;    
 
        if (dev->flags&IFF_PROMISC) {
                /* Log any net taps. */
                printk("%s: Promiscuous mode enabled.\n", dev->name);
-               outw(15, ioaddr+LANCE_ADDR);
-               outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
+               lp->init_block.mode = 0x8000;
        } else {
-               short multicast_table[4];
-               int i;
                int num_addrs=dev->mc_count;
                if(dev->flags&IFF_ALLMULTI)
                        num_addrs=1;
                /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
-               memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
-               for (i = 0; i < 4; i++) {
-                       outw(8 + i, ioaddr+LANCE_ADDR);
-                       outw(multicast_table[i], ioaddr+LANCE_DATA);
-               }
-               outw(15, ioaddr+LANCE_ADDR);
-               outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
+               memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
+               lp->init_block.mode = 0x0000;           
        }
+    
+       outw(0, ioaddr+LANCE_ADDR);
+       outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.  */
 
-       lance32_restart(dev, 0x0142, 0); /*  Resume normal operation */
+       lance32_restart(dev, 0x0042, 0); /*  Resume normal operation */
 
 }
 
index b709ff4..74181b5 100644 (file)
  *             Alan Cox        :       Rejig for NET3.029 snap #3
  *             Alan Cox        :       Fixed NET3.029 bugs and sped up
  *             Larry McVoy     :       Tiny tweak to double performance
- *             Alan Cox        :       Backed out LMV's tweak - the linux mm cant
- *                                     take it...
+ *             Alan Cox        :       Backed out LMV's tweak - the linux mm
+ *                                     can't take it...
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
index 58fe093..7d319f3 100644 (file)
     Paul Gortmaker     : new reset code, reset card after probe at boot.
     Paul Gortmaker     : multiple card support for module users.
     Paul Gortmaker     : Support for PCI ne2k clones, similar to lance.c
+    Paul Gortmaker     : Allow users with bad cards to avoid full probe.
 
 */
 
@@ -78,6+79,7 @@ bad_clone_list[] = {
     {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
     {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
     {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
+    {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
     {0,}
 };
 #endif
@@ -206,7+208,7 @@ static int ne_probe1(struct device *dev, int ioaddr)
     int wordlength = 2;
     const char *name = NULL;
     int start_page, stop_page;
-    int neX000, ctron;
+    int neX000, ctron, bad_card;
     int reg0 = inb_p(ioaddr);
     static unsigned version_printed = 0;
 
@@ -232,6+234,14 @@ static int ne_probe1(struct device *dev, int ioaddr)
 
     printk("NE*000 ethercard probe at %#3x:", ioaddr);
 
+    /* A user with a poor card that fails to ack the reset, or that
+       does not have a valid 0x57,0x57 signature can still use this
+       without having to recompile. Specifying an i/o address along
+       with an otherwise unused dev->mem_end value of "0xBAD" will 
+       cause the driver to skip these parts of the probe. */
+
+    bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
     /* Reset card. Who knows what dain-bramaged state it was left in. */
     {  unsigned long reset_start_time = jiffies;
 
@@ -240,8+250,13 @@ static int ne_probe1(struct device *dev, int ioaddr)
 
        while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
                if (jiffies - reset_start_time > 2*HZ/100) {
-                       printk(" not found (no reset ack).\n");
-                       return ENODEV;
+                       if (bad_card) {
+                               printk(" (warning: no reset ack)");
+                               break;
+                       } else {
+                               printk(" not found (no reset ack).\n");
+                               return ENODEV;
+                       }
                }
 
        outb_p(0xff, ioaddr + EN0_ISR);         /* Ack all intr. */
@@ -297,7+312,7 @@ static int ne_probe1(struct device *dev, int ioaddr)
     ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
 
     /* Set up the rest of the parameters. */
-    if (neX000) {
+    if (neX000 || bad_card) {
        name = (wordlength == 2) ? "NE2000" : "NE1000";
     } else if (ctron) {
        name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
index b0915a3..f3c7dce 100644 (file)
 */
 
 #include <linux/module.h>
+#include <linux/config.h>      /* for CONFIG_IP_FORWARD */
 
 /* Only two headers!! :-) */
 #include <net/ip.h>
@@ -172,7+173,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
                printk ( KERN_INFO "%s: Packet with no route!\n", dev->name);
                dev->tbusy=0;
                stats->tx_errors++;
-               return(1);
+               dev_kfree_skb(skb, FREE_WRITE);
+               return 0;
        }
 
        /*
@@ -191,7+193,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
                ip_rt_put(rt);
                dev->tbusy=0;
                stats->tx_errors++;
-               return(1);
+               dev_kfree_skb(skb, FREE_WRITE);
+               return 0;
        }
        ip_rt_put(rt);
 
@@ -203,7+206,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
                printk ( KERN_INFO "%s: Can't reach target gateway!\n", dev->name);
                dev->tbusy=0;
                stats->tx_errors++;
-               return(1);
+               dev_kfree_skb(skb, FREE_WRITE);
+               return 0;
        }
        tdev = rt->rt_dev;
 
@@ -214,7+218,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
                ip_rt_put(rt);
                dev->tbusy=0;
                stats->tx_errors++;
-               return(1);
+               dev_kfree_skb(skb, FREE_WRITE);
+               return 0;
        }
 
 #ifdef TUNNEL_DEBUG
@@ -243,7+248,8 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN);
                        ip_rt_put(rt);
                        dev->tbusy = 0;
                        stats->tx_dropped++;
-                       return(1);
+                       dev_kfree_skb(skb, FREE_WRITE);
+                       return 0;
                }
                new_skb->free = 1;
 
@@ -259,8+265,7 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN);
                 */
                new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len);
                memcpy(new_skb->ip_hdr, skb->data, skb->len);
-               /* Is this necessary? */
-               memcpy(new_skb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+               memset(new_skb->proto_priv, 0, sizeof(skb->proto_priv));
 
                /* Tack on our header */
                new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
@@ -299,7+304,9 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN);
         *      If ip_forward() made a copy, it will return 1 so we can free.
         */
 
-       if (ip_forward(skb, dev, 0, target) == 1)
+#ifdef CONFIG_IP_FORWARD
+       if (ip_forward(skb, dev, 0, target))
+#endif
                kfree_skb(skb, FREE_WRITE);
 
        /*
index 08625d5..865e8bb 100644 (file)
@@ -91,7+91,7 @@ typedef struct sk_buff             sk_buff;
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if_arp.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
 
 #define fcstab ppp_crc16_table         /* Name of the table in the kernel */
 #include <linux/ppp_defs.h>
index 570da92..74147f0 100644 (file)
@@ -955,7+955,7 @@ static int sdla_close(struct device *dev)
    }
 
    memset(&intr, 0, sizeof(intr));
-   /* lets start up the reception */
+   /* let's start up the reception */
    switch(flp->type)
    {
       case SDLA_S502A:
@@ -1028,7+1028,7 @@ static int sdla_open(struct device *dev)
 
    sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
 
-   /* lets start up the reception */
+   /* let's start up the reception */
    memset(&intr, 0, sizeof(intr));
    switch(flp->type)
    {
index 2ba2e08..c4d4852 100644 (file)
@@ -611,7+611,7 @@ static void
 set_multicast_list(struct device *dev)
 {
 /*
- * I _could_ do upto 6 addresses here, but wont (yet?)
+ * I _could_ do up to 6 addresses here, but won't (yet?)
  */
 
 #if 0
index b35d8e4..809ba6d 100644 (file)
 #define SEEQCFG2_NO_PREAM      (0x0080)        /* 1= user supplies Xmit preamble bytes */
 #define SEEQCFG2_ADDR_LEN      (0x0100)        /* 1= 2byte addresses */
 #define SEEQCFG2_REC_CRC       (0x0200)        /* 0= received packets will have CRC stripped from them */
-#define SEEQCFG2_XMIT_NO_CRC   (0x0400)        /* dont xmit CRC with each packet (user supplies it) */
+#define SEEQCFG2_XMIT_NO_CRC   (0x0400)        /* don't xmit CRC with each packet (user supplies it) */
 #define SEEQCFG2_LOOPBACK      (0x0800)
 #define SEEQCFG2_CTRLO         (0x1000)
 #define SEEQCFG2_RESET         (0x8000)        /* software Hard-reset bit */
index 98fa799..696acaf 100644 (file)
@@ -112,7+112,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
 
 /* 
  * In POS3 are bits A14-A19 of the address bus. These bits can be set
- * to choose the RAM address. Thats why we only can choose the RAM address
+ * to choose the RAM address. That's why we only can choose the RAM address
  * in 16KB steps.
  */
 
@@ -1441,7+1441,7 @@ static void SK_txintr(struct device *dev)
         /* 
          * Here I have a problem.
          * I only know that there must be one or up to 15 collisions.
-         * Thats why TX_MORE is set, because after 16 attempts TX_RTRY
+         * That's why TX_MORE is set, because after 16 attempts TX_RTRY
          * will be set which means couldn't send packet aborted transfer.
          *
          * First I did not have this in but then I thought at minimum
index b2696a1..5b86831 100644 (file)
 #include <asm/segment.h>
 #include <linux/mm.h>
 #include <net/checksum.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
 
 #ifdef __alpha__
 # include <asm/unaligned.h>
index 1b55ce4..4d3c053 100644 (file)
 #ifdef CONFIG_INET
 #include <linux/ip.h>
 #include <linux/tcp.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
 #endif
 
 #ifdef MODULE
index b393828..7ff1e27 100644 (file)
@@ -1,6+1,8 @@
 /* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
 /*
-       Written 1993,1994,1995 by Donald Becker.
+       This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards.
+
+       Written 1993-1996 by Donald Becker.
 
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.
        Center of Excellence in Space Data and Information Sciences
                Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-       This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
-
        This driver uses the cards in the 8390-compatible, shared memory mode.
        Most of the run-time complexity is handled by the generic code in
        8390.c.  The code in this file is responsible for
        transfers to avoid a bug in early version of the card that corrupted
        data transferred by a AHA1542.
 
-       This driver does not support the programmed-I/O data transfer mode of
-       the EtherEZ.  That support (if available) is smc-ez.c.  Nor does it
-       use the non-8390-compatible "Altego" mode. (No support currently planned.)
+       This driver now supports the programmed-I/O (PIO) data transfer mode of
+       the EtherEZ. It does not use the non-8390-compatible "Altego" mode.
+       That support (if available) is smc-ez.c.
 
        Changelog:
 
        Paul Gortmaker  : multiple card support for module users.
+       Donald Becker   : 4/17/96 PIO support, minor potential problems avoided.
 */
 
 static const char *version =
-       "smc-ultra.c:v1.12 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+       "smc-ultra.c:v1.99 4/17/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 
 #include <linux/module.h>
@@ -73,6+74,12 @@ static void ultra_block_input(struct device *dev, int count,
                                                  struct sk_buff *skb, int ring_offset);
 static void ultra_block_output(struct device *dev, int count,
                                                        const unsigned char *buf, const start_page);
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, 
+                                               int ring_page);
+static void ultra_pio_input(struct device *dev, int count,
+                                                 struct sk_buff *skb, int ring_offset);
+static void ultra_pio_output(struct device *dev, int count,
+                                                       const unsigned char *buf, const start_page);
 static int ultra_close_card(struct device *dev);
 
 \f
@@ -81,8+88,11 @@ static int ultra_close_card(struct device *dev);
 #define ULTRA_CMDREG   0               /* Offset to ASIC command register. */
 #define         ULTRA_RESET    0x80    /* Board reset, in ULTRA_CMDREG. */
 #define         ULTRA_MEMENB   0x40    /* Enable the shared memory. */
+#define IOPD   0x02                    /* I/O Pipe Data (16 bits), PIO operation. */
+#define IOPA   0x07                    /* I/O Pipe Address for PIO operation. */
 #define ULTRA_NIC_OFFSET  16   /* NIC register offset from the base_addr. */
 #define ULTRA_IO_EXTENT 32
+#define EN0_ERWCNT             0x08    /* Early receive warning count. */
 \f
 /*     Probe for the Ultra.  This looks like a 8013 with the station
        address PROM at I/O ports <base>+8 to <base>+13, with a checksum
@@ -123,7+133,7 @@ int ultra_probe1(struct device *dev, int ioaddr)
        unsigned char eeprom_irq = 0;
        static unsigned version_printed = 0;
        /* Values from various config regs. */
-       unsigned char num_pages, irqreg, addr;
+       unsigned char num_pages, irqreg, addr, piomode;
        unsigned char idreg = inb(ioaddr + 7);
        unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
 
@@ -162,8+172,9 @@ int ultra_probe1(struct device *dev, int ioaddr)
 
        /* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
        outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-       irqreg = inb(ioaddr + 0xd);
+       piomode = inb(ioaddr + 0x8);
        addr = inb(ioaddr + 0xb);
+       irqreg = inb(ioaddr + 0xd);
 
        /* Switch back to the station address register set so that the MS-DOS driver
           can find the card after a warm boot. */
@@ -214,13+225,20 @@ int ultra_probe1(struct device *dev, int ioaddr)
        dev->mem_end = dev->rmem_end
                = dev->mem_start + (ei_status.stop_page - START_PG)*256;
 
-       printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ",
-                  dev->irq, dev->mem_start, dev->mem_end-1);
-
+       if (piomode) {
+               printk(",%s IRQ %d programmed-I/O mode.\n",
+                          eeprom_irq ? "EEPROM" : "assigned ", dev->irq);
+               ei_status.block_input = &ultra_pio_input;
+               ei_status.block_output = &ultra_pio_output;
+               ei_status.get_8390_hdr = &ultra_pio_get_hdr;
+       } else {
+               printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ",
+                          dev->irq, dev->mem_start, dev->mem_end-1);
+               ei_status.block_input = &ultra_block_input;
+               ei_status.block_output = &ultra_block_output;
+               ei_status.get_8390_hdr = &ultra_get_8390_hdr;
+       }
        ei_status.reset_8390 = &ultra_reset_8390;
-       ei_status.block_input = &ultra_block_input;
-       ei_status.block_output = &ultra_block_output;
-       ei_status.get_8390_hdr = &ultra_get_8390_hdr;
        dev->open = &ultra_open;
        dev->stop = &ultra_close_card;
        NS8390_init(dev, 0);
@@ -236,9+254,16 @@ ultra_open(struct device *dev)
        if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL))
                return -EAGAIN;
 
-       outb(ULTRA_MEMENB, ioaddr);     /* Enable memory, 16 bit mode. */
+       outb(0x00, ioaddr);     /* Disable shared memory for safety. */
        outb(0x80, ioaddr + 5);
-       outb(0x01, ioaddr + 6);         /* Enable interrupts and memory. */
+       if (ei_status.block_input == &ultra_pio_input)
+               outb(0x11, ioaddr + 6);         /* Enable interrupts and PIO. */
+       else
+               outb(0x01, ioaddr + 6);         /* Enable interrupts and memory. */
+       /* Set the early receive warning level in window 0 high enough not
+          to receive ERW interrupts. */
+       outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
+       outb(0xff, dev->base_addr + EN0_ERWCNT);
        ei_open(dev);
        MOD_INC_USE_COUNT;
        return 0;
@@ -253,7+278,12 @@ ultra_reset_8390(struct device *dev)
        if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies);
        ei_status.txing = 0;
 
-       outb(ULTRA_MEMENB, cmd_port);
+       outb(0x00, cmd_port);   /* Disable shared memory for safety. */
+       outb(0x80, cmd_port + 5);
+       if (ei_status.block_input == &ultra_pio_input)
+               outb(0x11, cmd_port + 6);               /* Enable interrupts and PIO. */
+       else
+               outb(0x01, cmd_port + 6);               /* Enable interrupts and memory. */
 
        if (ei_debug > 1) printk("reset done\n");
        return;
@@ -266,7+296,6 @@ ultra_reset_8390(struct device *dev)
 static void
 ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
-
        unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
 
        outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);  /* shmem on */
@@ -318,6+347,49 @@ ultra_block_output(struct device *dev, int count, const unsigned char *buf,
        outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
 }
 
+/* The identical operations for programmed I/O cards.
+   The PIO model is trivial to use: the 16 bit start address is written
+   byte-sequentially to IOPA, with no intervening I/O operations, and the
+   data is read or written to the IOPD data port.
+   The only potential complication is that the address register is shared
+   must be always be rewritten between each read/write direction change.
+   This is no problem for us, as the 8390 code ensures that we are single
+   threaded. */
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, 
+                                               int ring_page)
+{
+       int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+       outb(0x00, ioaddr + IOPA);      /* Set the address, LSB first. */
+       outb(ring_page, ioaddr + IOPA);
+       insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+}
+
+static void ultra_pio_input(struct device *dev, int count,
+                                                 struct sk_buff *skb, int ring_offset)
+{
+       int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+    char *buf = skb->data;
+
+       /* For now set the address again, although it should already be correct. */
+       outb(ring_offset, ioaddr + IOPA);       /* Set the address, LSB first. */
+       outb(ring_offset >> 8, ioaddr + IOPA);
+       insw(ioaddr + IOPD, buf, (count+1)>>1);
+#ifdef notdef
+       /* We don't need this -- skbuffs are padded to at least word alignment. */
+       if (count & 0x01) {
+               buf[count-1] = inb(ioaddr + IOPD);
+#endif
+}
+
+static void ultra_pio_output(struct device *dev, int count,
+                                                       const unsigned char *buf, const start_page)
+{
+       int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+       outb(0x00, ioaddr + IOPA);      /* Set the address, LSB first. */
+       outb(start_page, ioaddr + IOPA);
+       outsw(ioaddr + IOPD, buf, (count+1)>>1);
+}
+
 static int
 ultra_close_card(struct device *dev)
 {
index 3b03ef5..7344191 100644 (file)
@@ -273,7+273,7 @@ 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...
+# That's all folks...
 string F1 = "\033[[A"
 string F2 = "\033[[B"
 string F3 = "\033[[C"
index c4c7797..fdea1b8 100644 (file)
@@ -467,7+467,7 @@ static _INLINE_ void transmit_chars(struct sun_serial *info)
        }
 
        if((info->xmit_cnt <= 0) || info->tty->stopped) {
-               /* Thats peculiar... */
+               /* That's peculiar... */
                info->zs_channel->control = RES_Tx_P;
                udelay(5);
                goto clear_and_return;
index d4d2dae..db25d92 100644 (file)
@@ -345,7+345,7 @@ static Scsi_Host_Template *the_template = NULL;
  * 001c46d4 : 0x001c5ea0 0x000011f8
  *
  *     Changed the print code in the phase_mismatch handler so
- *     that we call print_lots to try and diagnose this.
+ *     that we call print_lots to try to diagnose this.
  *
  */
 
index 050ac6d..5501be4 100644 (file)
@@ -1233,7+1233,7 @@ Thu Jul 14 10:51:42 1994  Eric Youngdale  (eric@esp22)
        * scsi.c (scan_scsis): Add new devices to end of linked list, not
        to the beginning.
 
-       * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save
+       * scsi.h (SCSI_SLEEP): Remove brain dead hack to try to save
        the task state before sleeping.
 
 Sat Jul  9 15:01:03 1994  Eric Youngdale  (eric@esp22)
@@ -1724,7+1724,7 @@ Thu Aug  5 11:59:18 1993
     * constants.c, constants.h: New files with ascii descriptions of
     various conditions.
 
-    * Makefile: Do not try and count the number of low-level drivers,
+    * Makefile: Do not try to count the number of low-level drivers,
     just generate the list of .o files.
 
     * aha1542.c: Replace 16 with sizeof(SCpnt->sense_buffer).  Add tests
@@ -1819,7+1819,7 @@ Thu Jun  2 17:58:11 1993
 
     * sr.c: Increase timeout to 500 from 250.  Add entry for sync in
     dispatch table (supply NULL).  If we do not have a sectorsize,
-    try and get it in the sd_open function.  Add new function just to
+    try to get it in the sd_open function.  Add new function just to
     obtain sectorsize.
 
     * sr.h: Add needs_sector_size semaphore.
index f4e7211..7fbd8b3 100644 (file)
@@ -21,7+21,7 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
+dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
 dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
index 71b41a1..c7ebd6a 100644 (file)
@@ -274,7+274,7 @@ MTIOCGET Returns some status information.
 The following ioctls use the structure mtlocation that contains both
 the block number and the partition number. These ioctls are available
 only for SCSI-2 tape drives and the block number is the
-device-indepent logical block number defined by the standard.
+device-independent logical block number defined by the standard.
 
 MTGETLOC Returns the current block and partition number.
 MTSETLOC Sets the tape to the block and partition specified by the
index 9e580b2..08d9a31 100644 (file)
@@ -1214,7+1214,7 @@ int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
        setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
 
        /*
-        * Now try and pick up the pieces.  Restart all commands
+        * Now try to pick up the pieces.  Restart all commands
         * that are currently active on the bus, and reset all of
         * the datastructures.  We have some time to kill while
         * things settle down, so print a nice message.
index fc0702b..996b625 100644 (file)
@@ -4483,12+4483,12 @@ aic7xxx_abort_reset(Scsi_Cmnd *cmd, unsigned char errcode)
        * The target we select to send the message to may be entirely
        * different than the target pointed to by the scb that timed
        * out.  If the command is in the QINFIFO or the waiting for
-       * selection list, its not tying up the bus and isn't responsible
+       * selection list, it's not tying up the bus and isn't responsible
        * for the delay so we pick off the active command which should
-       * be the SCB selected by SCBPTR.  If its disconnected or active,
+       * be the SCB selected by SCBPTR.  If it's disconnected or active,
        * we device reset the target scbp points to.  Although it may
        * be that this target is not responsible for the delay, it may
-       * may also be that we're timing out on a command that just takes
+       * also be that we're timing out on a command that just takes
        * too much time, so we try the bus device reset there first.
        */
       active_scb = inb(SCBPTR + base);
index 43e75f9..cb534f8 100644 (file)
@@ -8,8+8,15 @@
  *                                                         *
  *  The driver currently:                                  *
  *     -supports all ISA based EATA-DMA boards             *
+ *       like PM2011, PM2021, PM2041, PM3021                *
  *     -supports all EISA based EATA-DMA boards            *
+ *       like PM2012B, PM2022, PM2122, PM2322, PM2042,      *
+ *            PM3122, PM3222, PM3332                        *
  *     -supports all PCI based EATA-DMA boards             *
+ *       like PM2024, PM2124, PM2044, PM2144, PM3224,       *
+ *            PM3334                                        *
+ *      -supports the Wide, Ultra Wide and Differential     *
+ *       versions of the boards                             *
  *     -supports multiple HBAs with & without IRQ sharing  *
  *     -supports all SCSI channels on multi channel boards *
  *     -needs identical IDs on all channels of a HBA       * 
  *      -provides rudimentary latency measurement           * 
  *       possibilities via /proc/scsi/eata_dma/<hostnum>    *
  *                                                         *
- *  (c)1993,94,95 Michael Neuffer                          *
- *               neuffer@goofy.zdv.uni-mainz.de            *
+ *  (c)1993-96 Michael Neuffer                             *
+ *             mike@i-Connect.Net                           *
+ *            neuffer@mail.uni-mainz.de                    *
  *                                                         *
  *  This program is free software; you can redistribute it  *
  *  and/or modify it under the terms of the GNU General            *
  * very helpful and tried to give me all the infos and     *
  * support I need.                                         *
  *                                                         *
- * Thanks also to Greg Hosler who did a lot of testing and  *
- * found quite a number of bugs during the development.            *
+ * Thanks also to Simon Shapiro, Greg Hosler and Mike       *
+ * Jagdis who did a lot of testing and found quite a number *
+ * of bugs during the development.                          *
  ************************************************************
- *  last change: 95/04/27                 OS: Linux 1.3.95  *
+ *  last change: 95/05/05                 OS: Linux 1.3.98  *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration and revision information */
 #include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 #include <asm/byteorder.h>
 #include <asm/types.h>
 #include <asm/io.h>
@@ -132,7+142,7 @@ int eata_release(struct Scsi_Host *sh)
     else reg_IRQ[sh->irq]--;
     
     scsi_init_free((void *)status, 512);
-    scsi_init_free((void *)dma_scratch, 512);
+    scsi_init_free((void *)dma_scratch - 4, 1024);
     for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
        if(SD(sh)->ccb[i].sg_list != NULL)
            scsi_init_free((void *) SD(sh)->ccb[i].sg_list, 
@@ -149,12+159,89 @@ int eata_release(struct Scsi_Host *sh)
 #endif
 
 
+inline void eata_latency_in(struct eata_ccb *cp, hostdata *hd)
+{
+    uint time;
+    time = jiffies - cp->timestamp;
+    if(hd->all_lat[1] > time)
+        hd->all_lat[1] = time;
+    if(hd->all_lat[2] < time)
+        hd->all_lat[2] = time;
+    hd->all_lat[3] += time;
+    hd->all_lat[0]++;
+    if((cp->rw_latency) == WRITE) { /* was WRITE */
+        if(hd->writes_lat[cp->sizeindex][1] > time)
+           hd->writes_lat[cp->sizeindex][1] = time;
+       if(hd->writes_lat[cp->sizeindex][2] < time)
+           hd->writes_lat[cp->sizeindex][2] = time;
+       hd->writes_lat[cp->sizeindex][3] += time;
+       hd->writes_lat[cp->sizeindex][0]++;
+    } else if((cp->rw_latency) == READ) {
+        if(hd->reads_lat[cp->sizeindex][1] > time)
+           hd->reads_lat[cp->sizeindex][1] = time;
+       if(hd->reads_lat[cp->sizeindex][2] < time)
+           hd->reads_lat[cp->sizeindex][2] = time;
+       hd->reads_lat[cp->sizeindex][3] += time;
+       hd->reads_lat[cp->sizeindex][0]++;
+    }
+} 
+
+inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd)
+{
+    int x, z;
+    short *sho;
+    long *lon;
+    x = 0;                             /* just to keep GCC quiet */ 
+    cp->timestamp = jiffies;           /* For latency measurements */
+    switch(cmd->cmnd[0]) {
+    case WRITE_6:   
+        x = cmd->cmnd[4]/2; 
+       cp->rw_latency = WRITE;
+       break;
+    case READ_6:    
+        x = cmd->cmnd[4]/2; 
+       cp->rw_latency = READ;
+       break;
+    case WRITE_10:   
+        sho = (short *) &cmd->cmnd[7];
+       x = ntohs(*sho)/2;            
+       cp->rw_latency = WRITE;
+       break;
+    case READ_10:
+        sho = (short *) &cmd->cmnd[7];
+       x = ntohs(*sho)/2;            
+       cp->rw_latency = READ;
+       break;
+    case WRITE_12:   
+        lon = (long *) &cmd->cmnd[6];
+       x = ntohl(*lon)/2;            
+       cp->rw_latency = WRITE;
+       break;
+    case READ_12:
+        lon = (long *) &cmd->cmnd[6];
+       x = ntohl(*lon)/2;            
+       cp->rw_latency = READ;
+       break;
+    default:
+        cp->rw_latency = OTHER;
+       break;
+    }
+    if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || 
+       cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 || 
+       cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {
+        for(z = 0; (x > (1 << z)) && (z <= 11); z++) 
+           /* nothing */;
+       cp->sizeindex = z;
+    } 
+}
+
+
 void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
 {
     uint i, result = 0;
     uint hba_stat, scsi_stat, eata_stat;
     Scsi_Cmnd *cmd;
-    struct eata_ccb *cp;
+    struct eata_ccb *ccb;
     struct eata_sp *sp;
     uint base;
     ulong flags;
@@ -173,16+260,16 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
            int_counter++;
            
            sp = &SD(sh)->sp;
-           cp = sp->ccb;
+           ccb = sp->ccb;
            
-           if(cp == NULL) {
+           if(ccb == NULL) {
                eata_stat = inb((uint)sh->base + HA_RSTATUS);
                printk("eata_dma: int_handler, Spurious IRQ %d "
                       "received. CCB pointer not set.\n", irq);
                break;
            }
 
-           cmd = cp->cmd;
+           cmd = ccb->cmd;
            base = (uint) cmd->host->base;
                    hba_stat = sp->hba_stat;
            
@@ -190,23+277,27 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
            
            if (sp->EOC == FALSE) {
                eata_stat = inb(base + HA_RSTATUS);
-               printk("eata_dma: int_handler, board: %x cmd %lx returned "
-                      "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx "
-                      "spadrirq %lx, irq%d\n", base, (long)cp, eata_stat, 
-                      hba_stat, scsi_stat,(long)&status, (long)&status[irq], 
-                      irq);
-               DBG(DBG_DELAY, DEL2(800));
+               printk(KERN_WARNING "eata_dma: int_handler, board: %x cmd %lx "
+                      "returned unfinished.\n"
+                      "EATA: %x HBA: %x SCSI: %x spadr %lx spadrirq %lx, "
+                      "irq%d\n", base, (long)ccb, eata_stat, hba_stat, 
+                      scsi_stat,(long)&status, (long)&status[irq], irq);
+               cmd->result = DID_ERROR << 16;
+               ccb->status = FREE;
+               cmd->scsi_done(cmd);
                break;
            } 
            
-           if (cp->status == LOCKED) {
-               cp->status = FREE;
+           if (ccb->status == LOCKED) {
+               ccb->status = FREE;
                eata_stat = inb(base + HA_RSTATUS);
                printk("eata_dma: int_handler, freeing locked queueslot\n");
-               DBG(DBG_INTR && DBG_DELAY, DEL2(800));
+               DBG(DBG_INTR && DBG_DELAY, DELAY(1));
                break;
            }
            
+           sp->EOC = FALSE; /* Clean out this flag */
+
            eata_stat = inb(base + HA_RSTATUS); 
            DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "
                                 "target: %x, lun: %x, ea_s: %#.2x, hba_s: "
@@ -215,52+306,22 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
            
            switch (hba_stat) {
            case HA_NO_ERROR:   /* NO Error */
-               if (scsi_stat == CONDITION_GOOD
-                   && cmd->device->type == TYPE_DISK
-                   && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET))
-                   result = DID_BUS_BUSY << 16;            
-               else if (scsi_stat == GOOD) {
-                   HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK;
-                   if(HD(cmd)->do_latency == TRUE && cp->timestamp) {
-                       uint time;
-                       time = jiffies - cp->timestamp;
-                       if((cp->rw_latency) == TRUE) { /* was WRITE */
-                           if(HD(cmd)->writes_lat[cp->sizeindex][1] > time)
-                               HD(cmd)->writes_lat[cp->sizeindex][1] = time;
-                           if(HD(cmd)->writes_lat[cp->sizeindex][2] < time)
-                               HD(cmd)->writes_lat[cp->sizeindex][2] = time;
-                           HD(cmd)->writes_lat[cp->sizeindex][3] += time;
-                           HD(cmd)->writes_lat[cp->sizeindex][0]++;
-                       } else {
-                           if(HD(cmd)->reads_lat[cp->sizeindex][1] > time)
-                               HD(cmd)->reads_lat[cp->sizeindex][1] = time;
-                           if(HD(cmd)->reads_lat[cp->sizeindex][2] < time)
-                               HD(cmd)->reads_lat[cp->sizeindex][2] = time;
-                           HD(cmd)->reads_lat[cp->sizeindex][3] += time;
-                           HD(cmd)->reads_lat[cp->sizeindex][0]++;
-                       }
-                   }
-               }
-               else if (scsi_stat == CHECK_CONDITION
-                        && cmd->device->type == TYPE_DISK
-                        && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
-                   result = DID_BUS_BUSY << 16;
-               else
-                   result = DID_OK << 16;
-               HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK;
+               HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK;
+               if(HD(cmd)->do_latency == TRUE && ccb->timestamp) 
+                   eata_latency_in(ccb, HD(cmd));
+               result = DID_OK << 16;
+               HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK;
                break;
            case HA_ERR_SEL_TO:         /* Selection Timeout */
-               result = DID_BAD_TARGET << 16;  
-               break;
            case HA_ERR_CMD_TO:         /* Command Timeout   */
-               if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1)
-                   result = DID_ERROR << 16;
-               else {
-                   result = DID_TIME_OUT << 16;
-                   HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++;
-               }
+               result = DID_TIME_OUT << 16;
+               break;
+           case HA_BUS_RESET:          /* SCSI Bus Reset Received */
+               result = DID_RESET << 16;
+               DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: BUS RESET "
+                                      "received on cmd %ld\n", 
+                                      HD(cmd)->HBA_number, cmd->pid));
                break;
-           case HA_ERR_RESET:          /* SCSI Bus Reset Received */
            case HA_INIT_POWERUP:       /* Initial Controller Power-up */
                if (cmd->device->type != TYPE_TAPE)
                    result = DID_BUS_BUSY << 16;
@@ -268,15+329,39 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
                    result = DID_ERROR << 16;
                
                for (i = 0; i < MAXTARGET; i++)
-                   HD(cmd)->t_state[cp->cp_channel][i] = RESET;
+                   HD(cmd)->t_state[ccb->cp_channel][i] = RESET;
+               DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "
+                                      "returned with INIT_POWERUP\n", 
+                                      HD(cmd)->HBA_number, cmd->pid));
+               break;
+           case HA_CP_ABORT_NA:
+           case HA_CP_ABORTED:
+               result = DID_ABORT << 16;
+               DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: aborted cmd "
+                                      "returned\n", HD(cmd)->HBA_number));
+               break;
+           case HA_CP_RESET_NA:
+           case HA_CP_RESET:
+               HD(cmd)->t_state[cmd->channel][cmd->target] = OK; 
+               HD(cmd)->resetlevel[cmd->channel] = 0; 
+               result = DID_RESET << 16;
+               DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "
+                                      "pid %ldreturned\n", 
+                                      HD(cmd)->HBA_number, cmd->pid));
+           case HA_SCSI_HUNG:          /* SCSI Hung                 */
+               printk(KERN_ERR "scsi%d: SCSI hung\n", HD(cmd)->HBA_number);
+               result = DID_ERROR << 16;
+               break;
+           case HA_RSENSE_FAIL:        /* Auto Request-Sense Failed */
+               DBG(DBG_STATUS, printk(KERN_ERR "scsi%d: Auto Request Sense "
+                                      "Failed\n", HD(cmd)->HBA_number));
+               result = DID_ERROR << 16;
                break;
            case HA_UNX_BUSPHASE:       /* Unexpected Bus Phase */
            case HA_UNX_BUS_FREE:       /* Unexpected Bus Free */
            case HA_BUS_PARITY:         /* Bus Parity Error */
-           case HA_SCSI_HUNG:          /* SCSI Hung */
            case HA_UNX_MSGRJCT:        /* Unexpected Message Reject */
            case HA_RESET_STUCK:        /* SCSI Bus Reset Stuck */
-           case HA_RSENSE_FAIL:        /* Auto Request-Sense Failed */
            case HA_PARITY_ERR:         /* Controller Ram Parity */
            default:
                result = DID_ERROR << 16;
@@ -293,10+378,10 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
                       cmd->device->channel, cmd->device->id, cmd->device->lun,
                       cmd->pid, eata_stat, hba_stat, scsi_stat, 
                       cmd->sense_buffer[2] & 0xf, cmd->result); 
-           DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+           DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
 #endif
            
-           cp->status = FREE;      /* now we can release the slot  */
+           ccb->status = FREE;     /* now we can release the slot  */
            cmd->scsi_done(cmd);
        }
     }
@@ -314,41+399,55 @@ inline int eata_send_command(u32 addr, u32 base, u8 command)
            return(FALSE);
 
     /* And now the address in nice little byte chunks */
+#ifdef __LITTLE_ENDIAN
     outb( addr & 0x000000ff,       base + HA_WDMAADDR);
     outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
     outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
     outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+#else
+    outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
+    outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
+    outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 2);
+    outb((addr & 0x000000ff),       base + HA_WDMAADDR + 3);
+#endif
     outb(command, base + HA_WCOMMAND);
     return(TRUE);
 }
 
-#if 0 
-inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id, 
-                              u8 lun)
+inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
 {
+    outb(0x0, base + HA_WDMAADDR - 1);
     if(addr){
-       outb( addr & 0x000000ff,        base + HA_WDMAADDR);
-       outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
+#ifdef __LITTLE_ENDIAN
+        outb( addr & 0x000000ff,        base + HA_WDMAADDR);
+       outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 1);
        outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
        outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+#else
+       outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
+       outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
+       outb((addr & 0x0000ff00) >> 8,  base + HA_WDMAADDR + 2);
+       outb((addr & 0x000000ff),       base + HA_WDMAADDR + 3);
+#endif
     } else {
-       outb(id,  base + HA_WSUBCODE);
-       outb(lun, base + HA_WSUBLUN);
+        outb(0x0, base + HA_WDMAADDR);
+        outb(0x0, base + HA_WDMAADDR + 1);
+       outb(code2, base + HA_WCODE2);
+       outb(code,  base + HA_WCODE);
     }
     
-    outb(cmnd2, base + HA_WCOMMAND2);
-    outb(cmnd, base + HA_WCOMMAND);
+    outb(ifc, base + HA_WIFC);
+    outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND);
     return(TRUE);
 }
-#endif
 
 int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
 {
     unsigned int i, x, y;
-    u32 flags;
+    ulong flags;
     hostdata *hd;
     struct Scsi_Host *sh;
-    struct eata_ccb *cp;
+    struct eata_ccb *ccb;
     struct scatterlist *sl;
     
     save_flags(flags);
@@ -359,6+458,15 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
     hd = HD(cmd);
     sh = cmd->host;
     
+#if 1
+    if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
+        DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
+       cmd->result = DID_OK << 16;
+       done(cmd);
+       return(0);
+    }
+#endif
+
     /* check for free slot */
     for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) { 
        if (y >= sh->can_queue)
@@ -378,52+486,19 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
        restore_flags(flags);
        return(0);
     }
-    cp = &hd->ccb[y];
+    ccb = &hd->ccb[y];
     
-    memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
+    memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
     
-    cp->status = USED;                 /* claim free slot */
+    ccb->status = USED;                        /* claim free slot */
     
     DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
                          cmd->pid, cmd->target, cmd->lun, y));
-    DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
     
-    if(hd->do_latency == TRUE) {
-       int x, z;
-       short *sho;
-       long *lon;
-       x = 0;  /* just to keep GCC quiet */ 
-       if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || 
-           cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 || 
-           cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {
-           
-           cp->timestamp = jiffies;    /* For latency measurements */
-           switch(cmd->cmnd[0]) {
-           case WRITE_6:   
-           case READ_6:    
-               x = cmd->cmnd[4]/2; 
-               break;
-           case WRITE_10:   
-           case READ_10:
-               sho = (short *) &cmd->cmnd[7];
-               x = ntohs(*sho)/2;            
-               break;
-           case WRITE_12:   
-           case READ_12:
-               lon = (long *) &cmd->cmnd[6];
-               x = ntohl(*lon)/2;            
-               break;
-           }
+    if(hd->do_latency == TRUE) 
+        eata_latency_out(ccb, cmd);
 
-           for(z = 0; (x > (1 << z)) && (z <= 11); z++) 
-               /* nothing */;
-           cp->sizeindex = z;
-           if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || 
-               cmd->cmnd[0] == WRITE_12){
-               cp->rw_latency = TRUE;
-           }
-       }
-    }
     cmd->scsi_done = (void *)done;
     
     switch (cmd->cmnd[0]) {
@@ -438,73+513,73 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
     case WRITE_12:         case WRITE_VERIFY_12: case SET_WINDOW: 
     case MEDIUM_SCAN:      case SEND_VOLUME_TAG:            
     case 0xea:     /* alternate number for WRITE LONG */
-       cp->DataOut = TRUE;     /* Output mode */
+       ccb->DataOut = TRUE;    /* Output mode */
        break;
     case TEST_UNIT_READY:
     default:
-       cp->DataIn = TRUE;      /* Input mode  */
+       ccb->DataIn = TRUE;     /* Input mode  */
     }
 
     /* FIXME: This will will have to be changed once the midlevel driver 
      *        allows different HBA IDs on every channel.
      */
     if (cmd->target == sh->this_id) 
-       cp->Interpret = TRUE;   /* Interpret command */
+       ccb->Interpret = TRUE;  /* Interpret command */
 
     if (cmd->use_sg) {
-       cp->scatter = TRUE;     /* SG mode     */
-       if (cp->sg_list == NULL) {
-           cp->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
+       ccb->scatter = TRUE;    /* SG mode     */
+       if (ccb->sg_list == NULL) {
+           ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
                                  GFP_ATOMIC | GFP_DMA);
        }
-       if (cp->sg_list == NULL)
+       if (ccb->sg_list == NULL)
            panic("eata_dma: Run out of DMA memory for SG lists !\n");
-       cp->cp_dataDMA = htonl(virt_to_bus(cp->sg_list)); 
+       ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list)); 
        
-       cp->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
+       ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
        sl=(struct scatterlist *)cmd->request_buffer;
        for(i = 0; i < cmd->use_sg; i++, sl++){
-           cp->sg_list[i].data = htonl(virt_to_bus(sl->address));
-           cp->sg_list[i].len = htonl((u32) sl->length);
+           ccb->sg_list[i].data = htonl(virt_to_bus(sl->address));
+           ccb->sg_list[i].len = htonl((u32) sl->length);
        }
     } else {
-       cp->scatter = FALSE;
-       cp->cp_datalen = htonl(cmd->request_bufflen);
-       cp->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
+       ccb->scatter = FALSE;
+       ccb->cp_datalen = htonl(cmd->request_bufflen);
+       ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
     }
     
-    cp->Auto_Req_Sen = TRUE;
-    cp->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
-    cp->reqlen = sizeof(cmd->sense_buffer);
+    ccb->Auto_Req_Sen = TRUE;
+    ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
+    ccb->reqlen = sizeof(cmd->sense_buffer);
     
-    cp->cp_id = cmd->target;
-    cp->cp_channel = cmd->channel;
-    cp->cp_lun = cmd->lun;
-    cp->cp_dispri = TRUE;
-    cp->cp_identify = TRUE;
-    memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len);
+    ccb->cp_id = cmd->target;
+    ccb->cp_channel = cmd->channel;
+    ccb->cp_lun = cmd->lun;
+    ccb->cp_dispri = TRUE;
+    ccb->cp_identify = TRUE;
+    memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len);
     
-    cp->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
+    ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
     
-    cp->cp_viraddr = cp; /* This will be passed thru, so we don't need to 
+    ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to 
                           * convert it */
-    cp->cmd = cmd;
+    ccb->cmd = cmd;
     cmd->host_scribble = (char *)&hd->ccb[y];  
     
-    if(eata_send_command((u32) cp, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
+    if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
        cmd->result = DID_BUS_BUSY << 16;
        DBG(DBG_QUEUE && DBG_ABNORM, 
            printk("eata_queue target %d, pid %ld, HBA busy, "
                   "returning DID_BUS_BUSY\n",cmd->target, cmd->pid));
        done(cmd);
-       cp->status = FREE;    
+       ccb->status = FREE;    
        restore_flags(flags);
        return(0);
     }
     DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
                         "slot %d irq %d\n", (s32)sh->base, cmd->pid, 
                         cmd->target, cmd->lun, y, sh->irq));
-    DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
     restore_flags(flags);
     return(0);
 }
@@ -521,26+596,26 @@ int eata_abort(Scsi_Cmnd * cmd)
     DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"
                           " reason %x\n", cmd->pid, cmd->target, cmd->lun, 
                           cmd->abort_reason));
-    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
 
     while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
        if (--loop == 0) {
            printk("eata_dma: abort, timeout error.\n");
+           DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
            restore_flags(flags);
-           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
            return (SCSI_ABORT_ERROR);
        }
     }
     if (CD(cmd)->status == RESET) {
-       restore_flags(flags);
        printk("eata_dma: abort, command reset error.\n");
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+       restore_flags(flags);
        return (SCSI_ABORT_ERROR);
     }
     if (CD(cmd)->status == LOCKED) {
-       restore_flags(flags);
        DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+       restore_flags(flags);
        return (SCSI_ABORT_NOT_RUNNING);
     }
     if (CD(cmd)->status == USED) {
@@ -557,11+632,11 @@ int eata_abort(Scsi_Cmnd * cmd)
     panic("eata_dma: abort: invalid slot status\n");
 }
 
-int eata_reset(Scsi_Cmnd * cmd, int resetflags)
+int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
 {
     ushort x, z; 
-    ulong time, limit = 0;
-    ulong loop = R_LIMIT;
+    ulong limit = 0;
+    ulong loop = loops_per_sec / 3;
     ulong flags;
     unchar success = FALSE;
     Scsi_Cmnd *sp; 
@@ -576,7+651,7 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
     if (HD(cmd)->state == RESET) {
        printk("eata_reset: exit, already in reset.\n");
        restore_flags(flags);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_ERROR);
     }
     
@@ -584,7+659,7 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
        if (--loop == 0) {
            printk("eata_reset: exit, timeout error.\n");
            restore_flags(flags);
-           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
            return (SCSI_RESET_ERROR);
        }
  
@@ -602,17+677,17 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
        if (HD(cmd)->ccb[x].status == LOCKED) {
            HD(cmd)->ccb[x].status = FREE;
            printk("eata_reset: locked slot %d forced free.\n", x);
-           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
            continue;
        }
        sp = HD(cmd)->ccb[x].cmd;
        HD(cmd)->ccb[x].status = RESET;
        printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        
        if (sp == NULL)
            panic("eata_reset: slot %d, sp==NULL.\n", x);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        
        if (sp == cmd)
            success = TRUE;
@@ -624,19+699,12 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
     
     DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
     HD(cmd)->state = RESET;
-    
-    restore_flags(flags);
-    
-    time = jiffies;
-    while (jiffies < (time + (3 * HZ)) || limit++ < 10000000)
-       /* As time goes by... */;
-    
-    save_flags(flags);
-    cli();
+
+    DELAY(1); 
     
     DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", 
                           limit));
-    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
     
     for (x = 0; x < cmd->host->can_queue; x++) {
        
@@ -652,10+720,9 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
        
        printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
               x, sp->pid);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-       restore_flags(flags);
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+
        sp->scsi_done(sp);
-       cli();
     }
     
     HD(cmd)->state = FALSE;
@@ -663,11+730,11 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
     
     if (success) {
        DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_SUCCESS);
     } else {
        DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_PUNT);
     }
 }
@@ -677,7+744,8 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
  *
  * At the moment the algorithm is rather simple
  */
-static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist)
+static void eata_select_queue_depths(struct Scsi_Host *host, 
+                                    Scsi_Device *devicelist)
 {
     Scsi_Device *device;
     int devcount = 0; 
@@ -745,13+813,34 @@ static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *device
            } else /* ISA forces us to limit the QS because of bounce buffers*/
                device->queue_depth = 2; /* I know this is cruel */
 
-           printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d set "
-                  "to %d\n", host->host_no, device->id, device->channel,
+           printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
+                  "set to %d\n", host->host_no, device->id, device->channel,
                   device->queue_depth);
        }
     }
 }
 
+int check_blink_state(long base)
+{
+    ushort loops = 10;
+    u32 blinkindicator;
+    u32 state = 0x12345678;
+    u32 oldstate = 0;
+
+    blinkindicator = htonl(0x54504442);
+    while ((loops--) && (state != oldstate)) {
+       oldstate = state;
+       state = inl((uint) base + 1);
+    }
+
+    DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
+             (state == oldstate) && (state == blinkindicator)));
+
+    if ((state == oldstate) && (state == blinkindicator))
+       return(TRUE);
+    else
+       return (FALSE);
+}
 
 char * get_board_data(u32 base, u32 irq, u32 id)
 {
@@ -802,8+891,8 @@ char * get_board_data(u32 base, u32 irq, u32 id)
     while (fake_int_happened == FALSE && jiffies <= i) 
        barrier();
     
-    DBG(DBG_INTR3, printk("fake_int_result: %#x hbastat %#x scsistat %#x,"
-                         " buff %p sp %p\n",
+    DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x "
+                         "scsistat %#x, buff %p sp %p\n",
                          fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/), 
                          (u32) sp->scsi_stat, buff, sp));
 
@@ -811,38+900,17 @@ char * get_board_data(u32 base, u32 irq, u32 id)
     scsi_init_free((void *)sp, sizeof(struct eata_sp));
     
     if ((fake_int_result & HA_SERROR) || jiffies > i){
+       printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear "
+              "possible blink state\n", base); 
        /* hard reset the HBA  */
        inb((u32) (base) + HA_RSTATUS);
        eata_send_command(0, base, EATA_CMD_RESET);
-       i = jiffies;
-       while (jiffies < (i + (3 * HZ)) && limit++ < 10000000) 
-           barrier();
+       DELAY(1);
        return (NULL);
     } else
        return (buff);
 }
-    
-int check_blink_state(long base)
-{
-    ushort loops = 10;
-    u32 blinkindicator;
-    u32 state = 0x12345678;
-    u32 oldstate = 0;
-
-    blinkindicator = htonl(0x54504442);
-    while ((loops--) && (state != oldstate)) {
-       oldstate = state;
-       state = inl((uint) base + 1);
-    }
-
-    DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
-             (state == oldstate) && (state == blinkindicator)));
 
-    if ((state == oldstate) && (state == blinkindicator))
-       return(TRUE);
-    else
-       return (FALSE);
-}
 
 int get_conf_PIO(u32 base, struct get_conf *buf)
 {
@@ -857,6+925,10 @@ int get_conf_PIO(u32 base, struct get_conf *buf)
     while (inb(base + HA_RSTATUS) & HA_SBUSY)
        if (--loop == 0) 
            return (FALSE);
+
+    fake_int_base = (struct eata_register *) base;
+    fake_int_result = FALSE;
+    fake_int_happened = FALSE;
        
     DBG(DBG_PIO && DBG_PROBE,
        printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
@@ -890,6+962,7 @@ int get_conf_PIO(u32 base, struct get_conf *buf)
     return (FALSE);
 }
 
+
 void print_config(struct get_conf *gc)
 {
     printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
@@ -929,7+1002,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
     }
     if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22) 
        gc->MAX_CHAN = 0;
-    
+
     if (reg_IRQ[gc->IRQ] == FALSE) {   /* Interrupt already registered ? */
        if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
                         "eata_dma", NULL)){
@@ -948,13+1021,27 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
        } else
            reg_IRQ[gc->IRQ]++;
     }
-    
+
+    /* If DMA is supported but DMA_valid isn't set to indicate that
+     * the channel number is given we must have pre 2.0 firmware (1.7?)
+     * which leaves us to guess since the "newer ones" also don't set the 
+     * DMA_valid bit.
+     */
+    if (gc->DMA_support && !gc->DMA_valid && gc->DMA_channel) {
+      printk(KERN_WARNING "eata_dma: If you are using a pre 2.0 firmware "
+            "please update it !\n"
+            "          You can get new firmware releases from ftp.dpt.com\n");
+       gc->DMA_channel = (base == 0x1f0 ? 3 /* DMA=5 */ : 2 /* DMA=6 */);
+       gc->DMA_valid = TRUE;
+    }
+
     /* if gc->DMA_valid it must be an ISA HBA and we have to register it */
     dma_channel = BUSMASTER;
     if (gc->DMA_valid) {
        if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
-           printk("Unable to allocate DMA channel %d for ISA HBA at %#.4x.\n",
-                  dma_channel, base);
+           printk(KERN_WARNING "Unable to allocate DMA channel %d for ISA HBA"
+                  " at %#.4x.\n", dma_channel, base);
            reg_IRQ[gc->IRQ]--;
            if (reg_IRQ[gc->IRQ] == 0)
                free_irq(gc->IRQ, NULL);
@@ -963,23+1050,27 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
            return (FALSE);
        }
     }
-#if !(NEWSTUFF)
+
+    if (dma_channel != BUSMASTER) {
+       disable_dma(dma_channel);
+       clear_dma_ff(dma_channel);
+       set_dma_mode(dma_channel, DMA_MODE_CASCADE);
+       enable_dma(dma_channel);
+    }
+
     if (bustype != IS_EISA && bustype != IS_ISA)
-#endif
        buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
 
     if (buff == NULL) {
-#if !(NEWSTUFF)
        if (bustype == IS_EISA || bustype == IS_ISA) {
            bugs = bugs || BROKEN_INQUIRY;
        } else {
-#endif
            if (gc->DMA_support == FALSE)
-               printk("HBA at %#.4x doesn't support DMA. Sorry\n", base);
+               printk(KERN_WARNING "HBA at %#.4x doesn't support DMA. "
+                      "Sorry\n", base);
            else
-               printk("HBA at %#.4x does not react on INQUIRY. Sorry.\n", 
-                      base);
+               printk(KERN_WARNING "HBA at %#.4x does not react on INQUIRY. "
+                      "Sorry.\n", base);
            if (gc->DMA_valid) 
                free_dma(dma_channel);
            reg_IRQ[gc->IRQ]--;
@@ -988,14+1079,12 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
            if (gc->IRQ_TR == FALSE)
                reg_IRQL[gc->IRQ] = FALSE; 
            return (FALSE);
-#if !(NEWSTUFF)
        }
-#endif
     }
-    
     if (gc->DMA_support == FALSE && buff != NULL)  
-       printk("HBA %.12sat %#.4x doesn't set the DMA_support flag correctly.\n",
-              &buff[16], base);
+       printk(KERN_WARNING "HBA %.12sat %#.4x doesn't set the DMA_support "
+              "flag correctly.\n", &buff[16], base);
     
     request_region(base, 9, "eata_dma"); /* We already checked the 
                                          * availability, so this
@@ -1004,8+1093,10 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
     
     if(ntohs(gc->queuesiz) == 0) {
        gc->queuesiz = ntohs(64);
-       printk("Warning: Queue size has to be corrected. Assuming 64 queueslots\n"
-              "         This might be a PM2012B with a defective Firmware\n");
+       printk(KERN_WARNING "Warning: Queue size has to be corrected. Assuming"
+              " 64 queueslots\n"
+              "         This might be a PM2012B with a defective Firmware\n"
+              "         Contact DPT support@dpt.com for an upgrade\n");
     }
 
     size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long)) 
@@ -1015,7+1106,45 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
 
     sh = scsi_register(tpnt, size);
     
-    if(sh == NULL) {
+    if(sh != NULL) {
+
+        hd = SD(sh);              
+
+       memset(hd->reads, 0, sizeof(u32) * 26); 
+       
+       sh->select_queue_depths = eata_select_queue_depths;
+       
+       hd->bustype = bustype;
+
+       /*
+        * If we are using a ISA board, we can't use extended SG,
+        * because we would need exessive amounts of memory for
+        * bounce buffers.
+        */
+       if (gc->SG_64K==TRUE && ntohs(gc->SGsiz)==64 && hd->bustype!=IS_ISA){
+           sh->sg_tablesize = SG_SIZE_BIG;
+       } else {
+           sh->sg_tablesize = ntohs(gc->SGsiz);
+           if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
+               if (sh->sg_tablesize == 0)
+                   printk(KERN_WARNING "Warning: SG size had to be fixed.\n"
+                          "This might be a PM2012 with a defective Firmware"
+                          "\nContact DPT support@dpt.com for an upgrade\n");
+               sh->sg_tablesize = SG_SIZE;
+           }
+       }
+       hd->sgsize = sh->sg_tablesize;
+    }
+
+    if(sh != NULL) {
+        sh->can_queue = hd->queuesize = ntohs(gc->queuesiz);
+               sh->cmd_per_lun = 0;
+    }
+
+    if(sh == NULL) { 
+        DBG(DBG_REGISTER, printk(KERN_NOTICE "eata_dma: couldn't register HBA"
+                                " at%x \n", base));
+       scsi_unregister(sh);
        if (gc->DMA_valid) 
            free_dma(dma_channel);
        
@@ -1026,64+1155,52 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
            reg_IRQL[gc->IRQ] = FALSE; 
        return (FALSE);
     }
-    
-    hd = SD(sh);                  
-    
-    memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
-    memset(hd->reads, 0, sizeof(u32) * 26); 
 
+    
     hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);
 
     if(hd->broken_INQUIRY == TRUE) {
-       strcpy(SD(sh)->vendor, "DPT");
-       strcpy(SD(sh)->name, "??????????");
-       strcpy(SD(sh)->revision, "???.?");
+       strcpy(hd->vendor, "DPT");
+       strcpy(hd->name, "??????????");
+       strcpy(hd->revision, "???.?");
+        hd->firmware_revision = 0;
     } else {   
-       strncpy(SD(sh)->vendor, &buff[8], 8);
-       SD(sh)->vendor[8] = 0;
-       strncpy(SD(sh)->name, &buff[16], 17);
-       SD(sh)->name[17] = 0;
-       SD(sh)->revision[0] = buff[32];
-       SD(sh)->revision[1] = buff[33];
-       SD(sh)->revision[2] = buff[34];
-       SD(sh)->revision[3] = '.';
-       SD(sh)->revision[4] = buff[35];
-       SD(sh)->revision[5] = 0;
+       strncpy(hd->vendor, &buff[8], 8);
+       hd->vendor[8] = 0;
+       strncpy(hd->name, &buff[16], 17);
+       hd->name[17] = 0;
+       hd->revision[0] = buff[32];
+       hd->revision[1] = buff[33];
+       hd->revision[2] = buff[34];
+       hd->revision[3] = '.';
+       hd->revision[4] = buff[35];
+       hd->revision[5] = 0;
+        hd->firmware_revision = (buff[32] << 24) + (buff[33] << 16) 
+                                   + (buff[34] << 8) + buff[35]; 
     }
 
+    if (hd->firmware_revision >= (('0'<<24) + ('7'<<16) + ('G'<< 8) + '0'))
+        hd->immediate_support = 1;
+    else 
+        hd->immediate_support = 0;
+
     switch (ntohl(gc->len)) {
     case 0x1c:
-       SD(sh)->EATA_revision = 'a';
+       hd->EATA_revision = 'a';
        break;
     case 0x1e:
-       SD(sh)->EATA_revision = 'b';
+       hd->EATA_revision = 'b';
        break;
     case 0x22:
-       SD(sh)->EATA_revision = 'c';
+       hd->EATA_revision = 'c';
        break;
     case 0x24:
-       SD(sh)->EATA_revision = 'z';            
+       hd->EATA_revision = 'z';                
     default:
-       SD(sh)->EATA_revision = '?';
+       hd->EATA_revision = '?';
     }
 
-    if(ntohl(gc->len) >= 0x22) {
-       if (gc->is_PCI == TRUE)
-           hd->bustype = IS_PCI;
-       else if (gc->is_EISA == TRUE)
-           hd->bustype = IS_EISA;
-       else
-           hd->bustype = IS_ISA;
-    } else if(hd->broken_INQUIRY == FALSE) {
-       if (buff[21] == '4')
-           hd->bustype = IS_PCI;
-       else if (buff[21] == '2')
-           hd->bustype = IS_EISA;
-       else
-           hd->bustype = IS_ISA;
-    } else 
-       hd->bustype = bustype;
-    
+
     if(ntohl(gc->len) >= 0x22) {
        sh->max_id = gc->MAX_ID + 1;
        sh->max_lun = gc->MAX_LUN + 1;
@@ -1092,6+1209,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
        sh->max_lun = 8;
     }
 
+    hd->HBA_number = sh->host_no;
     hd->channel = gc->MAX_CHAN;            
     sh->max_channel = gc->MAX_CHAN; 
     sh->unique_id = base;
@@ -1105,34+1223,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
      * SCSI midlevel code should support different HBA ids on every channel
      */
     sh->this_id = gc->scsi_id[3];
-
-    hd->queuesize = ntohs(gc->queuesiz);
-    sh->can_queue = ntohs(gc->queuesiz);
-    sh->cmd_per_lun = 0;
-    sh->select_queue_depths = eata_select_queue_depths;
     
-    /* FIXME:
-     * SG should be allocated more dynamically 
-     */
-    /*
-     * If we are using a ISA board, we can't use extended SG,
-     * because we would need excessive amounts of memory for
-     * bounce buffers.
-     */
-    if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){
-       sh->sg_tablesize = SG_SIZE_BIG;
-       sh->use_clustering = TRUE;
-    } else {
-       sh->sg_tablesize = ntohs(gc->SGsiz);
-       sh->use_clustering = TRUE;
-       if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
-           sh->sg_tablesize = SG_SIZE;
-           if (ntohs(gc->SGsiz) == 0)
-               printk("Warning: SG size had to be corrected.\n"
-                      "This might be a PM2012 with a defective Firmware\n");
-       }
-    }
-
     if (gc->SECOND)
        hd->primary = FALSE;
     else
@@ -1150,6+1241,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
        hd->writes_lat[x][1] = 0xffffffff;
        hd->reads_lat[x][1] = 0xffffffff;
     }
+    hd->all_lat[1] = 0xffffffff;
 
     hd->next = NULL;   /* build a linked list of all HBAs */
     hd->prev = last_HBA;
@@ -1164,6+1256,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
 }
 
 
+
 void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
     u32 base;
@@ -1320,7+1413,7 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
                            continue;  /* break; */
                        } else if (check_blink_state(base) == TRUE) {
                            printk("eata_dma: HBA is in BLINK state.\n"
-                                  "Consult your HBAs Manual to correct this.\n");
+                                  "Consult your HBAs manual to correct this.\n");
                        }
                    }
                }
@@ -1350,13+1443,15 @@ int eata_detect(Scsi_Host_Template * tpnt)
     tpnt->proc_dir = &proc_scsi_eata_dma;
 
     status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
-    dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
+    dma_scratch = scsi_init_malloc(1024, GFP_ATOMIC | GFP_DMA);
 
     if(status == NULL || dma_scratch == NULL) {
        printk("eata_dma: can't allocate enough memory to probe for hosts !\n");
        return(0);
     }
 
+    dma_scratch += 4;
+
     find_PCI(&gc, tpnt);
     
     find_EISA(&gc, tpnt);
@@ -1364,41+1459,45 @@ int eata_detect(Scsi_Host_Template * tpnt)
     find_ISA(&gc, tpnt);
     
     for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we     */
-       if (reg_IRQ[i]){            /* exchange the interrupt handler which  */
+       if (reg_IRQ[i] >= 1){       /* exchange the interrupt handler which  */
            free_irq(i, NULL);      /* we used for probing with the real one */
-           request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma", NULL);
+           request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, 
+                       "eata_dma", NULL);
        }
     }
+
     HBA_ptr = first_HBA;
-    
+
     if (registered_HBAs != 0) {
-       printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
-              "developed in co-operation with DPT\n"             
-              "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n",
-              VER_MAJOR, VER_MINOR, VER_SUB);
-       printk("Registered HBAs:");
-       printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: "
-              "ID: Pr: QS: SG: CPL:\n");
-       for (i = 1; i <= registered_HBAs; i++) {
-           printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d",
+        printk("EATA (Extended Attachment) driver version: %d.%d%s"
+               "\ndeveloped in co-operation with DPT\n"
+               "(c) 1993-96 Michael Neuffer, mike@i-Connect.Net\n",
+               VER_MAJOR, VER_MINOR, VER_SUB);
+        printk("Registered HBAs:");
+        printk("\nHBA no. Boardtype    Revis  EATA Bus  BaseIO IRQ"
+               " DMA Ch ID Pr QS  S/G IS\n");
+        for (i = 1; i <= registered_HBAs; i++) {
+           printk("scsi%-2d: %.12s v%s 2.0%c %s %#.4x  %2d",
                   HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
                   SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')? 
                   "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
                   (u32) HBA_ptr->base, HBA_ptr->irq);
            if(HBA_ptr->dma_channel != BUSMASTER)
-               printk("   %2x ", HBA_ptr->dma_channel);
+               printk("  %2x ", HBA_ptr->dma_channel);
            else
-               printk("  %s", "BMST");
-           printk("  %d   %d   %c  %2d  %2d   %2d\n", SD(HBA_ptr)->channel, 
-                  HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
-                  HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+               printk(" %s", "BMST");
+           printk(" %d  %d  %c %3d %3d %c\n", 
+                  SD(HBA_ptr)->channel+1, HBA_ptr->this_id, 
+                  (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
+                  HBA_ptr->can_queue, HBA_ptr->sg_tablesize, 
+                  (SD(HBA_ptr)->immediate_support == TRUE)?'Y':'N'); 
            HBA_ptr = SD(HBA_ptr)->next;
        }
     } else {
        scsi_init_free((void *)status, 512);
     }
 
-    scsi_init_free((void *)dma_scratch, 512);
+    scsi_init_free((void *)dma_scratch - 4, 1024);
 
     DBG(DPT_DEBUG, DELAY(12));
 
index 7aec03e..eaa4dc0 100644 (file)
 /********************************************************
 * Header file for eata_dma.c Linux EATA-DMA SCSI driver *
-* (c) 1993,94,95 Michael Neuffer                        *
+* (c) 1993-96 Michael Neuffer                           *
+*             mike@i-Connect.Net                        *
+*             neuffer@mail.uni-mainz.de                 *
 *********************************************************
-* last change: 95/07/18                                 *
+* last change: 96/05/05                                 *
 ********************************************************/
 
-
 #ifndef _EATA_DMA_H
 #define _EATA_DMA_H
 
 
 #define VER_MAJOR 2
 #define VER_MINOR 5
-#define VER_SUB   "8a"
+#define VER_SUB   "8d"
 
 
 /************************************************************************
 #define DBG_INTR        0       /* Trace interrupt service routine.     */
 #define DBG_INTR2       0       /* Trace interrupt service routine.     */
 #define DBG_INTR3       0       /* Trace get_board_data interrupts.     */
+#define DBG_REQSENSE    0       /* Trace request sense commands         */     
+#define DBG_RESET       0       /* Trace reset calls                    */     
+#define DBG_STATUS      0       /* Trace status generation              */
 #define DBG_PROC        0       /* Debug proc-fs related statistics     */
 #define DBG_PROC_WRITE  0
 #define DBG_REGISTER    0       /* */
@@ -65,7+69,7 @@ const char *eata_info(struct Scsi_Host *);
 int eata_command(Scsi_Cmnd *);
 int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int eata_abort(Scsi_Cmnd *);
-int eata_reset(Scsi_Cmnd *);
+int eata_reset(Scsi_Cmnd *, unsigned int);
 int eata_proc_info(char *, char **, off_t, int, int, int);
 #ifdef MODULE
 int eata_release(struct Scsi_Host *);
index b68e329..8bbb63a 100644 (file)
@@ -1,9+1,11 @@
 /********************************************************
 * Header file for eata_dma.c and eata_pio.c            *
 * Linux EATA SCSI drivers                              *
-* (c) 1993,94,95 Michael Neuffer                       *
+* (c) 1993-96 Michael Neuffer                           *
+*             mike@i-Connect.Net                        *
+*             neuffer@mail.uni-mainz.de                 *
 *********************************************************
-* last change: 95/11/07                                        *
+* last change: 95/05/05                                 *
 ********************************************************/
 
 
 #define NEC_ID2         0xa3
 #define NEC_ID3         0x82
 
+#define EATA_CP_SIZE    44
 
-#define EATA_CP_SIZE   44
-
-#define MAX_PCI_DEVICES 32            /* Maximum # Of Devices Per Bus   */
-#define MAX_METHOD_2   16             /* Max Devices For Method 2       */
-#define MAX_PCI_BUS    16             /* Maximum # Of Busses Allowed    */
+#define MAX_PCI_DEVICES  32           /* Maximum # Of Devices Per Bus   */
+#define MAX_METHOD_2    16            /* Max Devices For Method 2       */
+#define MAX_PCI_BUS     16            /* Maximum # Of Busses Allowed    */
 
-#define SG_SIZE                64 
-#define SG_SIZE_BIG    252            /* max. 8096 elements, 64k */
+#define SG_SIZE                 64 
+#define SG_SIZE_BIG     252           /* max. 8096 elements, 64k */
 
 #define TYPE_DISK_QUEUE  16
 #define TYPE_TAPE_QUEUE  4
 #define TYPE_ROM_QUEUE   4
 #define TYPE_OTHER_QUEUE 2
 
-#define FREE      0
-#define OK        0
-#define NO_TIMEOUT 0
-#define USED      1
-#define TIMEOUT           2
-#define RESET     4
-#define LOCKED    8
+#define FREE            0
+#define OK              0
+#define NO_TIMEOUT       0
+#define USED            1
+#define TIMEOUT                 2
+#define RESET           4
+#define LOCKED          8
+#define ABORTED          16
+
+#define READ             0
+#define WRITE            1
+#define OTHER            2
 
 #define HD(cmd)         ((hostdata *)&(cmd->host->hostdata))
 #define CD(cmd)         ((struct eata_ccb *)(cmd->host_scribble))
 #define SD(host) ((hostdata *)&(host->hostdata))
 
-#define DELAY(x) { __u32 i; i = jiffies + (x * HZ); while (jiffies < i) barrier(); }
-#define DEL2(x)         { __u32 i; for (i = 0; i < 0xffff * x; i++); }
+#define DELAY(x) { __u32 i; ulong flags;          \
+                   save_flags(flags); sti();      \
+                   i = jiffies + (x * HZ);        \
+                   while (jiffies < i) barrier(); \
+                   restore_flags(flags); }
 
 /***********************************************
  *    EATA Command & Register definitions      *
 
 
 #define HA_WCOMMAND    0x07       /* command register offset   */
-#define HA_WCOMMAND2   0x06       /* immediate command offset  */
-#define HA_WSUBCODE    0x05 
-#define HA_WSUBLUN     0x04 
+#define HA_WIFC        0x06       /* immediate command offset  */
+#define HA_WCODE       0x05 
+#define HA_WCODE2      0x04 
 #define HA_WDMAADDR    0x02       /* DMA address LSB offset    */  
 #define HA_RAUXSTAT    0x08       /* aux status register offset*/
 #define HA_RSTATUS     0x07       /* status register offset    */
 #define HA_RDATA       0x00       /* data register (16bit)     */
+#define HA_WDATA       0x00       /* data register (16bit)     */
 
 #define HA_ABUSY       0x01       /* aux busy bit              */
 #define HA_AIRQ               0x02        /* aux IRQ pending bit       */
 #define HA_NO_ERROR     0x00   /* No Error                             */
 #define HA_ERR_SEL_TO   0x01   /* Selection Timeout                    */
 #define HA_ERR_CMD_TO   0x02   /* Command Timeout                      */
-#define HA_ERR_RESET    0x03   /* SCSI Bus Reset Received              */
+#define HA_BUS_RESET    0x03   /* SCSI Bus Reset Received              */
 #define HA_INIT_POWERUP         0x04   /* Initial Controller Power-up          */
 #define HA_UNX_BUSPHASE         0x05   /* Unexpected Bus Phase                 */
 #define HA_UNX_BUS_FREE         0x06   /* Unexpected Bus Free                  */
@@ -247,7+258,8 @@ struct get_conf {         /* Read Configuration Array               */
         ID_qest:1,           /* Raidnum ID is questionable             */
          is_PCI:1,           /* HBA is PCI                             */
         is_EISA:1;           /* HBA is EISA                            */
-    __u8 unused[478]; 
+    __u8 RAIDNUM;             /* unique HBA identifier                  */
+    __u8 unused[474]; 
 };
 
 struct eata_sg_list
@@ -322,27+334,34 @@ typedef struct hstd {
     __u8   name[18];
     __u8   revision[6];
     __u8   EATA_revision;
+    __u32  firmware_revision;
+    __u8   HBA_number;
     __u8   bustype;             /* bustype of HBA             */
     __u8   channel;             /* # of avail. scsi channels  */
     __u8   state;               /* state of HBA               */
     __u8   primary;             /* true if primary            */
-    __u8   broken_INQUIRY:1;    /* This is an EISA HBA with   *
+    __u8        more_support:1,  /* HBA supports MORE flag     */
+           immediate_support:1,  /* HBA supports IMMEDIATE CMDs*/
+              broken_INQUIRY:1;         /* This is an EISA HBA with   *
                                  * broken INQUIRY             */
     __u8   do_latency;          /* Latency measurement flag   */
     __u32  reads[13];
     __u32  writes[13];
     __u32  reads_lat[12][4];
     __u32  writes_lat[12][4];
+    __u32  all_lat[4];
                                 /* state of Target (RESET,..) */
     __u8   t_state[MAXCHANNEL][MAXTARGET];   
                                 /* timeouts on target         */
     __u32  t_timeout[MAXCHANNEL][MAXTARGET]; 
+    __u8   resetlevel[MAXCHANNEL]; 
     __u32  last_ccb;            /* Last used ccb              */
     __u32  cplen;               /* size of CP in words        */
     __u16  cppadlen;            /* pad length of cp in words  */
-    int    queuesize;
+    __u16  queuesize;
+    __u16  sgsize;               /* # of entries in the SG list*/
+    __u16  devflags;            /* bits set for detected devices */
     __u8   hostid;              /* SCSI ID of HBA             */
-    __u8   devflags;            /* bits set for detected devices */
     __u8   moresupport;                 /* HBA supports MORE flag     */
     struct Scsi_Host *next;        
     struct Scsi_Host *prev;
index e6740c0..829a700 100644 (file)
@@ -242,7+242,7 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
            eata_stat = inb(base + HA_RSTATUS);
            printk(KERN_NOTICE "eata_pio: int_handler, freeing locked "
                    "queueslot\n");
-           DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+           DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
            restore_flags(flags);
            return;
        }
@@ -251,7+251,7 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
        if (stat != 0x50) 
            printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, 
                    cmd->result); 
-       DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+       DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
 #endif
        
        cp->status = FREE;   /* now we can release the slot  */
@@ -322,7+322,7 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 
     DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:"
                           " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));
-    DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
     
     cmd->scsi_done = (void *)done;
     
@@ -396,7+396,7 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
     DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x "
                          "lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid, 
                         cmd->target, cmd->lun, y, sh->irq));
-    DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+    DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
     
     restore_flags(flags);
     return (0);
@@ -413,14+413,14 @@ int eata_pio_abort(Scsi_Cmnd * cmd)
     DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld "
                            "target: %x lun: %x reason %x\n", cmd->pid, 
                            cmd->target, cmd->lun, cmd->abort_reason));
-    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
     
     
     while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
        if (--loop == 0) {
            printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
            restore_flags(flags);
-           DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+           DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
            return (SCSI_ABORT_ERROR);
        }
     if (CD(cmd)->status == FREE) {
@@ -436,21+436,21 @@ int eata_pio_abort(Scsi_Cmnd * cmd)
     if (CD(cmd)->status == RESET) {
        restore_flags(flags);
        printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_ABORT_ERROR);
     }
     if (CD(cmd)->status == LOCKED) {
        restore_flags(flags);
        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot "
                                "locked.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_ABORT_NOT_RUNNING);
     }
     restore_flags(flags);
     panic("eata_pio: abort: invalid slot status\n");
 }
 
-int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
+int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy)
 {
     uint x, z, time, limit = 0;
     ulong flags;
@@ -467,7+467,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
     if (HD(cmd)->state == RESET) {
        printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
        restore_flags(flags);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_ERROR);
     }
     
@@ -487,11+487,11 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
        HD(cmd)->ccb[x].status = RESET;
        printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x,
                sp->pid);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        
        if (sp == NULL)
            panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
     }
     
     /* hard reset the HBA  */
@@ -505,7+505,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
     
     DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "
                            "loops %d.\n", limit));
-    DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+    DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
     
     for (x = 0; x < cmd->host->can_queue; x++) {
        
@@ -517,7+517,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
        sp->result = DID_RESET << 16;
        
        /* This mailbox is terminated */
-       printk(KERN_WARNING "eata_pio_reset: resetted ccb %d.\n",x);
+       printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n",x);
        HD(cmd)->ccb[x].status = FREE;
        
        restore_flags(flags);
@@ -530,11+530,11 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
     
     if (success) { /* hmmm... */
        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_SUCCESS);
     } else {
        DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
-       DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+       DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
        return (SCSI_RESET_PUNT);
     }
 }
@@ -718,7+718,7 @@ int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
            if (!gc->IRQ_TR)
                reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
        } else {
-           printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
+           printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
            return (FALSE);
        }
     } else {            /* More than one HBA on this IRQ */
index 3c25bf5..b02a056 100644 (file)
@@ -65,7+65,7 @@ const char *eata_pio_info(struct Scsi_Host *);
 int eata_pio_command(Scsi_Cmnd *);
 int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata_pio_abort(Scsi_Cmnd *);
-int eata_pio_reset(Scsi_Cmnd *);
+int eata_pio_reset(Scsi_Cmnd *, unsigned int);
 int eata_pio_proc_info(char *, char **, off_t, int, int, int);
 #ifdef MODULE
 int eata_pio_release(struct Scsi_Host *);
index 03585b0..ab68e27 100644 (file)
@@ -594,7+594,7 @@ static int fdomain_is_valid_port( int port )
 #else
 
                                /* That should have worked, but appears to
-                                  have problems.  Lets assume it is an
+                                  have problems.  Let's assume it is an
                                   18c30 if the RAM is disabled. */
 
       if (inb( port + Configuration2 ) & 0x02) {
index 9c2076c..f35029d 100644 (file)
@@ -332,7+332,7 @@ scsi_unregister(struct Scsi_Host * sh){
 
 /* We call this when we come across a new host adapter. We only do this
  * once we are 100% sure that we want to use this host adapter -  it is a
- * pain to reverse this, so we try and avoid it 
+ * pain to reverse this, so we try to avoid it 
  */
 
 struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
index 8100dba..a08ff1e 100644 (file)
@@ -311,7+311,7 @@ int     pas16_hw_detect( unsigned short  board_num )
 
     /* Mediavision has some new model boards that return ID bits
      * that indicate a SCSI interface, but they're not (LMS).  We'll
-     * put in an additional test to try and weed them out.
+     * put in an additional test to try to weed them out.
      */
 
     outb( 0x01, io_port + WAIT_STATE );        /* 1 Wait state */
index 5365346..b623ae1 100644 (file)
@@ -422,7+422,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
            do_done[i] = done;
     }
     else
-       printk("scsi_debug_queuecommand: done cant be NULL\n");
+       printk("scsi_debug_queuecommand: done can't be NULL\n");
     
 #ifdef IMMEDIATE
     if( !scsi_debug_lockup )
index be690c0..e68d085 100644 (file)
@@ -128,7+128,7 @@ static int sd_open(struct inode * inode, struct file * filp)
 
        if(!rscsi_disks[target].device->access_count)
            sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-    };
+    }
 
     /*
      * See if we are requesting a non-existent partition.  Do this
@@ -250,8+250,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
                        memcpy(sgpnt[i].alt_address, sgpnt[i].address, 
                               sgpnt[i].length);
                    scsi_free(sgpnt[i].address, sgpnt[i].length);
-               };
-           };
+               }
+           }
 
            /* Free list of scatter-gather pointers */
            scsi_free(SCpnt->buffer, SCpnt->sglist_len);  
@@ -265,8+265,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
                    memcpy(SCpnt->request.buffer, SCpnt->buffer,
                           SCpnt->bufflen);
                scsi_free(SCpnt->buffer, SCpnt->bufflen);
-           };
-       };
+           }
+       }
        /*
         * If multiple sectors are requested in one buffer, then
         * they will have been finished off by the first command.
@@ -307,8+307,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
 #endif
            if (sgpnt[i].alt_address) {
                scsi_free(sgpnt[i].address, sgpnt[i].length);
-           };
-       };
+           }
+       }
        scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
     } else {
 #ifdef DEBUG
@@ -317,7+317,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
 #endif
        if (SCpnt->buffer != SCpnt->request.buffer)
            scsi_free(SCpnt->buffer, SCpnt->bufflen);
-    };
+    }
     
     /*
      * Now, if we were good little boys and girls, Santa left us a request
@@ -417,7+417,7 @@ static void do_sd_request (void)
        if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
            restore_flags(flags);
            return;
-       };
+       }
        
        INIT_SCSI_REQUEST;
         SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
@@ -468,11+468,11 @@ static void do_sd_request (void)
        restore_flags(flags);
 
        /* This is a performance enhancement. We dig down into the request 
-        * list and try and find a queueable request (i.e. device not busy, 
+        * list and try to find a queueable request (i.e. device not busy, 
         * and host able to accept another command. If we find one, then we 
         * queue it. This can make a big difference on systems with more than 
         * one disk drive.  We want to have the interrupts off when monkeying 
-        * with the request list, because otherwise the kernel might try and 
+        * with the request list, because otherwise the kernel might try to 
         * slip in a request in between somewhere. 
         */
 
@@ -486,21+486,21 @@ static void do_sd_request (void)
                if(SCpnt) break;
                req1 = req;
                req = req->next;
-           };
+           }
            if (SCpnt && req->rq_status == RQ_INACTIVE) {
                if (req == CURRENT) 
                    CURRENT = CURRENT->next;
                else
                    req1->next = req->next;
-           };
+           }
            restore_flags(flags);
-       };
+       }
        
        if (!SCpnt) return; /* Could not find anything to do */
        
        /* Queue command */
        requeue_sd_request(SCpnt);
-    };  /* While */
+    }  /* While */
 }    
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt)
@@ -610,7+610,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
        if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
            bounce_buffer = (char *) scsi_malloc(bounce_size);
        if(!bounce_buffer) contiguous = 0;
-    };
+    }
     
     if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
        for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp, 
@@ -620,7+620,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                contiguous = 0;
                break;
            } 
-       };
+       }
     if (!SCpnt->request.bh || contiguous) {
        
        /* case of page request (i.e. raw device), or unlinked buffer */
@@ -667,11+667,11 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
                if (count < SCpnt->host->sg_tablesize) count++;
                else break;
-           };
+           }
            this_count += (bh->b_size >> 9);
            bhp = bh;
            bh = bh->b_reqnext;
-       };
+       }
 #if 0
        if(SCpnt->host->unchecked_isa_dma &&
           ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
@@ -710,7+710,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
                    !sgpnt[count].alt_address) {
                    sgpnt[count].alt_address = sgpnt[count].address;
-                   /* We try and avoid exhausting the DMA pool, since it is 
+                   /* We try to avoid exhausting the DMA pool, since it is 
                     * easier to control usage here. In other places we might 
                     * have a more pressing need, and we would be screwed if 
                     * we ran out */
@@ -719,7+719,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                    } else {
                        sgpnt[count].address = 
                            (char *) scsi_malloc(sgpnt[count].length);
-                   };
+                   }
                    /* If we start running low on DMA buffers, we abort the 
                     * scatter-gather operation, and free all of the memory 
                     * we have allocated.  We want to ensure that all scsi 
@@ -733,7+733,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                            if(sgpnt[count].alt_address) 
                                scsi_free(sgpnt[count].address, 
                                          sgpnt[count].length);
-                       };
+                       }
                        this_count = SCpnt->request.current_nr_sectors;
                        buff = SCpnt->request.buffer;
                        SCpnt->use_sg = 0;
@@ -742,9+742,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                        SCpnt->use_sg = count;
                        this_count = counted -= bh->b_size >> 9;
                        break;
-                   };
-                   
-               };
+                   }               
+               }
                
                /* Only cluster buffers if we know that we can supply DMA 
                 * buffers large enough to satisfy the request. Do not cluster
@@ -766,21+765,21 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                    else {
                        tmp = NULL;
                        max_sg = SCpnt->use_sg;
-                   };
+                   }
                    if(tmp){
                        scsi_free(sgpnt[count].address, sgpnt[count].length);
                        sgpnt[count].address = tmp;
                        count--;
                        continue;
-                   };
+                   }
                    
                    /* If we are allowed another sg chain, then increment 
                     * counter so we can insert it.  Otherwise we will end 
                     up truncating */
                    
                    if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
-               };  /* contiguous buffers */
-           }; /* for loop */
+               }  /* contiguous buffers */
+           } /* for loop */
            
            /* This is actually how many we are going to transfer */
            this_count = counted; 
@@ -795,7+794,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                while(bh){
                    printk("[%p %lx] ", bh->b_data, bh->b_size);
                    bh = bh->b_reqnext;
-               };
+               }
                if(SCpnt->use_sg < 16)
                    for(count=0; count<SCpnt->use_sg; count++)
                        printk("{%d:%p %p %d}  ", count,
@@ -803,15+802,15 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                               sgpnt[count].alt_address,
                               sgpnt[count].length);
                panic("Ooops");
-           };
+           }
            
            if (SCpnt->request.cmd == WRITE)
                for(count=0; count<SCpnt->use_sg; count++)
                    if(sgpnt[count].alt_address)
                        memcpy(sgpnt[count].address, sgpnt[count].alt_address, 
                               sgpnt[count].length);
-       };  /* Able to malloc sgpnt */
-    };  /* Host adapter capable of scatter-gather */
+       }  /* Able to malloc sgpnt */
+    }  /* Host adapter capable of scatter-gather */
     
     /* Now handle the possibility of DMA to addresses > 16Mb */
     
@@ -826,11+825,11 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
                this_count = SCpnt->request.current_nr_sectors;
                buff = (char *) scsi_malloc(this_count << 9);
                if(!buff) panic("Ran out of DMA buffers.");
-           };
+           }
            if (SCpnt->request.cmd == WRITE)
                memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
-       };
-    };
+       }
+    }
 #ifdef DEBUG
     printk("sd%c : %s %d/%d 512 byte blocks.\n", 
           'a' + devm,
@@ -845,12+844,12 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
        if(this_count & 1) panic("sd.c:Bad block number requested");
        block = block >> 1;
        this_count = this_count >> 1;
-    };
+    }
     
     if (rscsi_disks[dev].sector_size == 256){
        block = block << 1;
        this_count = this_count << 1;
-    };
+    }
     
     if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
     {
@@ -906,7+905,7 @@ static int check_scsidisk_media_change(kdev_t full_dev){
        !rscsi_disks[target].device) {
        printk("SCSI disk request error: invalid device.\n");
        return 0;
-    };
+    }
     
     if(!rscsi_disks[target].device->removable) return 0;
     
@@ -922,7+921,7 @@ static int check_scsidisk_media_change(kdev_t full_dev){
        rscsi_disks[target].device->changed = 1;
        return 1; /* This will force a flush, if called from
                   * check_disk_change */
-    };
+    }
     
     /* 
      * for removable scsi disk ( FLOPTICAL ) we have to recognise the
@@ -1033,7+1032,7 @@ static int sd_init_onedisk(int i)
                time1 = jiffies;
                while(jiffies < time1 + HZ); /* Wait 1 second for next try */
                printk( "." );
-           };
+           }
        } while(the_result && spintime && spintime+100*HZ > jiffies);
        if (spintime) {
            if (the_result)
@@ -1041,8+1040,7 @@ static int sd_init_onedisk(int i)
            else
                printk( "ready\n" );
        }
-    };  /* !MODULE_FLAG */
-    
+    }  /* !MODULE_FLAG */
     
     retries = 3;
     do {
@@ -1153,7+1151,7 @@ static int sd_init_onedisk(int i)
                rscsi_disks[i].device = NULL;
                sd_template.nr_dev--;
                return i;
-           };
+           }
        }
     {
        /*
@@ -1399,7+1397,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
        restore_flags(flags);
        printk("Device busy for revalidation (usage=%d)\n", USAGE);
        return -EBUSY;
-    };
+    }
     DEVICE_BUSY = 1;
     restore_flags(flags);
     
@@ -1419,7+1417,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
          * the partition table.
          */
         blksize_size[MAJOR_NR][minor] = 1024;
-    };
+    }
     
 #ifdef MAYBE_REINIT
     MAYBE_REINIT;
@@ -1461,7+1459,7 @@ static void sd_detach(Scsi_Device * SDp)
                sd_gendisk.part[minor].start_sect = 0;
                sd_gendisk.part[minor].nr_sects = 0;
                sd_sizes[minor] = 0;
-           };
+           }
            
            dpnt->has_part_table = 0;
            dpnt->device = NULL;
index 88aa979..9337be4 100644 (file)
@@ -303,7+303,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
                }
 
       /* If the user specified the controller type from the command line,
-        controller_type will be non-zero, so don't try and detect one */
+        controller_type will be non-zero, so don't try to detect one */
 
        if (!controller_type) {
 #ifdef OVERRIDE
index 783d9ba..03565be 100644 (file)
@@ -603,11+603,11 @@ static void do_sr_request (void)
        restore_flags(flags);
        
        /* This is a performance enhancement.  We dig down into the request list and
-        * try and find a queueable request (i.e. device not busy, and host able to
+        * try to find a queueable request (i.e. device not busy, and host able to
         * accept another command.  If we find one, then we queue it. This can
         * make a big difference on systems with more than one disk drive.  We want
         * to have the interrupts off when monkeying with the request list, because
-        * otherwise the kernel might try and slip in a request in between somewhere. */
+        * otherwise the kernel might try to slip in a request in between somewhere. */
        
        if (!SCpnt && sr_template.nr_dev > 1){
            struct request *req1;
@@ -789,7+789,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
                if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD &&
                  SCpnt->host->unchecked_isa_dma) {
                    sgpnt[count].alt_address = sgpnt[count].address;
-                   /* We try and avoid exhausting the DMA pool, since it is easier
+                   /* We try to avoid exhausting the DMA pool, since it is easier
                     * to control usage here.  In other places we might have a more
                     * pressing need, and we would be screwed if we ran out */
                    if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
index 5dcdc13..123590d 100644 (file)
@@ -259,7+259,7 @@ struct WD33C93_hostdata {
 /* defines for hostdata->level2 */
 /* NOTE: only the first 3 are implemented so far */
 
-/*  (The first 8 bits are reserved for compatibility. They function
+#define L2_NONE      1  /* no combination commands - we get lots of ints */
 #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 */
index 6acd80d..f760bdf 100644 (file)
@@ -255,7+255,7 @@ Since 2.2
 
 Since 2.1
 - Preliminary support for SB16. 
-  - The SB16 mixer is supported in it's native mode.
+  - The SB16 mixer is supported in its native mode.
   - Digitized voice capability up to 44.1 kHz/8 bit/mono
     (16 bit and stereo support coming in the next release).
 - Fixed some bugs in the digitized voice driver for PAS16.
index 88317e6..a096876 100644 (file)
@@ -893,10+893,10 @@ Cards not supported yet
 Please check which version of sound driver you are using before 
 complaining that your card is not supported. It's possible that you are 
 using a driver version which was released months before your card was
-introduced. Driver's release date is listed after it's version number
+introduced. Driver's release date is listed after its version number
 in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h.
 
-First of all. There is an easy way to make most soundcards to work
+First of all, there is an easy way to make most soundcards to work
 with Linux. Just use the DOS based driver to initialize the card
 to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
 to use the same I/O, IRQ and DMA numbers than DOS, the card could work.
index 9c8478a..ac77f44 100644 (file)
@@ -1187,7+1187,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp)
      * Check that the I/O address is in use.
      *
      * The bit 0x80 of the base I/O port is known to be 0 after the
-     * chip has performed it's power on initialization. Just assume
+     * chip has performed its power-on initialization. Just assume
      * this has happened before the OS is starting.
      *
      * If the I/O address is unused, it typically returns 0xff.
@@ -1233,7+1233,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp)
     }
 
   /*
-     * The indirect register I12 has some read only bits. Lets
+     * The indirect register I12 has some read only bits. Let's
      * try to change them.
    */
 
index 7524fce..81d5a48 100644 (file)
@@ -359,7+359,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
 
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
   gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
-  /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+  /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */
   gus_delay ();
   gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
   gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
@@ -3128,7+3128,7 @@ gus_wave_init (long mem_start, struct address_info *hw_config)
     sound_num_blocks++;;
   if (samples == NULL)
     {
-      printk ("GUS Error: Cant allocate memory for instrument tables\n");
+      printk ("GUS Error: Can't allocate memory for instrument tables\n");
       return mem_start;
     }
 
index 262ea9c..82ee5c1 100644 (file)
@@ -1348,7+1348,7 @@ clocks2ticks (unsigned long clocks)
   /*
      * The MPU-401 supports just a limited set of possible timebase values.
      * Since the applications require more choices, the driver has to
-     * program the HW to do it's best and to convert between the HW and
+     * program the HW to do its best and to convert between the HW and
      * actual timebases.
    */
 
index 413724a..fe5b030 100644 (file)
@@ -407,8+407,6 @@ sound_write_sw (int dev, struct fileinfo *file, const char *buf, int count)
 int
 sound_open_sw (int dev, struct fileinfo *file)
 {
-  int             retval;
-
   DEB (printk ("sound_open_sw(dev=%d)\n", dev));
 
   if ((dev >= SND_NDEVS) || (dev < 0))
@@ -438,25+436,37 @@ sound_open_sw (int dev, struct fileinfo *file)
 #ifdef CONFIG_SEQUENCER
     case SND_DEV_SEQ:
     case SND_DEV_SEQ2:
+    {
+      int retval;
+
       if ((retval = sequencer_open (dev, file)) < 0)
        return retval;
       break;
+    }
 #endif
 
 #ifdef CONFIG_MIDI
     case SND_DEV_MIDIN:
+    {
+      int retval;
+
       if ((retval = MIDIbuf_open (dev, file)) < 0)
        return retval;
       break;
+    }
 #endif
 
 #ifdef CONFIG_AUDIO
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
+    {
+      int retval;
+
       if ((retval = audio_open (dev, file)) < 0)
        return retval;
       break;
+    }
 #endif
 
     default:
index be20326..999fb5f 100644 (file)
@@ -34,7+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
-tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS
+tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
+if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
+  define_bool CONFIG_AMIGA_PARTITION y
+fi
 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
index fb272dc..77cb422 100644 (file)
@@ -1,5+1,5 @@
 #
-# Makefile for the linux amiga fast filesystem routines.
+# Makefile for the linux affs-filesystem routines.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
@@ -8,7+8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := affs.o
-O_OBJS   := namei.o inode.o file.o dir.o amigaffs.o symlink.o
+O_OBJS   := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
dissimilarity index 65%
index 0a0ce35..55a125f 100644 (file)
-/*
- *  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>
-
-#include "amigaffs.h"
-
-/*
- * Functions for accessing Amiga-FFS structures.
- *
- */
-
-/* Get key entry number ENTRY_POS from the header block pointed to
-   by DATA.  If ENTRY_POS is invalid, -1 is returned.  This is
-   used to get entries from file and directory headers as well
-   as extension and root blocks.  In the current FFS specs, these
-   tables are defined to be the same size in all of these. */
-
-int affs_get_key_entry (int bsize, void *data, int entry_pos)
-{
-       struct dir_front *dir_front = (struct dir_front *)data;
-       int key, hash_table_size;
-
-       hash_table_size = MIDBLOCK_LONGS (bsize);
-       key = 0;
-       if (entry_pos >= 0 && entry_pos < hash_table_size)
-               key = swap_long (dir_front->hash_table[entry_pos]);
-
-       return key;
-}
-
-/* Find the next used hash entry at or after *HASH_POS in a directory's hash
-   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
-   the directory header block in memory.  If there are no more entries,
-   0 is returned.  Otherwise, the key number in the next used hash slot
-   is returned. */
-
-int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos)
-{
-       struct dir_front *dir_front = (struct dir_front *)dir_data;
-       int i, hash_table_size;
-
-       hash_table_size = MIDBLOCK_LONGS (bsize);
-       if (*hash_pos < 0 || *hash_pos >= hash_table_size)
-               return -1;
-       for (i = *hash_pos; i < hash_table_size; i++)
-               if (dir_front->hash_table[i] != 0)
-                       break;
-       if (i == hash_table_size)
-               return 0;
-       *hash_pos = i;
-       return swap_long (dir_front->hash_table[i]);
-}
-
-/* Get the hash_chain (next file header key in hash chain) entry from a
-   file header block in memory pointed to by FH_DATA. */
-
-int affs_get_fh_hash_link (int bsize, void *fh_data)
-{
-       struct file_end *file_end;
-       int key;
-
-       file_end = GET_END_PTR (struct file_end, fh_data, bsize);
-       key = swap_long (file_end->hash_chain);
-       return key;
-}
-
-/* Set *NAME to point to the file name in a file header block in memory
-   pointed to by FH_DATA.  The length of the name is returned. */
-
-int affs_get_file_name (int bsize, void *fh_data, char **name)
-{
-       struct file_end *file_end;
-
-       file_end = GET_END_PTR (struct file_end, fh_data, bsize);
-       if (file_end->file_name[0] == 0
-           || file_end->file_name[0] > 30) {
-               printk ("affs_get_file_name: OOPS! bad filename\n");
-               printk ("  file_end->file_name[0] = %d\n",
-                       file_end->file_name[0]);
-               *name = "***BAD_FILE***";
-               return 14;
-        }
-       *name = (char *) &file_end->file_name[1];
-        return file_end->file_name[0];
-}
-
-/* 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)
-{
-       struct file_end *file_end;
-       int key;
-
-       file_end = GET_END_PTR (struct file_end, fh_data, bsize);
-       key = swap_long (file_end->extension);
-       return key;
-}
-
-/* Checksum a block, do various consistency checks and optionally return
-   the blocks type number.  DATA points to the block.  If their pointers
-   are non-null, *PTYPE and *STYPE are set to the primary and secondary
-   block types respectively.  Returns non-zero if the block is not
-   consistent. */
-
-int affs_checksum_block (int bsize, void *data, int *ptype, int *stype)
-{
-       if (ptype)
-               *ptype = swap_long (((long *) data)[0]);
-       if (stype)
-               *stype = swap_long (((long *) data)[bsize / 4 - 1]);
-       return 0;
-}
-
-static struct file_system_type affs_fs_type = {
-        affs_read_super, "affs", 1, NULL
-};
-
-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
-
+/*
+ *  linux/fs/affs/amigaffs.c
+ *
+ *  (c) 1996  Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ *  (C) 1993  Ray Burr - Amiga FFS filesystem.
+ *
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+extern struct timezone sys_tz;
+
+/*
+ * Functions for accessing Amiga-FFS structures.
+ *
+ */
+
+/* Find the next used hash entry at or after *HASH_POS in a directory's hash
+   table.  *HASH_POS is assigned that entry's number.  DIR_DATA points to
+   the directory header block in memory.  If there are no more entries,
+   0 is returned.  Otherwise, the key number in the next used hash slot
+   is returned. */
+
+int
+affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos)
+{
+       struct dir_front *dir_front = dir_data;
+       ULONG i;
+
+       for (i = *hash_pos; i < hsize; i++)
+               if (dir_front->hashtable[i] != 0)
+                       break;
+       if (i >= hsize)
+               return 0;
+       *hash_pos = i;
+       return htonl(dir_front->hashtable[i]);
+}
+
+/* Set *NAME to point to the file name in a file header block in memory
+   pointed to by FH_DATA.  The length of the name is returned. */
+
+int
+affs_get_file_name(int bsize, void *fh_data, char **name)
+{
+       struct file_end *file_end;
+
+       file_end = GET_END_PTR(struct file_end, fh_data, bsize);
+       if (file_end->file_name[0] == 0
+           || file_end->file_name[0] > 30) {
+               printk ("affs_get_file_name: OOPS! bad filename\n");
+               printk ("  file_end->file_name[0] = %d\n",
+                       file_end->file_name[0]);
+               *name = "***BAD_FILE***";
+               return 14;
+        }
+       *name = (char *) &file_end->file_name[1];
+        return file_end->file_name[0];
+}
+
+/* Find the predecessor in the hash chain */
+
+int
+affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey)
+{
+       struct buffer_head      *bh = NULL;
+       ULONG                    nextkey;
+       LONG                     ptype, stype;
+       int                      retval;
+
+       nextkey = startino->i_ino;
+       retval  = -ENOENT;
+       lock_super(startino->i_sb);
+       while (1) {
+               pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n", nextkey, startoffset);
+               if (nextkey == 0)
+                       break;
+               if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+                       break;
+               if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+                   || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
+                                           stype != ST_LINKFILE && stype != ST_LINKDIR &&
+                                           stype != ST_ROOT && stype != ST_SOFTLINK)) {
+                       printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n",
+                              ptype,stype);
+                       affs_brelse(bh);
+                       break;
+               }
+               nextkey = htonl(((ULONG *)bh->b_data)[startoffset]);
+               if (nextkey == key) {
+                       ((ULONG *)bh->b_data)[startoffset] = newkey;
+                       affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+                       mark_buffer_dirty(bh,1);
+                       affs_brelse(bh);
+                       retval = 0;
+                       break;
+               }
+               affs_brelse(bh);
+               startoffset = AFFS_I2BSIZE(startino) / 4 - 4;
+       }
+       unlock_super(startino->i_sb);
+
+       return retval;
+}
+
+/* Remove inode from link chain */
+
+int
+affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
+{
+       struct buffer_head      *bh = NULL;
+       ULONG                    nextkey;
+       ULONG                    offset;
+       LONG                     etype = 0;
+       LONG                     ptype, stype;
+       int                      retval;
+
+       offset  = AFFS_I2BSIZE(startino) / 4 - 10;
+       nextkey = startino->i_ino;
+       retval  = -ENOENT;
+       lock_super(startino->i_sb);
+       while (1) {
+               if (nextkey == 0)
+                       break;
+               pr_debug("AFFS: find_link_pred(): next key=%d\n", nextkey));
+               if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+                       break;
+               if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+                   || ptype != T_SHORT) {
+                       affs_brelse(bh);
+                       break;
+               }
+               if (!etype) {
+                       if (stype != ST_FILE && stype != ST_USERDIR) {
+                               affs_brelse(bh);
+                               break;
+                       }
+                       if (stype == ST_FILE)
+                               etype = ST_LINKFILE;
+                       else
+                               etype = ST_LINKDIR;
+               } else if (stype != etype) {
+                       affs_brelse(bh);
+                       retval = -EPERM;
+                       break;
+               }
+               nextkey = htonl(((ULONG *)bh->b_data)[offset]);
+               if (nextkey == key) {
+                       FILE_END(bh->b_data,startino)->link_chain = newkey;
+                       affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+                       mark_buffer_dirty(bh,1);
+                       affs_brelse(bh);
+                       retval = 0;
+                       break;
+               }
+               affs_brelse(bh);
+       }
+       unlock_super(startino->i_sb);
+       return retval;
+}
+
+/* Checksum a block, do various consistency checks and optionally return
+   the blocks type number.  DATA points to the block.  If their pointers
+   are non-null, *PTYPE and *STYPE are set to the primary and secondary
+   block types respectively, *HASHSIZE is set to the size of the hashtable
+   (which lets us calculate the block size).
+   Returns non-zero if the block is not consistent. */
+
+ULONG
+affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype)
+{
+       ULONG sum;
+       ULONG *p;
+
+       bsize /= 4;
+       if (ptype)
+               *ptype = htonl(((LONG *)data)[0]);
+       if (stype)
+               *stype = htonl(((LONG *)data)[bsize - 1]);
+
+       sum    = 0;
+       p      = data;
+       while (bsize--)
+               sum += htonl(*p++);
+       return sum;
+}
+
+void
+affs_fix_checksum(int bsize, void *data, int cspos)
+{
+       ULONG    ocs;
+       ULONG    cs;
+
+       cs   = affs_checksum_block(bsize,data,NULL,NULL);
+       ocs  = htonl (((ULONG *)data)[cspos]);
+       ocs -= cs;
+       ((ULONG *)data)[cspos] = htonl(ocs);
+}
+
+void
+secs_to_datestamp(int secs, struct DateStamp *ds)
+{
+       ULONG    days;
+       ULONG    minute;
+
+       secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
+       if (secs < 0)
+               secs = 0;
+       days    = secs / 86400;
+       secs   -= days * 86400;
+       minute  = secs / 60;
+       secs   -= minute * 60;
+
+       ds->ds_Days   = htonl(days);
+       ds->ds_Minute = htonl(minute);
+       ds->ds_Tick   = htonl(secs * 50);
+}
+
+int
+prot_to_mode(ULONG prot)
+{
+       int      mode = 0;
+
+       if (AFFS_UMAYWRITE(prot))
+               mode |= S_IWUSR;
+       if (AFFS_UMAYREAD(prot))
+               mode |= S_IRUSR;
+       if (AFFS_UMAYEXECUTE(prot))
+               mode |= S_IXUSR;
+       if (AFFS_GMAYWRITE(prot))
+               mode |= S_IWGRP;
+       if (AFFS_GMAYREAD(prot))
+               mode |= S_IRGRP;
+       if (AFFS_GMAYEXECUTE(prot))
+               mode |= S_IXGRP;
+       if (AFFS_OMAYWRITE(prot))
+               mode |= S_IWOTH;
+       if (AFFS_OMAYREAD(prot))
+               mode |= S_IROTH;
+       if (AFFS_OMAYEXECUTE(prot))
+               mode |= S_IXOTH;
+       
+       return mode;
+}
+
+ULONG
+mode_to_prot(int mode)
+{
+       ULONG    prot = 0;
+
+       if (mode & S_IXUSR)
+               prot |= FIBF_SCRIPT;
+       if (mode & S_IRUSR)
+               prot |= FIBF_READ;
+       if (mode & S_IWUSR)
+               prot |= FIBF_WRITE | FIBF_DELETE;
+       if (mode & S_IRGRP)
+               prot |= FIBF_GRP_READ;
+       if (mode & S_IWGRP)
+               prot |= FIBF_GRP_WRITE;
+       if (mode & S_IROTH)
+               prot |= FIBF_OTR_READ;
+       if (mode & S_IWOTH)
+               prot |= FIBF_OTR_WRITE;
+       
+       return prot;
+}
diff --git a/fs/affs/amigaffs.h b/fs/affs/amigaffs.h
deleted file mode 100644 (file)
index 457a32c..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-#ifndef AMIGAFFS_H
-#define AMIGAFFS_H
-
-/* Ugly macros to make the code pretty. */
-
-#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
-
-#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \
-                            - sizeof (struct dir_end)) / 4)
-
-static __inline__ unsigned long
-swap_long (unsigned long x)
-{
-#ifdef __i386__   /* bad check... should be endian check */
-  unsigned char *px;
-
-  px = (unsigned char *) &x;
-  return (  (px[3] <<  0)
-         | (px[2] <<  8)
-         | (px[1] << 16)
-         | (px[0] << 24));
-#else
-  return x;
-#endif
-}
-
-typedef unsigned long  ULONG;
-typedef unsigned short UWORD;
-typedef unsigned char  UBYTE;
-
-typedef long           LONG;
-typedef short          WORD;
-typedef char           BYTE;
-
-struct DateStamp
-{
-  ULONG ds_Days;
-  ULONG ds_Minute;
-  ULONG ds_Tick;
-};
-
-#define T_SHORT        2
-#define T_LIST         16
-#define T_DATA         8
-
-#define ST_FILE        -3
-#define ST_USERDIR     2
-#define ST_ROOT        1
-#define ST_SOFTLINK    3
-#define ST_LINKFILE    -4
-#define ST_LINKDIR     4
-
-#define PROT_ARCHIVE        (1<<4)
-#define PROT_READ           (1<<3)
-#define PROT_WRITE          (1<<2)
-#define PROT_EXECUTE        (1<<1)
-#define PROT_DELETE         (1<<0)
-
-#define PROT_OTR_READ       (1<<15)
-#define PROT_OTR_WRITE      (1<<14)
-#define PROT_OTR_EXECUTE    (1<<13)
-#define PROT_OTR_DELETE     (1<<12)
-
-#define PROT_GRP_READ       (1<<11)
-#define PROT_GRP_WRITE      (1<<10)
-#define PROT_GRP_EXECUTE    (1<<9)
-#define PROT_GRP_DELETE     (1<<8)
-
-struct ffs_root_front
-{
-  LONG primary_type;
-  ULONG spare1[2];
-  ULONG hash_size;
-  ULONG spare2;
-  ULONG checksum;
-};
-
-struct ffs_root_end
-{
-  LONG bm_flag;
-  ULONG bm_keys[25];
-  ULONG bm_extend;
-  struct DateStamp dir_altered;
-  UBYTE disk_name[40];
-  struct DateStamp disk_altered;
-  struct DateStamp disk_made;
-  ULONG spare1[3];
-  LONG secondary_type;
-};
-
-struct dir_front
-{
-  LONG primary_type;
-  ULONG own_key;
-  ULONG spare1[3];
-  ULONG checksum;
-  ULONG hash_table[0];
-};
-
-struct dir_end
-{
-  ULONG spare1;
-  UWORD uid;
-  UWORD gid;
-  ULONG protect;
-  ULONG spare2;
-  UBYTE comment[92];
-  struct DateStamp created;
-  UBYTE dir_name[64];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG spare3;
-  LONG secondary_type;
-};
-
-struct file_front
-{
-  LONG primary_type;
-  ULONG own_key;
-  ULONG block_count;
-  ULONG unknown1;
-  ULONG first_data;
-  ULONG checksum;
-  ULONG blocks[0];
-};
-
-struct file_end
-{
-  ULONG spare1;
-  UWORD uid;
-  UWORD gid;
-  ULONG protect;
-  ULONG byte_size;
-  UBYTE comment[92];
-  struct DateStamp created;
-  UBYTE file_name[64];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG extension;
-  LONG secondary_type;
-};
-
-struct data_front
-{
-  LONG primary_type;
-  ULONG header;
-  ULONG seq_num;
-  ULONG data_size;
-  ULONG next_data;
-  ULONG checksum;
-};
-
-struct symlink_front
-{
-  LONG primary_type;
-  ULONG own_key;
-  LONG unused[3];
-  ULONG checksum;
-  UBYTE symname[0];
-};
-
-struct symlink_end
-{
-  ULONG spare1;
-  UWORD uid;
-  UWORD gid;
-  ULONG protect;
-  ULONG spare2;
-  UBYTE comment[92];
-  struct DateStamp created;
-  UBYTE link_name[64];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG spare3;
-  LONG secondary_type;
-};
-
-struct hardlink_front
-{
-  LONG primary_type;
-  ULONG own_key;
-  LONG unused[3];
-  ULONG checksum;
-};
-
-struct hardlink_end
-{
-  ULONG spare1;
-  UWORD uid;
-  UWORD gid;
-  ULONG protect;
-  ULONG spare2;
-  UBYTE comment[92];
-  struct DateStamp created;
-  UBYTE link_name[32];
-  ULONG spare3;
-  ULONG original;
-  ULONG link_chain;
-  ULONG spare4[5];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG spare5;
-  LONG secondary_type;
-};
-
-#endif
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c
new file mode 100644 (file)
index 0000000..8a14c3e
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ *  linux/fs/affs/bitmap.c
+ *
+ *  (c) 1996 Hans-Joachim Widmaier
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/amigaffs.h>
+#include <linux/locks.h>
+
+#include <asm/bitops.h>
+
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+int
+affs_count_free_bits(int blocksize, const UBYTE *data)
+{
+  int   free;
+  int   i;
+
+  free = 0;
+  for (i = 0; i < blocksize; i++) {
+    free  += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF];
+  }
+
+  return free;
+}
+
+int
+affs_count_free_blocks(struct super_block *s)
+{
+       int      free;
+       int      i;
+
+       pr_debug("AFFS: count_free_blocks()\n");
+
+       free = 0;
+       if (s->u.affs_sb.s_flags & SF_BM_VALID) {
+               for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
+                       free += s->u.affs_sb.s_bitmap[i].bm_free;
+               }
+       }
+       return free;
+}
+
+void
+affs_free_block(struct super_block *sb, LONG block)
+{
+       int                      bmap;
+       int                      bit;
+       ULONG                    blk;
+       struct affs_bm_info     *bm;
+
+       pr_debug("AFFS: free_block(%d)\n",block);
+
+       blk    = block - sb->u.affs_sb.s_reserved;
+       bmap   = blk / (sb->s_blocksize * 8 - 32);
+       bit    = blk % (sb->s_blocksize * 8 - 32);
+       bm     = &sb->u.affs_sb.s_bitmap[bmap];
+       if (bmap >= sb->u.affs_sb.s_bm_count || bit >= bm->bm_size) {
+               printk("AFFS: free_block(): block %d outside partition.\n",block);
+               return;
+       }
+       blk  = 0;
+       set_bit(bit & 31,&blk);
+
+       lock_super(sb);
+       if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
+               printk("AFFS: free_block(): block %d is already free.\n",block);
+       else {
+               bm->bm_free++;
+               ((ULONG *)bm->bm_bh->b_data)[0] = ntohl(htonl(((ULONG *)bm->bm_bh->b_data)[0]) - blk);
+               mark_buffer_dirty(bm->bm_bh,1);
+               sb->s_dirt = 1;
+       }
+       unlock_super(sb);
+}
+
+static ULONG
+affs_balloc(struct inode *inode, int zone_no)
+{
+       ULONG                    w;
+       ULONG                   *bm;
+       int                      fb;
+       int                      i;
+       int                      fwb;
+       ULONG                    block;
+       struct affs_zone        *zone;
+       struct super_block      *sb;
+
+       sb   = inode->i_sb;
+       zone = &sb->u.affs_sb.s_zones[zone_no];
+
+       if (!zone || !zone->z_bm || !zone->z_bm->bm_bh)
+               return 0;
+       
+       pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
+
+       bm = (ULONG *)zone->z_bm->bm_bh->b_data;
+repeat:
+       fb = (zone->z_bm->bm_size + 31) >> 5;
+       for (i = zone->z_start; i <= fb; i++) {
+               if (bm[i])
+                       goto found;
+       }
+       return 0;
+
+found:
+       fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
+       lock_super(sb);
+       zone->z_start = i;
+       w   = htonl(bm[i]);
+       fb  = find_first_one_bit(&w,32);
+       if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+               unlock_super(sb);
+               printk("AFFS: balloc(): empty block disappeared somehow\n");
+               goto repeat;
+       }
+       block = fwb + fb;
+       zone->z_bm->bm_free--;
+
+       /* prealloc as much as possible within this word, but not for headers */
+
+       if (zone_no) {
+               while (inode->u.affs_i.i_pa_cnt < MAX_PREALLOC && ++fb < 32) {
+                       fb = find_next_one_bit(&w,32,fb);
+                       if (fb > 31)
+                               break;
+                       if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+                               printk("AFFS: balloc(): empty block disappeared\n");
+                               break;
+                       }
+                       inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
+                       inode->u.affs_i.i_pa_last &= MAX_PREALLOC - 1;
+                       inode->u.affs_i.i_pa_cnt++;
+                       zone->z_bm->bm_free--;
+               }
+       }
+       w    -= htonl(bm[i]);
+       bm[0] = ntohl(htonl(bm[0]) + w);
+       unlock_super(sb);
+       mark_buffer_dirty(zone->z_bm->bm_bh,1);
+
+       return block;
+}
+
+static void
+affs_find_new_zone(struct super_block *sb,struct affs_zone *z, int minfree, int start)
+{
+       struct affs_bm_info     *bm;
+       int                      offs;
+       int                      zone;
+       int                      free;
+       int                      len;
+
+       pr_debug("AFFS: find_new_zone()\n");
+
+       lock_super(sb);
+
+       zone    = start;
+       z->z_bm = NULL;
+       while (1) {
+               if (zone >= sb->u.affs_sb.s_num_zones) {
+                       zone = 0;
+                       continue;
+               }
+
+               if (!set_bit(zone,sb->u.affs_sb.s_zonemap)) {
+                       bm   = &sb->u.affs_sb.s_bitmap[zone >> (sb->s_blocksize_bits - 8)];
+                       offs = zone * 256 & (sb->s_blocksize - 1);
+                       len  = bm->bm_size / 8 - offs;
+                       if (len > 256)
+                               len = 256;
+                       offs += 4;
+                       free  = affs_count_free_bits(len,(char *)bm->bm_bh->b_data + offs);
+                       if (free && (100 * free) / (len * 8) > minfree) {
+                               z->z_bm       = bm;
+                               z->z_start    = offs / 4;
+                               z->z_ino      = 0;
+                               z->z_zone_no  = zone;
+                               pr_debug("  ++ found zone (%d) in bh %d at offset %d with %d free blocks\n",
+                                        zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free);
+                               break;
+                       }
+                       clear_bit(zone,sb->u.affs_sb.s_zonemap);
+               }
+
+               /* Skip to next possible zone */
+
+               pr_debug("  ++ Skipping to next zone\n");
+               if (++zone == start)
+                       break;
+       }
+       unlock_super(sb);
+       return;
+}
+
+LONG
+affs_new_header(struct inode *inode)
+{
+       struct affs_zone        *zone;
+       LONG                     block;
+       struct super_block      *sb;
+       struct buffer_head      *bh;
+
+       sb   = inode->i_sb;
+       zone = &sb->u.affs_sb.s_zones[0];
+
+       /* We try up to 3 times to find a free block:
+        * If there is no more room in the current header zone,
+        * we try to get a new one and allocate the block there.
+        * If there is no zone with at least AFFS_HDR_MIN_FREE
+        * percent of free blocks, we try to find a zone with
+        * at least one free block.
+        */
+
+       if (!(block = affs_balloc(inode,0))) {
+               clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+               affs_find_new_zone(sb,zone,AFFS_HDR_MIN_FREE,(sb->u.affs_sb.s_num_zones + 1) / 2);
+               if (!(block = affs_balloc(inode,0))) {
+                       clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+                       affs_find_new_zone(sb,zone,0,(sb->u.affs_sb.s_num_zones + 1) / 2);
+                       if (!(block = affs_balloc(inode,0)))
+                               return 0;
+               }
+       }
+       if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
+               printk("AFFS: balloc(): cannot read block %d\n",block);
+               return 0;
+       }
+       memset(bh->b_data,0,sb->s_blocksize);
+       mark_buffer_uptodate(bh,1);
+       mark_buffer_dirty(bh,1);
+       affs_brelse(bh);
+
+       return block;
+}
+
+LONG
+affs_new_data(struct inode *inode)
+{
+       int                      empty, old;
+       unsigned long            oldest;
+       struct affs_zone        *zone;
+       struct super_block      *sb;
+       struct buffer_head      *bh;
+       int                      i = 0;
+       LONG                     block;
+
+       pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
+
+       sb = inode->i_sb;
+       lock_super(sb);
+       if (inode->u.affs_i.i_pa_cnt) {
+               inode->u.affs_i.i_pa_cnt--;
+               unlock_super(sb);
+               block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
+               inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
+               goto init_block;
+       }
+       unlock_super(sb);
+repeat:
+       oldest = jiffies;
+       old    = 0;
+       empty  = 0;
+       zone   = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+       if (zone->z_ino == inode->i_ino) {
+               i = inode->u.affs_i.i_zone;
+               goto found;
+       }
+       for (i = 1; i < MAX_ZONES; i++) {
+               zone = &sb->u.affs_sb.s_zones[i];
+               if (!empty && zone->z_bm && !zone->z_ino)
+                       empty = i;
+               if (zone->z_bm && zone->z_lru_time < oldest) {
+                       old    = i;
+                       oldest = zone->z_lru_time;
+               }
+       }
+       if (empty)
+               i = empty;
+       else if (old)
+               i = old;
+       else
+               return affs_new_header(inode);
+
+       inode->u.affs_i.i_zone = i;
+       zone->z_ino            = inode->i_ino;
+
+found:
+       zone = &sb->u.affs_sb.s_zones[i];
+       if (!(block = affs_balloc(inode,i))) {                          /* Zone is full */
+               clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+               affs_find_new_zone(sb,zone,AFFS_DATA_MIN_FREE,sb->u.affs_sb.s_nextzone);
+               sb->u.affs_sb.s_nextzone = zone->z_zone_no + 1;
+               goto repeat;
+       }
+
+init_block:
+       if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
+               printk("AFFS: balloc(): cannot read block %u\n",block);
+               return 0;
+       }
+       memset(bh->b_data,0,sb->s_blocksize);
+       mark_buffer_uptodate(bh,1);
+       mark_buffer_dirty(bh,1);
+       affs_brelse(bh);
+
+       return block;
+}
+
+void
+affs_make_zones(struct super_block *sb)
+{
+       int      i, j;
+
+       pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_zones);
+
+       j = (sb->u.affs_sb.s_num_zones + 1) / 2;
+
+       affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[0],AFFS_HDR_MIN_FREE,j);
+       for (i = 1; i < MAX_ZONES; i++) {
+               affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[i],AFFS_DATA_MIN_FREE,j);
+               j = sb->u.affs_sb.s_zones[i].z_zone_no + 1;
+       }
+}
dissimilarity index 66%
index 5668fed..165e767 100644 (file)
-/*
- *  linux/fs/affs/dir.c
- *
- *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
- *
- *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
- *
- *  (C) 1991  Linus Torvalds - minix filesystem
- *
- *  affs directory handling functions
- */
-
-#include <linux/errno.h>
-
-#include <asm/segment.h>
-
-#include <linux/fs.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/affs_fs.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-
-static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
-
-struct file_operations affs_dir_operations = {
-       NULL,                   /* lseek - default */
-       NULL,                   /* read */
-       NULL,                   /* write - bad */
-       affs_readdir,           /* readdir */
-       NULL,                   /* select - default */
-       NULL,                   /* ioctl - default */
-       NULL,                   /* mmap */
-       NULL,                   /* no special open code */
-       NULL,                   /* no special release code */
-       NULL                    /* fsync */
-};
-
-/*
- * directories can handle most operations...
- */
-struct inode_operations affs_dir_inode_operations = {
-       &affs_dir_operations,   /* default directory file-ops */
-       NULL,                   /* create */
-       affs_lookup,            /* lookup */
-       NULL,                   /* link */
-       NULL,                   /* unlink */
-       NULL,                   /* symlink */
-       NULL,                   /* mkdir */
-       NULL,                   /* rmdir */
-       NULL,                   /* mknod */
-       NULL,                   /* rename */
-       NULL,                   /* readlink */
-       NULL,                   /* follow_link */
-       NULL,                   /* bmap */
-       NULL,                   /* truncate */
-       NULL                    /* permission */
-};
-
-/* This is used to speed up lookup.  Without this we would need to
-make a linear search of the directory to find the file that the
-directory read just returned.  This is a single element cache. */
-
-/* struct lookup_cache cache = {0,}; */
-
-static int affs_readdir(struct inode * inode, struct file * filp,
-       void * dirent, filldir_t filldir)
-{
-       int i, j, chain_pos, hash_pos, reclen, ino;
-       char *name;
-       struct buffer_head *dir_bh;
-       struct buffer_head *fh_bh;
-       void *dir_data;
-       void *fh_data;
-
-#ifdef DEBUG
-       printk ("AFFS: readdir: inode=%d f_pos=%d\n",
-               inode->i_ino, filp->f_pos);
-#endif
-       
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
-       while ((unsigned long)filp->f_pos < 2) {
-               if (filp->f_pos == 0) {
-                       if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
-                               return 0;
-               } else {
-                       i = affs_parent_ino (inode);
-                       if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
-                               return 0;
-               }
-               filp->f_pos++;
-       }
-       /* No caching here.  I've got 16 megs why should I care?  :-) */
-       chain_pos = (filp->f_pos - 2) & 0xffff;
-       if (chain_pos == 0xffff)
-               return 0;
-       hash_pos = (filp->f_pos - 2) >> 16;
-#ifdef DEBUG
-       printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
-#endif
-       if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data)))
-               return 0;
-       /* HASH_POS should already be on a used entry unless it is
-          the first read of the directory.  Will this break the
-          dirtell thing somehow? */
-       i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data,
-                                      &hash_pos);
-       j = chain_pos;
-       for (;;) {
-               if (i <= 0) {
-#ifdef DEBUG
-                       printk ("AFFS: bad f_pos in readdir\n");
-#endif
-                       brelse (dir_bh);
-                       return 0;
-               }
-               ino = i;
-               if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
-                       brelse (dir_bh);
-                       return 0;
-               }
-               i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
-               if (j == 0) {
-                       j = 1;
-                       if (i <= 0) {
-                               hash_pos++;
-                               i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
-                                                              dir_data, &hash_pos);
-                               if (i <= 0)
-                                       chain_pos = 0xffff;
-                               else
-                                       chain_pos = 0;
-                       } else
-                               chain_pos++;
-                       reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
-                                                    fh_data, &name);
-                       if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
-                               brelse (fh_bh);
-                               brelse (dir_bh);
-                               return 0;
-                       }
-                       filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
-               }
-               brelse (fh_bh);
-               j--;
-       }
-}
+/*
+ *  linux/fs/affs/dir.c
+ *
+ *  (c) 1996  Hans-Joachim Widmaier - Modifications for larger blocks
+ *             and hard links.
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ *
+ *  affs directory handling functions
+ *
+ */
+
+#include <asm/segment.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count);
+
+static struct file_operations affs_dir_operations = {
+       NULL,                   /* lseek - default */
+       affs_dir_read,          /* read */
+       NULL,                   /* write - bad */
+       affs_readdir,           /* readdir */
+       NULL,                   /* select - default */
+       NULL,                   /* ioctl - default */
+       NULL,                   /* mmap */
+       NULL,                   /* no special open code */
+       NULL,                   /* no special release code */
+       file_fsync              /* default fsync */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations affs_dir_inode_operations = {
+       &affs_dir_operations,   /* default directory file-ops */
+       affs_create,            /* create */
+       affs_lookup,            /* lookup */
+       affs_link,              /* link */
+       affs_unlink,            /* unlink */
+       affs_symlink,           /* symlink */
+       affs_mkdir,             /* mkdir */
+       affs_rmdir,             /* rmdir */
+       NULL,                   /* mknod */
+       affs_rename,            /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       affs_dir_truncate,      /* truncate */
+       NULL                    /* permissions */
+};
+
+static int
+affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+       return -EISDIR;
+}
+
+static int
+affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
+{
+       int                      j, namelen;
+       LONG                     i;
+       ULONG                    hash_pos;
+       ULONG                    chain_pos;
+       unsigned long            ino;
+       unsigned long                    old;
+       int stored;
+       char *name;
+       struct buffer_head *dir_bh;
+       struct buffer_head *fh_bh;
+       struct inode       *dir;
+
+       pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
+       
+
+       if (!inode || !S_ISDIR(inode->i_mode))
+               return -EBADF;
+
+       stored = 0;
+       dir_bh = NULL;
+       fh_bh  = NULL;
+       dir    = NULL;
+       old    = filp->f_pos & 0x80000000;
+       filp->f_pos &= 0x7FFFFFFF;
+
+       if (filp->f_pos == 0) {
+               filp->private_data = (void *)0;
+               if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+                       return 0;
+               }
+               ++filp->f_pos;
+               stored++;
+       }
+       if (filp->f_pos == 1) {
+               if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+                       filp->f_pos |= 0x80000000;
+                       return stored;
+               }
+               filp->f_pos = 2;
+               stored++;
+       }
+
+       /* Read original if this is a link */
+       ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+       if (!(dir = iget(inode->i_sb,ino)))
+               return stored;
+       
+       chain_pos = (filp->f_pos - 2) & 0xffff;
+       hash_pos  = (filp->f_pos - 2) >> 16;
+       if (chain_pos == 0xffff) {
+               printk("AFFS: more than 65535 entries in chain\n");
+               chain_pos = 0;
+               hash_pos++;
+               filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+       }
+       if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
+               goto readdir_done;
+
+       while (!stored || !old) {
+               while (hash_pos < AFFS_I2HSIZE(inode) &&
+                    !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
+                       hash_pos++;
+               if (hash_pos >= AFFS_I2HSIZE(inode))
+                       goto readdir_done;
+               
+               i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
+               j = chain_pos;
+               /* If the directory hasn't changed since the last call to readdir(),
+                * we can jump directly to where we left off.
+                */
+               if (filp->private_data && filp->f_version == dir->i_version) {
+                       i = (ULONG)filp->private_data;
+                       j = 0;
+                       pd_debug("AFFS: readdir() left off=%lu\n",i);
+               }
+               filp->f_version = dir->i_version;
+               pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+               while (i) {
+                       if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
+                               printk("AFFS: readdir: Can't get block %d\n",i);
+                               goto readdir_done;
+                       }
+                       ino = i;
+                       i   = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
+                       if (j == 0)
+                               break;
+                       affs_brelse(fh_bh);
+                       fh_bh = NULL;
+                       j--;
+               }
+               if (fh_bh) {
+                       namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
+                       pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
+                       filp->private_data = (void *)ino;
+                       if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+                               goto readdir_done;
+                       filp->private_data = (void *)i;
+                       affs_brelse(fh_bh);
+                       fh_bh = NULL;
+                       stored++;
+               }
+               if (i == 0) {
+                       hash_pos++;
+                       chain_pos = 0;
+               } else
+                       chain_pos++;
+               filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+       }
+
+readdir_done:
+       filp->f_pos |= old;
+       affs_brelse(dir_bh);
+       affs_brelse(fh_bh);
+       iput(dir);
+       pr_debug("AFFS: readdir()=%d\n",stored);
+       return stored;
+}
+
+void
+affs_dir_truncate(struct inode *inode)
+{
+       printk("AFFS: dir_truncate()\n");
+}
index 50f126e..585093e 100644 (file)
@@ -1,6+1,8 @@
 /*
  *  linux/fs/affs/file.c
  *
+ *  (c) 1996  Hans-Joachim Widmaier - Rewritten
+ *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
 
 #include <asm/segment.h>
 #include <asm/system.h>
-
 #include <linux/sched.h>
 #include <linux/affs_fs.h>
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/locks.h>
-
 #include <linux/dirent.h>
-
-#define        NBUF    16
+#include <linux/fs.h>
+#include <linux/amigaffs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-#include <linux/fs.h>
-#include <linux/affs_fs.h>
+static int affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count);
+static int affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count);
+static int affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count);
+static void affs_release_file(struct inode *inode, struct file *filp);
 
-#include "amigaffs.h"
-
-int affs_file_read(struct inode *, struct file *, char *, int);
-
-/*
- * We have mostly NULL's here: the current defaults are ok for
- * the affs filesystem.
- */
-struct file_operations affs_file_operations = {
+static struct file_operations affs_file_operations = {
        NULL,                   /* lseek - default */
-       affs_file_read,         /* read */
-       NULL,                   /* write */
+       generic_file_read,      /* read */
+       affs_file_write,        /* write */
        NULL,                   /* readdir - bad */
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
        generic_file_mmap,      /* mmap */
        NULL,                   /* no special open is needed */
-       NULL,                   /* release */
-       NULL                    /* can't fsync */
+       affs_release_file,      /* release */
+       file_fsync              /* brute force, but works */
 };
 
 struct inode_operations affs_file_inode_operations = {
@@ -65,75+61,229 @@ struct inode_operations affs_file_inode_operations = {
        NULL,                   /* rename */
        NULL,                   /* readlink */
        NULL,                   /* follow_link */
-       NULL /* affs_bmap */,           /* bmap */
-       NULL,                   /* truncate */
-       NULL                    /* permission */
+       generic_readpage,       /* readpage */
+       NULL,                   /* writepage */
+       affs_bmap,              /* bmap */
+       affs_truncate,          /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* smap */
 };
 
-static int affs_smap(struct inode *inode, int block)
-{
-       struct buffer_head *bh;
-       int key;
-       void *fh_data;
+static struct file_operations affs_file_operations_ofs = {
+       NULL,                   /* lseek - default */
+       affs_file_read_ofs,     /* read */
+       affs_file_write_ofs,    /* write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select - default */
+       NULL,                   /* ioctl - default */
+       NULL,                   /* mmap */
+       NULL,                   /* no special open is needed */
+       NULL,                   /* release */
+       file_fsync              /* brute force, but works */
+};
+
+struct inode_operations affs_file_inode_operations_ofs = {
+       &affs_file_operations_ofs,      /* default file operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       affs_truncate_ofs,      /* truncate */
+       NULL,                   /* permission */
+       NULL                    /* smap */
+};
 
-/* FIXME */
-#define KEY_SLOTS_PER_BLOCK 72
+int
+affs_bmap(struct inode *inode, LONG block)
+{
+       struct buffer_head      *bh;
+       LONG                     ext, key;
+       LONG                     ptype, stype;
 
-#ifdef DEBUG
-       printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block);
-#endif
+       pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
 
        if (block < 0) {
-               printk("affs_smap: block < 0");
+               printk("affs_bmap: block < 0\n");
                return 0;
        }
 
-       key = inode->i_ino;
+       /* If this is a hard link, quietly exchange the inode with the original */
+
+       key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+
+       ext = block / AFFS_I2HSIZE(inode);
+       if (ext) {
+               if (ext > inode->u.affs_i.i_max_ext)
+                       ext = inode->u.affs_i.i_max_ext;
+               if (ext)
+                       key = inode->u.affs_i.i_ext[ext -  1];
+               block -= ext * AFFS_I2HSIZE(inode);
+       }
+
        for (;;) {
-               bh = affs_pread (inode, key, &fh_data);
+               bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
                if (!bh)
                        return 0;
-               if (block < KEY_SLOTS_PER_BLOCK)
+               if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
+                   (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE) {
+                       affs_brelse(bh);
+                       return 0;
+               }
+               if (block < AFFS_I2HSIZE(inode))
                        break;
-               block -= KEY_SLOTS_PER_BLOCK;
-               key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data);
-#ifdef DEBUG
-               printk ("affs_smap: reading extension block %d\n", key);
-#endif
-               brelse (bh);
-       }
-       key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data,
-                                 (KEY_SLOTS_PER_BLOCK - 1) - block);
-       brelse (bh);
-
-#ifdef DEBUG
-       printk ("affs_smap: key=%d\n", key);
-#endif
+               block -= AFFS_I2HSIZE(inode);
+               key    = htonl(FILE_END(bh->b_data,inode)->extension);
+               affs_brelse(bh);
+               if (ext < EXT_CACHE_SIZE - 1) {
+                       inode->u.affs_i.i_ext[ext] = key;
+                       inode->u.affs_i.i_max_ext  = ++ext;
+               }
+       }
+       key = AFFS_GET_HASHENTRY(bh->b_data,(AFFS_I2HSIZE(inode) - 1) - block);
+       affs_brelse(bh);
        return key;
 }
 
-/*
- * 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 compatibility reasons with older
- * versions.
+struct buffer_head *
+affs_getblock(struct inode *inode, LONG block)
+{
+       struct buffer_head      *bh;
+       struct buffer_head      *ebh;
+       LONG                     key;
+       LONG                     ext;
+       LONG                     cnt, j, pt;
+
+       pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+
+       if (block < 0)
+               return NULL;
+       key = inode->i_ino;
+       pt  = T_SHORT;
+
+       ext = block / AFFS_I2HSIZE(inode);
+       if (ext) {
+               if (ext > inode->u.affs_i.i_max_ext)
+                       ext = inode->u.affs_i.i_max_ext;
+               if (ext) {
+                       key    = inode->u.affs_i.i_ext[ext - 1];
+                       block -= ext * AFFS_I2HSIZE(inode);
+                       pt     = T_LIST;
+               }
+       }
+
+       for (;;) {
+               bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+               if (!bh)
+                       return NULL;
+               if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
+                   cnt != pt || j != ST_FILE) {
+                       printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+                              pt == T_SHORT ? "file header" : "extension block");
+                       affs_brelse(bh);
+                       return NULL;
+               }
+               j = htonl(((struct file_front *)bh->b_data)->block_count);
+               while (j < AFFS_I2HSIZE(inode) && j <= block) {
+                       key = affs_new_data(inode);
+                       if (!key)
+                               break;
+                       lock_super(inode->i_sb);
+                       if (AFFS_BLOCK(bh->b_data,inode,j)) {
+                               unlock_super(inode->i_sb);
+                               printk("AFFS: getblock(): block already allocated\n");
+                               affs_free_block(inode->i_sb,key);
+                               j++;
+                               continue;
+                       }
+                       unlock_super(inode->i_sb);
+                       AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
+                       j++;
+               }
+               if (pt == T_SHORT)
+                       ((struct file_front *)bh->b_data)->first_data =
+                                                               AFFS_BLOCK(bh->b_data,inode,0);
+               ((struct file_front *)bh->b_data)->block_count = ntohl(j);
+               affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+               mark_buffer_dirty(bh,1);
+
+               if (block < j)
+                       break;
+               if (j < AFFS_I2HSIZE(inode)) {
+                       affs_brelse(bh);
+                       return NULL;
+               }
+
+               block -= AFFS_I2HSIZE(inode);
+               key    = htonl(FILE_END(bh->b_data,inode)->extension);
+               if (!key) {
+                       key = affs_new_header(inode);
+                       if (!key) {
+                               affs_brelse(bh);
+                               return NULL;
+                       }
+                       ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+                       if (!ebh) {
+                               affs_free_block(inode->i_sb,key);
+                               return NULL;
+                       }
+                       ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
+                       ((struct file_front *)ebh->b_data)->own_key      = ntohl(key);
+                       FILE_END(ebh->b_data,inode)->secondary_type      = ntohl(ST_FILE);
+                       FILE_END(ebh->b_data,inode)->parent              = ntohl(inode->i_ino);
+                       affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+                       FILE_END(bh->b_data,inode)->extension = ntohl(key);
+                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+                       mark_buffer_dirty(bh,1);
+                       affs_brelse(bh);
+                       bh = ebh;
+               }
+               affs_brelse(bh);
+               pt = T_LIST;
+               if (ext < EXT_CACHE_SIZE - 1) {
+                       inode->u.affs_i.i_ext[ext] = key;
+                       inode->u.affs_i.i_max_ext  = ++ext;
+               }
+       }
+       key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+       affs_brelse(bh);
+       if (!key)
+               return NULL;
+
+       return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+}
+
+/* This could be made static, regardless of what the former comment said.
+ * You cannot directly read affs directories.
  */
-int affs_file_read(struct inode * inode, struct file * filp,
-                  char * buf, int count)
+
+static int
+affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count)
 {
        char *start;
        int left, offset, size, sector;
+       int blocksize;
        struct buffer_head *bh;
        void *data;
 
+       pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
+
        if (!inode) {
                printk("affs_file_read: inode = NULL\n");
                return -EINVAL;
        }
+       blocksize = AFFS_I2BSIZE(inode) - 24;
        if (!(S_ISREG(inode->i_mode))) {
-#ifdef DEBUG
-               printk("affs_file_read: mode = %07o\n",inode->i_mode);
-#endif
+               pr_debug("affs_file_read: mode = %07o\n",inode->i_mode);
                return -EINVAL;
        }
        if (filp->f_pos >= inode->i_size || count <= 0)
@@ -141,34+291,296 @@ int affs_file_read(struct inode * inode, struct file * filp,
 
        start = buf;
        for (;;) {
-               left = MIN (inode->i_size - filp->f_pos,
-                           count - (buf - start));
+               left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
                if (!left)
                        break;
-               sector = affs_smap (inode, filp->f_pos >> AFFS_BLOCK_BITS);
+               sector = affs_bmap(inode,(ULONG)filp->f_pos / blocksize);
                if (!sector)
                        break;
-               offset = filp->f_pos & (AFFS_BLOCK_SIZE - 1);
-               bh = affs_pread (inode, sector, &data);
+               offset = (ULONG)filp->f_pos % blocksize;
+               bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
                if (!bh)
                        break;
-               size = MIN (AFFS_BLOCK_SIZE - offset, left);
+               data = bh->b_data + 24;
+               size = MIN(blocksize - offset,left);
                filp->f_pos += size;
-               memcpy_tofs (buf, data + offset, size);
+               memcpy_tofs(buf,data + offset,size);
                buf += size;
-               brelse (bh);
+               affs_brelse(bh);
        }
        if (start == buf)
                return -EIO;
        return buf - start;
+}
+
+static int
+affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count)
+{
+       off_t                    pos;
+       int                      written;
+       int                      c;
+       int                      blocksize;
+       struct buffer_head      *bh;
+       struct inode            *ino;
+       char                    *p;
+
+       pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+               (unsigned long)filp->f_pos,count);
 
-#if 0
-       if (filp->f_pos == 0 && count > 0) {
-               put_fs_byte ('X', buf++);
-               filp->f_pos++;
-               return 1;
+       ino = NULL;
+       if (!inode) {
+               printk("AFFS: file_write(): inode=NULL\n");
+               return -EINVAL;
+       }
+       if (inode->u.affs_i.i_original) {
+               ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+               if (!ino) {
+                       printk("AFFS: could not follow link from inode %lu to %d\n",
+                              inode->i_ino,inode->u.affs_i.i_original);
+                       return -EINVAL;
+               }
+               inode = ino;
+       }
+       if (!S_ISREG(inode->i_mode)) {
+               printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+               iput(inode);
+               return -EINVAL;
+       }
+       if (filp->f_flags & O_APPEND) {
+               pos = inode->i_size;
+       } else
+               pos = filp->f_pos;
+       written   = 0;
+       blocksize = AFFS_I2BSIZE(inode);
+
+       while (written < count) {
+               bh = affs_getblock(inode,pos / blocksize);
+               if (!bh) {
+                       if (!written)
+                               written = -ENOSPC;
+                       break;
+               }
+               c = blocksize - (pos % blocksize);
+               if (c > count - written)
+                       c = count - written;
+               if (c != blocksize && !buffer_uptodate(bh)) {
+                       ll_rw_block(READ,1,&bh);
+                       wait_on_buffer(bh);
+                       if (!buffer_uptodate(bh)) {
+                               affs_brelse(bh);
+                               if (!written)
+                                       written = -EIO;
+                               break;
+                       }
+               }
+               p = (pos % blocksize) + bh->b_data;
+               memcpy_fromfs(p,buf,c);
+               update_vm_cache(inode,pos,p,c);
+               mark_buffer_uptodate(bh,1);
+               mark_buffer_dirty(bh,0);
+               affs_brelse(bh);
+               pos     += c;
+               written += c;
+               buf     += c;
+       }
+       if (pos > inode->i_size)
+               inode->i_size = pos;
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       filp->f_pos    = pos;
+       inode->i_dirt  = 1;
+       iput(ino);
+       return written;
+}
+
+static int
+affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
+{
+       pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+               (unsigned long)filp->f_pos,count);
+
+       return -ENOSPC;
+}
+
+void
+affs_truncate(struct inode *inode)
+{
+       struct buffer_head      *bh;
+       struct inode            *ino;
+       LONG     first;
+       LONG     block;
+       LONG     key;
+       LONG    *keyp;
+       LONG     ekey;
+       LONG     ptype, stype;
+       int      freethis;
+       int      ext;
+
+       pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+
+       ino = NULL;
+       if (inode->u.affs_i.i_original) {
+               ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+               if (!ino) {
+                       printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+                              inode->i_ino,inode->u.affs_i.i_original);
+                       return;
+               }
+               inode = ino;
+       }
+       first = (inode->i_size + AFFS_I2BSIZE(inode) - 1) / AFFS_I2BSIZE(inode);
+       ekey  = inode->i_ino;
+       ext   = 0;
+
+       while (ekey) {
+               if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
+                       printk("AFFS: truncate(): Can't read block %d\n",ekey);
+                       break;
+               }
+               ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
+               stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+               if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
+                   LINK_END(bh->b_data,inode)->original == 0) {
+                       pr_debug("AFFS: truncate(): dumping link\n");
+                       affs_brelse(bh);
+                       break;
+               }
+               if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
+                       printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
+                               ptype,stype);
+                       affs_brelse(bh);
+                       break;
+               }
+               /* Do not throw away file header */
+               freethis = first == 0 && ekey != inode->i_ino;
+               for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+                       keyp = &AFFS_BLOCK(bh->b_data,inode,block);
+                       key  = htonl(*keyp);
+                       if (key) {
+                               *keyp = 0;
+                               affs_free_block(inode->i_sb,key);
+                       } else {
+                               block = AFFS_I2HSIZE(inode);
+                               break;
+                       }
+               }
+               keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
+               key  = htonl(*keyp);
+               if (first <= AFFS_I2HSIZE(inode)) {
+                       ((struct file_front *)bh->b_data)->block_count = htonl(first);
+                       first = 0;
+                       *keyp = 0;
+               } else {
+                       first -= AFFS_I2HSIZE(inode);
+               }
+               if (freethis) {         /* Don't bother fixing checksum */
+                       affs_brelse(bh);
+                       affs_free_block(inode->i_sb,ekey);
+               } else {
+                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+                       mark_buffer_dirty(bh,1);
+                       affs_brelse(bh);
+               }
+               ekey = key;
+       }
+       inode->u.affs_i.i_max_ext = 0;          /* invalidate cache */
+       iput(ino);
+}
+
+void
+affs_truncate_ofs(struct inode *inode)
+{
+       struct buffer_head      *bh;
+       struct inode            *ino;
+       LONG     first;
+       LONG     block;
+       LONG     key;
+       LONG    *keyp;
+       LONG     ekey;
+       LONG     ptype, stype;
+       int      freethis;
+       int      blocksize;
+
+       pr_debug("AFFS: file_truncate_ofs(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+
+       ino = NULL;
+       if (inode->u.affs_i.i_original) {
+               ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+               if (!ino) {
+                       printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+                              inode->i_ino,inode->u.affs_i.i_original);
+                       return;
+               }
+               inode = ino;
+       }
+       blocksize = AFFS_I2BSIZE(inode) - 24;
+       first = (inode->i_size + blocksize - 1) / blocksize;
+       ekey  = inode->i_ino;
+
+       while (ekey) {
+               if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
+                       printk("AFFS: truncate(): Can't read block %d\n",ekey);
+                       break;
+               }
+               ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
+               stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+               if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
+                   LINK_END(bh->b_data,inode)->original == 0) {
+                       pr_debug("AFFS: truncate(): dumping link\n");
+                       affs_brelse(bh);
+                       break;
+               }
+               if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
+                       printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
+                               ptype,stype);
+                       affs_brelse(bh);
+                       break;
+               }
+               /* Do not throw away file header */
+               freethis = first == 0 && ekey != inode->i_ino;
+               for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+                       keyp  = &((struct file_front *)bh->b_data)->
+                                blocks[AFFS_I2HSIZE(inode) - 1 - block];
+                       key   = htonl(*keyp);
+                       if (key) {
+                               *keyp = 0;
+                               affs_free_block(inode->i_sb,key);
+                       } else {
+                               block = AFFS_I2HSIZE(inode);
+                               break;
+                       }
+               }
+               keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
+               key  = htonl(*keyp);
+               if (first <= AFFS_I2HSIZE(inode)) {
+                       ((struct file_front *)bh->b_data)->block_count = htonl(first);
+                       first = 0;
+                       *keyp = 0;
+               } else {
+                       first -= AFFS_I2HSIZE(inode);
+               }
+               if (freethis) {         /* Don't bother fixing checksum */
+                       affs_brelse(bh);
+                       affs_free_block(inode->i_sb,ekey);
+               } else {
+                       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+                       mark_buffer_dirty(bh,1);
+                       affs_brelse(bh);
+               }
+               ekey = key;
+       }
+       inode->u.affs_i.i_max_ext = 0;          /* invalidate cache */
+       iput(ino);
+}
+
+static void
+affs_release_file(struct inode *inode, struct file *filp)
+{
+       if (filp->f_mode & 2) {         /* Free preallocated blocks */
+               while (inode->u.affs_i.i_pa_cnt) {
+                       affs_free_block(inode->i_sb,
+                                       inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
+                       inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
+                       inode->u.affs_i.i_pa_cnt--;
+               }
        }
-       else
-               return 0;
-#endif
 }
dissimilarity index 81%
index 82ed07c..4041785 100644 (file)
-/*
- *  linux/fs/affs/inode.c
- *
- *  (C) 1994  Geert Uytterhoeven - Modified for MultiUserFileSystem
- *
- *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
- *
- *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
- *
- *  (C) 1991  Linus Torvalds - minix filesystem
- */
-
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/errno.h>
-
-#include <linux/genhd.h>
-
-#include "amigaffs.h"
-
-extern int check_cdrom_media_change(int, int);
-
-#ifdef LEAK_CHECK
-static int check_malloc = 0;
-static int check_bread = 0;
-#endif
-
-void affs_put_super(struct super_block *sb)
-{
-       lock_super(sb);
-
-#ifdef LEAK_CHECK
-       printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
-              check_malloc, check_bread);
-#endif
-       sb->s_dev = 0;
-       unlock_super(sb);
-       return;
-}
-
-static struct super_operations affs_sops = {
-       affs_read_inode,
-       NULL,                   /* notify_change */
-       NULL,                   /* write_inode */
-       NULL,                   /* put_inode */
-       affs_put_super,
-       NULL,                   /* write_super */
-       affs_statfs,
-       NULL                    /* remount */
-};
-
-int affs_parent_ino(struct inode *dir)
-{
-       int root_ino = (dir->i_sb->u.affs_sb.s_root_block
-                       - dir->i_sb->u.affs_sb.s_partition_offset);
-
-       if (!S_ISDIR (dir->i_mode)) {
-               printk ("affs_parent_ino: argument is not a directory\n");
-               return root_ino;
-       }
-       if (dir->i_ino == root_ino)
-               return root_ino;
-       return dir->u.affs_i.i_parent;
-}
-
-static int parse_options(char *options, struct affs_options *optp)
-{
-       char *this_opt,*value,*end;
-       int n;
-
-       optp->offset = 0;
-       optp->size = 0;
-       optp->root = 0;
-       optp->conv_links = 0;
-
-       if (!options)
-               return 1;
-       for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
-               if ((value = strchr(this_opt,'='))) *value++ = 0;
-
-               if (!strcmp(this_opt,"offset") && value) {
-                       n = simple_strtoul (value, &end, 10);
-                       if (end == value || *end != 0)
-                               return 0;
-                       optp->offset = n;
-               }
-               else if (!strcmp(this_opt,"size") && value) {
-                       n = simple_strtoul (value, &end, 10);
-                       if (end == value || *end != 0 || n <= 0)
-                               return 0;
-                       optp->size = n;
-               }
-               else if (!strcmp(this_opt,"root") && value) {
-                       n = simple_strtoul (value, &end, 10);
-                       if (end == value || *end != 0 || n <= 0)
-                               return 0;
-                       optp->root = n;
-               }
-               else if (!strcmp(this_opt,"conv_symlinks")) {
-                       optp->conv_links = 1;
-               }
-               else return 0;
-       }
-       return 1;
-}
-
-/* Is this The Right Way?  Should I be locking something? */
-
-static int get_device_size (dev_t dev)
-{
-       struct gendisk *gd_p;
-       int dev_size = 0;
-
-       for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
-               if (gd_p->major != MAJOR(dev))
-                       continue;
-               dev_size = gd_p->part[MINOR(dev)].nr_sects;
-               break;
-       }
-       return dev_size;
-}
-
-struct super_block *affs_read_super(struct super_block *s,void *data,
-                                   int silent)
-{
-       struct buffer_head *bh;
-       int dev = s->s_dev;
-       int root_block;
-       int ptype, stype;
-       void *root_data;
-       struct affs_options *optp;
-
-       optp = &s->u.affs_sb.s_options;
-
-       if (!parse_options((char *) data, optp)) {
-               s->s_dev = 0;
-               printk ("AFFS: bad mount options\n");
-               return NULL;
-       }
-
-       lock_super(s);
-
-       root_block = 0;
-       if (optp->size) {
-               s->u.affs_sb.s_partition_size = optp->size;
-       }
-       else {
-               int size = get_device_size (dev);
-               if (size == 0) {
-                       s->s_dev = 0;
-                       unlock_super(s);
-                       printk ("affs_read_super: could not"
-                               "determine device size\n");
-               }
-               s->u.affs_sb.s_partition_size = size;
-       }
-
-       s->u.affs_sb.s_partition_offset = optp->offset;
-       root_block = optp->root;
-
-       if (!root_block)
-               root_block = (s->u.affs_sb.s_partition_offset
-                             + s->u.affs_sb.s_partition_size / 2
-                             + (s->u.affs_sb.s_partition_size & 1));
-       s->u.affs_sb.s_root_block = root_block;
-
-       s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
-
-#if 0
-       printk ("affs_read_super: dev=0x%04x offset=%d "
-               "size=%d root=%d blocksize=%d\n",
-               dev,
-               s->u.affs_sb.s_partition_offset,
-               s->u.affs_sb.s_partition_size,
-               s->u.affs_sb.s_root_block,
-               s->u.affs_sb.s_block_size);
-#endif
-
-       bh = affs_sread (dev, root_block, &root_data);
-       if (!bh) {
-               s->s_dev = 0;
-               unlock_super(s);
-               printk ("AFFS: unable to read superblock\n");
-               return NULL;
-       }
-
-       if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype)
-           || ptype != T_SHORT || stype != ST_ROOT) {
-               printk ("AFFS: invalid root block %d on device 0x%04x\n",
-                       root_block, dev);
-               goto out;
-       }
-
-#if 1
-{
-       char *name;
-       int len;
-       char buf[33];
-       len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name);
-       memcpy (buf,name,len);
-       buf[len] = 0;
-#if 0
-       printk ("affs_read_super: volume name \"%s\"\n", buf);
-#endif
-}
-#endif
-
-       s->s_magic = AFFS_SUPER_MAGIC;
-
-       s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
-
-       brelse(bh);
-
-       /* set up enough so that it can read an inode */
-       s->s_dev = dev;
-       s->s_op = &affs_sops;
-       s->s_blocksize = AFFS_BUFFER_SIZE;
-       s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset);
-
-       unlock_super(s);
-
-       if (!(s->s_mounted)) {
-               s->s_dev = 0;
-               printk("AFFS: get root inode failed\n");
-               return NULL;
-       }
-
-       return s;
-
- out: /* Kick out for various error conditions */
-       brelse (bh);
-       s->s_dev = 0;
-       unlock_super(s);
-       return NULL;
-}
-
-void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
-{
-#ifdef DEBUG
-       printk ("AFFS: affs_statfs called\n");
-#endif
-       put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
-       put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
-       put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
-       put_fs_long(0, &buf->f_bfree);
-       put_fs_long(0, &buf->f_bavail);
-       put_fs_long(0, &buf->f_files);
-       put_fs_long(0, &buf->f_ffree);
-       /* Don't know what value to put in buf->f_fsid */
-}
-
-static int prot_table[9][2] = {
-       {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE},   /* other: 1 = allowed */
-       {PROT_OTR_WRITE, PROT_OTR_WRITE},
-       {PROT_OTR_READ, PROT_OTR_READ},
-       {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE},   /* group: 1 = allowed */
-       {PROT_GRP_WRITE, PROT_GRP_WRITE},
-       {PROT_GRP_READ, PROT_GRP_READ},
-       {PROT_EXECUTE, 0},                      /* owner: 0 = allowed */
-       {PROT_WRITE, 0},
-       {PROT_READ, 0}
-};
-
-void affs_read_inode(struct inode * inode)
-{
-       struct buffer_head *bh;
-       int block;
-       void *fh_data;
-       struct file_front *file_front;
-       struct file_end *file_end;
-       int i;
-       struct hardlink_end *link_end;
-       int link;       
-
-#ifdef DEBUG
-       printk ("AFFS: entering affs_read_inode\n");
-#endif
-
-       inode->i_nlink = 1; /* at least */
-       do {
-               link = 0;
-               block = inode->i_ino;
-               if (!(bh=affs_pread (inode, block, &fh_data))) {
-                       printk("AFFS: unable to read i-node block %d\n", block);
-                       return;
-               }
-
-               file_front = (struct file_front *) fh_data;
-               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 */
-               if (block == inode->i_sb->u.affs_sb.s_root_block) {
-                       inode->u.affs_i.i_protect = 0;
-                       inode->u.affs_i.i_parent = block;
-
-                       inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ;  /* drwxrwxrwt */
-                       inode->i_nlink = 2; /* at least ..... */
-
-                       inode->i_size = 0;  /* some different idea ? */
-
-                       inode->i_uid = 0;
-                       inode->i_gid = 0;
-               }
-               else { 
-
-                       inode->u.affs_i.i_protect = file_end->protect;
-                       inode->u.affs_i.i_parent = swap_long (file_end->parent);
-
-                       inode->i_mode = 0;
-                       for (i = 0; i < 9; i++)
-                               if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
-                                       inode->i_mode |= 1<<i;
-                       switch(swap_long(file_end->secondary_type)) {
-                               case ST_USERDIR:
-                                       inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
-
-                                       inode->i_nlink++; /* There are always at least 2.  It is
-                                                              hard to figure out what is correct*/
-                                       inode->i_size = 0;
-                               break;
-                               case ST_SOFTLINK:
-                                       inode->i_mode |= S_IFLNK;
-                                       inode->i_size  = 0;
-                               break;
-                               case ST_LINKFILE:   /* doing things very easy (not really correct) */
-                               case ST_LINKDIR:    /* code is _very_ inefficient (see below) */
-
-                                 /* Where is struct link_end defined?
-                                    ... I don't know what is going on
-                                    here, someone else should
-                                    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 what's correct */
-                                       brelse(bh);
-                                       link = 1;
-                               break;
-                               default:
-                                       printk("affs: unknown secondary type %ld; assuming file\n",
-                                               file_end->secondary_type);
-                               case ST_FILE:
-                                       inode->i_mode |= S_IFREG;
-                                       inode->i_size = swap_long (file_end->byte_size);
-                               break;
-                               }
-                       if (file_end->uid == 0xffff)
-                               inode->i_uid = 0;       /* root uid */
-                       else if (file_end->uid == 0x0000) {
-                               umode_t mode;
-                               inode->i_uid = -1;      /* unknown uid */
-
-                               /*
-                                * change the mode of the inode to duplicate the
-                                * perms of the user in the group and other fields;
-                                * the assumption is that this isn't a MultiUser
-                                * filesystem/file, so the permissions should be
-                                * the same for all users
-                                */
-                               mode = (inode->i_mode >> 6) & 7;
-                               inode->i_mode |= (mode << 3) | (mode);
-                       } else
-                               inode->i_uid = file_end->uid;
-                       if (file_end->gid == 0xffff)
-                               inode->i_gid = 0;       /* root gid */
-                       else if (file_end->gid == 0x0000)
-                               inode->i_gid = -1;      /* unknown gid */
-                       else
-                               inode->i_gid = file_end->gid;
-               }
-       }
-       while (link);
-
-#ifdef DEBUG
-       printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
-#endif
-       inode->i_mtime = inode->i_atime = inode->i_ctime
-               = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
-                  + swap_long (file_end->created.ds_Minute) * 60
-                  + swap_long (file_end->created.ds_Tick) / 50
-                  + ((8 * 365 + 2) * 24 * 60 * 60));
-
-       brelse(bh);
-
-       inode->i_op = NULL;
-       if (S_ISREG(inode->i_mode))
-               inode->i_op = &affs_file_inode_operations;
-       else if (S_ISDIR(inode->i_mode))
-               inode->i_op = &affs_dir_inode_operations;
-       else if (S_ISLNK(inode->i_mode))
-               inode->i_op = &affs_symlink_inode_operations;
-}
-
-
-#ifdef LEAK_CHECK
-#undef malloc
-#undef free_s
-#undef bread
-#undef brelse
-
-void * leak_check_malloc(unsigned int size){
-  void * tmp;
-  check_malloc++;
-  tmp = kmalloc(size, GFP_ATOMIC);
-  return tmp;
-}
-
-void leak_check_free_s(void * obj, int size){
-  check_malloc--;
-  return kfree_s(obj, size);
-}
-
-struct buffer_head * leak_check_bread(int dev, int block, int size){
-  check_bread++;
-  return bread(dev, block, size);
-}
-
-void leak_check_brelse(struct buffer_head * bh){
-  check_bread--;
-  return brelse(bh);
-}
-
-#endif
+/*
+ *  linux/fs/affs/inode.c
+ *
+ *  (c) 1996  Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ * 
+ *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/major.h>
+#include <linux/amigaffs.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+
+extern int *blk_size[];
+extern struct timezone sys_tz;
+
+void affs_put_super(struct super_block *sb)
+{
+       int      i;
+
+       pr_debug("affs_put_super()\n");
+
+       lock_super(sb);
+       if (!(sb->s_flags & MS_RDONLY)) {
+               for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
+                       affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
+               ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1);
+               secs_to_datestamp(CURRENT_TIME,
+                                 &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
+               affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
+               mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+       }
+       if (sb->u.affs_sb.s_flags & SF_PREFIX)
+               kfree(sb->u.affs_sb.s_prefix);
+       kfree(sb->u.affs_sb.s_bitmap);
+       affs_brelse(sb->u.affs_sb.s_root_bh);
+       set_blocksize(sb->s_dev,BLOCK_SIZE);
+       sb->s_dev = 0;
+       unlock_super(sb);
+       MOD_DEC_USE_COUNT;
+       return;
+}
+
+static void affs_write_super(struct super_block *sb)
+{
+       int      i, clean = 2;
+
+       if (!(sb->s_flags & MS_RDONLY)) {
+               for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
+                       if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
+                               clean = 0;
+                               break;
+                       }
+               }
+               ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean);
+               secs_to_datestamp(CURRENT_TIME,
+                                 &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
+               affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
+               mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+               sb->s_dirt = !clean;    /* redo until bitmap synced */
+       } else
+               sb->s_dirt = 0;
+
+       pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean);
+}
+
+static struct super_operations affs_sops = { 
+       affs_read_inode,
+       affs_notify_change,
+       affs_write_inode,
+       affs_put_inode, 
+       affs_put_super,
+       affs_write_super,
+       affs_statfs,
+       NULL                    /* remount */
+};
+
+int affs_parent_ino(struct inode *dir)
+{
+       int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
+
+       if (!S_ISDIR (dir->i_mode)) {
+               printk ("affs_parent_ino: argument is not a directory\n");
+               return root_ino;
+       }
+       if (dir->i_ino == root_ino)
+               return root_ino;
+       return dir->u.affs_i.i_parent;
+}
+
+
+static int
+parse_options(char *options, uid_t *uid, gid_t *gid, int *mode,
+             int *reserved, int *root, int *blocksize, char **prefix,
+             char *volume, unsigned long *mount_opts)
+{
+       char    *this_char, *value;
+       int      f;
+
+       /* Fill in defaults */
+
+       *uid        = 0;
+       *gid        = 0;
+       *reserved   = 2;
+       *root       = -1;
+       *blocksize  = -1;
+       *prefix     = "/";
+       volume[0]   = ':';
+       volume[1]   = 0;
+       *mount_opts = 0;
+       if (!options)
+               return 1;
+       for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+               f = 0;
+               if ((value = strchr(this_char,'=')) != NULL)
+                       *value++ = 0;
+               if (!strcmp(this_char,"protect")) {
+                       if (value) {
+                               printk("AFFS: option protect does not take an argument\n");
+                               return 0;
+                       }
+                       *mount_opts |= SF_IMMUTABLE;
+               }
+               else if (!strcmp(this_char,"verbose")) {
+                       if (value) {
+                               printk("AFFS: option verbose does not take an argument\n");
+                               return 0;
+                       }
+                       *mount_opts |= SF_VERBOSE;
+               }
+               else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) {
+                       if (!value)
+                               *uid = current->uid;
+                       else if (!*value) {
+                               printk("AFFS: argument for uid option missing\n");
+                               return 0;
+                       } else {
+                               *uid = simple_strtoul(value,&value,0);
+                               if (*value)
+                                       return 0;
+                               if (!f)
+                                       *mount_opts |= SF_SETUID;
+                       }
+               }
+               else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) {
+                       if (!value)
+                               *gid = current->gid;
+                       else if (!*value) {
+                               printk("AFFS: argument for gid option missing\n");
+                               return 0;
+                       } else {
+                               *gid = simple_strtoul(value,&value,0);
+                               if (*value)
+                                       return 0;
+                               if (!f)
+                                       *mount_opts |= SF_SETGID;
+                       }
+               }
+               else if (!strcmp(this_char,"prefix")) {
+                       if (!value) {
+                               printk("AFFS: The prefix option requires an argument\n");
+                               return 0;
+                       }
+                       *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
+                       if (!*prefix)
+                               return 0;
+                       strcpy(*prefix,value);
+                       *mount_opts |= SF_PREFIX;
+               }
+               else if (!strcmp(this_char,"volume")) {
+                       if (!value) {
+                               printk("AFFS: The volume option requires an argument\n");
+                               return 0;
+                       }
+                       if (strlen(value) > 30)
+                               value[30] = 0;
+                       strcpy(volume,value);
+               }
+               else if (!strcmp(this_char,"mode")) {
+                       if (!value || !*value) {
+                               printk("AFFS: The mode option requires an argument\n");
+                               return 0;
+                       }
+                       *mode = simple_strtoul(value,&value,8) & 0777;
+                       if (*value)
+                               return 0;
+                       *mount_opts |= SF_SETMODE;
+               }
+               else if (!strcmp(this_char,"reserved")) {
+                       if (!value || !*value) {
+                               printk("AFFS: The reserved option requires an argument\n");
+                               return 0;
+                       }
+                       *reserved = simple_strtoul(value,&value,0);
+                       if (*value)
+                               return 0;
+               }
+               else if (!strcmp(this_char,"root")) {
+                       if (!value || !*value) {
+                               printk("AFFS: The root option requires an argument\n");
+                               return 0;
+                       }
+                       *root = simple_strtoul(value,&value,0);
+                       if (*value)
+                               return 0;
+               }
+               else if (!strcmp(this_char,"bs")) {
+                       if (!value || !*value) {
+                               printk("AFFS: The bs option requires an argument\n");
+                               return 0;
+                       }
+                       *blocksize = simple_strtoul(value,&value,0);
+                       if (*value)
+                               return 0;
+                       if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
+                           && *blocksize != 4096) {
+                               printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n");
+                               return 0;
+                       }
+               }
+               /* Silently ignore the quota options */
+               else if (!strcmp (this_char, "grpquota")
+                        || !strcmp (this_char, "noquota")
+                        || !strcmp (this_char, "quota")
+                        || !strcmp (this_char, "usrquota"))
+                       ;
+               else {
+                       printk("AFFS: Unrecognized mount option %s\n",
+                              this_char);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+struct super_block *
+affs_read_super(struct super_block *s,void *data, int silent)
+{
+       struct buffer_head      *bh = NULL;
+       struct buffer_head      *bb;
+       kdev_t                   dev = s->s_dev;
+       int                      root_block;
+       int                      size;
+       ULONG                    chksum;
+       ULONG                   *bm;
+       LONG                     ptype, stype;
+       int                      mapidx = 0;
+       int                      num_bm;
+       int                      i;
+       int                      key;
+       int                      blocksize;
+       uid_t                    uid;
+       gid_t                    gid;
+       int                      mode, reserved;
+       int                      zm_size;
+       unsigned long            mount_flags;
+       ULONG                    offset;
+
+       pr_debug("affs_read_super(%s)\n",(const char *)data);
+
+       MOD_INC_USE_COUNT;
+
+       if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
+           &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
+               s->s_dev = 0;
+               printk("AFFS: error parsing options.\n");
+               MOD_DEC_USE_COUNT;
+               return NULL;
+       }
+       lock_super(s);
+
+       /* Get the size of the device in 512-byte blocks.
+        * If we later see that the partition uses bigger
+        * blocks, we will have to change it.
+        */
+
+       size                      = 2 * blk_size[MAJOR(dev)][MINOR(dev)];
+       s->u.affs_sb.s_bitmap     = NULL;
+       s->u.affs_sb.s_root_bh    = NULL;
+       s->u.affs_sb.s_flags      = mount_flags;
+       s->u.affs_sb.s_mode       = mode;
+       s->u.affs_sb.s_uid        = uid;
+       s->u.affs_sb.s_gid        = gid;
+
+       if (size == 0) {
+               s->s_dev = 0;
+               unlock_super(s);
+               printk("affs_read_super: could not determine device size\n");
+               goto out;
+       }
+       s->u.affs_sb.s_partition_size = size;
+       s->u.affs_sb.s_reserved       = reserved;
+
+       /* Try to find root block. It's location may depend on the block size. */
+
+       s->u.affs_sb.s_hashsize = 0;
+       if (blocksize > 0) {
+               chksum = blocksize;
+               num_bm = blocksize;
+       } else {
+               chksum = 512;
+               num_bm = 4096;
+       }
+       for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) {
+               if (root_block < 0)
+                   if (MAJOR(dev) == FLOPPY_MAJOR)
+                       s->u.affs_sb.s_root_block = size/4;
+                   else
+                       s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
+               else
+                       s->u.affs_sb.s_root_block = root_block;
+               pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n",
+                       blocksize,s->u.affs_sb.s_root_block,size,reserved);
+               set_blocksize(dev,blocksize);
+               bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize);
+               if (!bh) {
+                       printk("AFFS: unable to read root block\n");
+                       goto out;
+               }
+               if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
+                   ptype == T_SHORT && stype == ST_ROOT) {
+                       s->s_blocksize          = blocksize;
+                       s->u.affs_sb.s_hashsize = blocksize / 4 - 56;
+                       break;
+               }
+               affs_brelse(bh);
+               bh = NULL;
+       }
+       if (!s->u.affs_sb.s_hashsize) {
+               affs_brelse(bh);
+               if (!silent)
+                       printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev));
+               goto out;
+       }
+       root_block = s->u.affs_sb.s_root_block;
+
+       s->u.affs_sb.s_partition_size   = size;
+       s->s_blocksize_bits             = blocksize == 512 ? 9 :
+                                         blocksize == 1024 ? 10 :
+                                         blocksize == 2048 ? 11 : 12;
+
+       /* Find out which kind of FS we have */
+       bb = affs_bread(dev,0,s->s_blocksize);
+       if (bb) {
+               chksum = htonl(*(ULONG *)bb->b_data);
+               switch (chksum) {
+                       case MUFS_FS:
+                       case MUFS_INTLFFS:
+                               s->u.affs_sb.s_flags |= SF_MUFS;
+                               /* fall thru */
+                       case FS_INTLFFS:
+                               s->u.affs_sb.s_flags |= SF_INTL;
+                               break;
+                       case MUFS_FFS:
+                               s->u.affs_sb.s_flags |= SF_MUFS;
+                               break;
+                       case FS_FFS:
+                               break;
+                       case MUFS_OFS:
+                               s->u.affs_sb.s_flags |= SF_MUFS;
+                               /* fall thru */
+                       case FS_OFS:
+                               s->u.affs_sb.s_flags |= SF_OFS;
+                               break;
+                       case MUFS_INTLOFS:
+                               s->u.affs_sb.s_flags |= SF_MUFS;
+                               /* fall thru */
+                       case FS_INTLOFS:
+                               s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
+                               break;
+                       case FS_DCOFS:
+                       case FS_DCFFS:
+                       case MUFS_DCOFS:
+                       case MUFS_DCFFS:
+                               if (!silent)
+                                       printk("AFFS: Unsupported filesystem on device %s: %08X\n",
+                                               kdevname(dev),chksum);
+                               if (0)
+                       default:
+                               printk("AFFS: Unknown filesystem on device %s: %08X\n",
+                                      kdevname(dev),chksum);
+                               affs_brelse(bb);
+                               goto out;
+               }
+               affs_brelse(bb);
+       } else {
+               printk("AFFS: Can't get boot block.\n");
+               goto out;
+       }
+       if (mount_flags & SF_VERBOSE) {
+               chksum = ntohl(chksum);
+               printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
+                      GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
+                      &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+                      (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+       }
+
+       s->s_magic = AFFS_SUPER_MAGIC;
+       s->s_flags = MS_NODEV | MS_NOSUID;
+
+       /* Keep super block in cache */
+       if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
+               printk("AFFS: Can't read root block a second time\n");
+               goto out;
+       }
+
+       /* Allocate space for bitmap pointers and read the bitmap */
+
+       size    = s->u.affs_sb.s_partition_size - reserved;
+       num_bm  = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
+       zm_size = (num_bm *  (1 << (s->s_blocksize_bits - 8)) + 7) / 8;
+       ptype   = num_bm * sizeof(struct affs_bm_info) + zm_size +
+                 MAX_ZONES * sizeof(struct affs_zone);
+       if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
+               printk("AFFS: Can't get memory for bitmap info.\n");
+               goto out;
+       }
+       memset(s->u.affs_sb.s_bitmap,0,ptype);
+
+       if( (ULONG)((UBYTE *)bh->b_data + s->s_blocksize - 200) == 0 ) {
+               if (!(s->s_flags & MS_RDONLY)) {
+                       printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev));
+                       s->s_flags |= MS_RDONLY;
+               }
+               affs_brelse(bh);
+               bh = NULL;
+               goto nobitmap;
+       }
+
+       pr_debug("AFFS: %d bitmap blocks\n",num_bm);
+
+       key    = root_block;
+       ptype  = s->s_blocksize / 4 - 49;
+       stype  = ptype + 25;
+       offset = s->u.affs_sb.s_reserved;
+       while (bh) {
+               bm = (ULONG *)bh->b_data;
+               for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
+                       if (mapidx >= num_bm) {
+                               printk("AFFS: Not enough bitmap space!?\n");
+                               goto out;
+                       }
+                       bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
+                       if (bb) {
+                               if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&&
+                                   !(s->s_flags & MS_RDONLY)*/) {
+                                       printk("AFFS: Bitmap (%d,key=%lu) invalid - mounting %s read only.\n",
+                                              mapidx, htonl(bm[i]),
+                                              kdevname(dev));
+                                       s->s_flags |= MS_RDONLY;
+                               }
+                               if (size <= s->s_blocksize * 8 - 32) {  /* last bitmap */
+                                       ptype = size / 32 + 1;          /* word number */
+                                       key   = size & 0x1F;            /* used bits */
+                                       if (key) {
+                                               chksum = ntohl(0x7FFFFFFF >> (31 - key));
+                                               ((ULONG *)bb->b_data)[ptype] &= chksum;
+                                               affs_fix_checksum(s->s_blocksize,bb->b_data,0);
+                                               /* no need to mark buffer as dirty */
+                                       }
+                                       ptype = (size + 31) & ~0x1F;
+                                       size  = 0;
+                                       if (!(s->s_flags & MS_RDONLY))
+                                               s->u.affs_sb.s_flags |= SF_BM_VALID;
+                               } else {
+                                       ptype = s->s_blocksize * 8 - 32;
+                                       size -= ptype;
+                               }
+                               s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
+                               s->u.affs_sb.s_bitmap[mapidx].bm_size     = ptype;
+                               s->u.affs_sb.s_bitmap[mapidx].bm_bh       = bb;
+                               s->u.affs_sb.s_bitmap[mapidx].bm_free     =
+                                 affs_count_free_bits(ptype/8,bb->b_data + 4);
+                               offset += ptype;
+                       } else {
+                               printk("AFFS: Can't read bitmap.\n");
+                               goto out;
+                       }
+               }
+               key   = htonl(bm[stype]);   /* Next block of bitmap pointers */
+               ptype = 0;
+               stype = s->s_blocksize / 4 - 1;
+               affs_brelse(bh);
+               if (key) {
+                       if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
+                               printk("AFFS: Can't read bitmap extension.\n");
+                               goto out;
+                       }
+               } else
+                       bh = NULL;
+       }
+       if (mapidx != num_bm) {
+               printk("AFFS: Got only %d bitmap blocks, expected %d\n",
+                      mapidx, num_bm);
+               goto out;
+       }
+       s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8))+
+                                  (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048;
+nobitmap:
+       s->u.affs_sb.s_bm_count  = mapidx;
+       s->u.affs_sb.s_zones     = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
+       s->u.affs_sb.s_zonemap   = (char *)&s->u.affs_sb.s_zones[MAX_ZONES];
+
+       /* set up enough so that it can read an inode */
+
+       s->s_dev       = dev;
+       s->s_op        = &affs_sops;
+       s->s_mounted   = iget(s,root_block);
+       unlock_super(s);
+
+       if (!(s->s_mounted)) {
+               s->s_dev = 0;
+               printk("AFFS: get root inode failed\n");
+               MOD_DEC_USE_COUNT;
+               return NULL;
+       }
+
+       /* If the fs is mounted r/w, create data zones, else free bitmaps. */
+
+       if (!(s->s_flags & MS_RDONLY)) {
+               ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
+               secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
+                                 s->s_mounted)->disk_altered);
+               affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
+               mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
+               affs_make_zones(s);
+       } else {
+               for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
+                       affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
+                       s->u.affs_sb.s_bitmap[i].bm_bh = NULL;
+               }
+       }
+
+
+       pr_debug("AFFS: s_flags=%lX\n", s->s_flags);
+       return s;
+
+ out: /* Kick out for various error conditions */
+       affs_brelse (bh);
+       affs_brelse(s->u.affs_sb.s_root_bh);
+       if (s->u.affs_sb.s_bitmap) {
+               for (i = 0; i < mapidx; i++)
+                       affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
+               kfree(s->u.affs_sb.s_bitmap);
+       }
+       s->s_dev = 0;
+       unlock_super(s);
+       MOD_DEC_USE_COUNT;
+       return NULL;
+}
+
+void
+affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+       ULONG            free;
+       struct statfs    tmp;
+
+       pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",
+               sb->u.affs_sb.s_partition_size, sb->u.affs_sb.s_reserved);
+
+       free          = affs_count_free_blocks(sb);
+       tmp.f_type    = AFFS_SUPER_MAGIC;
+       tmp.f_bsize   = sb->s_blocksize;
+       tmp.f_blocks  = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+       tmp.f_bfree   = free;
+       tmp.f_bavail  = free;
+       tmp.f_files   = 0;
+       tmp.f_ffree   = 0;
+       memcpy_tofs(buf,&tmp,bufsiz);
+}
+
+void
+affs_read_inode(struct inode *inode)
+{
+       struct buffer_head      *bh, *lbh;
+       struct file_front       *file_front;
+       struct file_end         *file_end;
+       LONG                     block;
+       ULONG                    prot;
+       LONG                     ptype, stype;
+       unsigned short           id;
+
+       pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
+       lbh   = NULL;
+       block = inode->i_ino;
+       if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
+               printk("AFFS: unable to read i-node block %d\n",block);
+               return;
+       }
+       if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
+               printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n",
+                      ptype, block);
+               affs_brelse(bh);
+               return;
+       }
+
+       file_front = (struct file_front *)bh->b_data;
+       file_end   = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
+       prot       = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER;
+
+       inode->u.affs_i.i_protect  = prot;
+       inode->u.affs_i.i_parent   = htonl(file_end->parent);
+       inode->u.affs_i.i_original = 0; 
+       inode->u.affs_i.i_zone     = 0;
+       inode->u.affs_i.i_hlink    = 0;
+       inode->u.affs_i.i_pa_cnt   = 0;
+       inode->u.affs_i.i_pa_next  = 0;
+       inode->u.affs_i.i_pa_last  = 0;
+       inode->u.affs_i.i_ext[0]   = 0;
+       inode->u.affs_i.i_max_ext  = 0;
+       inode->i_nlink             = 1;
+       inode->i_mode              = 0;
+
+       if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
+               inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
+       else
+               inode->i_mode = prot_to_mode(prot);
+       
+       if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
+               inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
+       else {
+               id = htons(file_end->owner_uid);
+               if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+                       if (id == 0 || id == 0xFFFF)
+                               id ^= ~0;
+               }
+               inode->i_uid = id;
+       }
+       if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
+               inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
+       else {
+               id = htons(file_end->owner_gid);
+               if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+                       if (id == 0 || id == 0xFFFF)
+                               id ^= ~0;
+               }
+               inode->i_gid = id;
+       }
+
+       switch (htonl(file_end->secondary_type)) {
+               case ST_ROOT:
+                       inode->i_uid   = inode->i_sb->u.affs_sb.s_uid;
+                       inode->i_gid   = inode->i_sb->u.affs_sb.s_gid;
+               case ST_USERDIR:
+                       if (htonl(file_end->secondary_type) == ST_USERDIR ||
+                           inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
+                               if (inode->i_mode & S_IRUSR)
+                                       inode->i_mode |= S_IXUSR;
+                               if (inode->i_mode & S_IRGRP)
+                                       inode->i_mode |= S_IXGRP;
+                               if (inode->i_mode & S_IROTH)
+                                       inode->i_mode |= S_IXOTH;
+                               inode->i_mode |= S_IFDIR;
+                       } else
+                               inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
+                       inode->i_size  = 0;
+                       break;
+               case ST_LINKDIR:
+                       inode->u.affs_i.i_original = htonl(file_end->original);
+                       inode->u.affs_i.i_hlink    = 1;
+                       inode->i_mode             |= S_IFDIR;
+                       inode->i_size              = 0;
+                       break;
+               case ST_LINKFILE:
+                       inode->u.affs_i.i_original = htonl(file_end->original);
+                       inode->u.affs_i.i_hlink    = 1;
+                       if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original,
+                                         AFFS_I2BSIZE(inode)))) {
+                               affs_brelse(bh);
+                               printk("AFFS: unable to read i-node block %ld\n",inode->i_ino);
+                               return;
+                       }
+                       file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode));
+               case ST_FILE:
+                       inode->i_mode |= S_IFREG;
+                       inode->i_size  = htonl(file_end->byte_size);
+                       break;
+               case ST_SOFTLINK:
+                       inode->i_mode |= S_IFLNK;
+                       inode->i_size  = 0;
+                       break;
+       }
+
+       inode->i_mtime = inode->i_atime = inode->i_ctime
+                      = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) +
+                        htonl(file_end->created.ds_Minute) * 60 +
+                        htonl(file_end->created.ds_Tick) / 50 +
+                        ((8 * 365 + 2) * 24 * 60 * 60)) +
+                        sys_tz.tz_minuteswest * 60;
+       affs_brelse(bh);
+       affs_brelse(lbh);
+       
+       inode->i_op = NULL;
+       if (S_ISREG(inode->i_mode)) {
+               if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
+                       inode->i_op = &affs_file_inode_operations_ofs;
+               else
+                       inode->i_op = &affs_file_inode_operations;
+       } else if (S_ISDIR(inode->i_mode))
+               inode->i_op = &affs_dir_inode_operations;
+       else if (S_ISLNK(inode->i_mode))
+               inode->i_op = &affs_symlink_inode_operations;
+}
+
+void
+affs_write_inode(struct inode *inode)
+{
+       struct buffer_head *bh;
+       struct file_end    *file_end;
+       short               uid, gid;
+
+       pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
+
+       inode->i_dirt = 0;
+       if (!inode->i_nlink)
+               return;
+       if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
+               printk("AFFS: Unable to read block of inode %ld on %s\n",
+                      inode->i_ino,kdevname(inode->i_dev));
+               return;
+       }
+       file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
+       if (file_end->secondary_type == htonl(ST_ROOT)) {
+               secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
+       } else {
+               file_end->protect   = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER);
+               file_end->byte_size = ntohl(inode->i_size);
+               secs_to_datestamp(inode->i_mtime,&file_end->created);
+               if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
+                       uid = inode->i_uid;
+                       gid = inode->i_gid;
+                       if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+                               if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
+                                       uid = inode->i_uid ^ ~0;
+                               if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
+                                       gid = inode->i_gid ^ ~0;
+                       }
+                       if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
+                               file_end->owner_gid = ntohs(uid);
+                       if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
+                               file_end->owner_gid = ntohs(gid);
+               }
+       }
+       affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+       mark_buffer_dirty(bh,1);
+       brelse(bh);
+}
+
+int
+affs_notify_change(struct inode *inode, struct iattr *attr)
+{
+       int error;
+
+       pr_debug("AFFS: notify_change(%lu,0x%x)\n",
+               inode->i_ino,attr->ia_valid);
+
+       error = inode_change_ok(inode,attr);
+       if (error)
+               return error;
+       
+       if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) ||
+           ((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) ||
+           ((attr->ia_valid & ATTR_MODE) &&
+            (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE))))
+               error = -EPERM;
+       
+       if (error)
+               return (inode->i_sb->u.affs_sb.s_flags & SF_QUIET) ? 0 : error;
+       
+       if (attr->ia_valid & ATTR_MODE)
+               inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
+
+       inode_setattr(inode,attr);
+
+       return 0;
+}
+
+void
+affs_put_inode(struct inode *inode)
+{
+       pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
+               inode->i_ino,inode->i_nlink);
+       if (inode->i_nlink) {
+               return;
+       }
+       inode->i_size = 0;
+       if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink)
+               affs_truncate(inode);
+       affs_free_block(inode->i_sb,inode->i_ino);
+       clear_inode(inode);
+}
+
+struct inode *
+affs_new_inode(const struct inode *dir)
+{
+       struct inode            *inode;
+       struct super_block      *sb;
+       ULONG                    block;
+
+       if (!dir || !(inode = get_empty_inode()))
+               return NULL;
+       
+       sb = dir->i_sb;
+       inode->i_sb    = sb;
+       inode->i_flags = sb->s_flags;
+
+       if (!(block = affs_new_header((struct inode *)dir))) {
+               iput(inode);
+               return NULL;
+       }
+
+       inode->i_count   = 1;
+       inode->i_nlink   = 1;
+       inode->i_dev     = sb->s_dev;
+       inode->i_uid     = current->fsuid;
+       inode->i_gid     = current->fsgid;
+       inode->i_dirt    = 1;
+       inode->i_ino     = block;
+       inode->i_op      = NULL;
+       inode->i_blocks  = 0;
+       inode->i_size    = 0;
+       inode->i_mode    = 0;
+       inode->i_blksize = 0;
+       inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+       inode->u.affs_i.i_original = 0;
+       inode->u.affs_i.i_parent   = dir->i_ino;
+       inode->u.affs_i.i_zone     = 0;
+       inode->u.affs_i.i_hlink    = 0;
+       inode->u.affs_i.i_pa_cnt   = 0;
+       inode->u.affs_i.i_pa_next  = 0;
+       inode->u.affs_i.i_pa_last  = 0;
+       inode->u.affs_i.i_ext[0]   = 0;
+       inode->u.affs_i.i_max_ext  = 0;
+
+       insert_inode_hash(inode);
+
+       return inode;
+}
+
+int
+affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
+              const char *name, int len, LONG type)
+{
+       struct buffer_head      *dir_bh;
+       struct buffer_head      *inode_bh;
+       struct buffer_head      *link_bh;
+       ULONG                    hash;
+
+       pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",
+               dir->i_ino,inode->i_ino, len,name,type);
+
+       dir_bh     = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+       inode_bh   = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       link_bh    = NULL;
+       if (!dir_bh || !inode_bh) {
+               affs_brelse(dir_bh);
+               affs_brelse(inode_bh);
+               return -ENOSPC;
+       }
+       if (link) {
+               link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
+               if (!link_bh) {
+                       affs_brelse(dir_bh);
+                       affs_brelse(inode_bh);
+                       return -EINVAL;
+               }
+       }
+       ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT);
+       ((struct dir_front *)inode_bh->b_data)->own_key      = ntohl(inode->i_ino);
+
+       if (len > 30)           /* truncate name quietly */
+               len = 30;
+       DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
+       strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
+       DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type);
+       DIR_END(inode_bh->b_data,inode)->parent         = ntohl(dir->i_ino);
+       hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir));
+
+       lock_super(inode->i_sb);
+       DIR_END(inode_bh->b_data,inode)->hash_chain = 
+                        ((struct dir_front *)dir_bh->b_data)->hashtable[hash];
+       ((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino);
+       if (link_bh) {
+               LINK_END(inode_bh->b_data,inode)->original   = ntohl(link->i_ino);
+               LINK_END(inode_bh->b_data,inode)->link_chain = 
+                                   FILE_END(link_bh->b_data,link)->link_chain;
+               FILE_END(link_bh->b_data,link)->link_chain   = ntohl(inode->i_ino);
+               affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
+               link->i_version = ++event;
+               link->i_dirt    = 1;
+               mark_buffer_dirty(link_bh,1);
+       }
+       affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
+       affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
+       dir->i_version = ++event;
+       dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
+       unlock_super(inode->i_sb);
+
+       dir->i_dirt    = 1;
+       inode->i_dirt  = 1;
+       mark_buffer_dirty(dir_bh,1);
+       mark_buffer_dirty(inode_bh,1);
+       affs_brelse(dir_bh);
+       affs_brelse(inode_bh);
+       affs_brelse(link_bh);
+
+       return 0;
+}
+
+static struct file_system_type affs_fs_type = {
+       affs_read_super,
+       "affs",
+       1,
+       NULL
+};
+
+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
dissimilarity index 74%
index 77c1a2b..f213dc1 100644 (file)
-/*
- *  linux/fs/affs/namei.c
- *
- *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
- *
- *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
- *
- *  (C) 1991  Linus Torvalds - minix filesystem
- */
-
-#include <linux/sched.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <asm/segment.h>
-
-#include <linux/errno.h>
-
-
-static inline int namecompare(int len, int maxlen,
-       const char * name, const char * buffer)
-{
-       if (len >= maxlen || !buffer[len]) {
-               return strncmp (name, buffer, len) == 0;
-       }
-       return 0;
-}
-
-/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use affs_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
- */
-static int affs_match(int len,const char * name, char * compare, int dlen)
-{
-       if (!compare) return 0;
-
-       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-       if (!len && dlen == 1 && compare[0] == '.')
-               return 1;
-       
-#if 0
-       if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
-#endif
-       
-       return namecompare(len,dlen,name,compare);
-}
-
-/* Avoid pulling in ctype stuff. */
-
-static int affs_toupper (int ch)
-{
-       if (ch >= 'a' && ch <= 'z')
-               ch -= ('a' - 'A');
-       return ch;
-}
-
-static int affs_hash_name (const char *name, int len)
-{
-       int i, x;
-
-       x = len;
-       for (i = 0; i < len; i++)
-               x = (x * 13 + affs_toupper (name[i])) & 0x7ff;
-       return x % 72;  /* FIXME: Assumes 512 byte blocks. */
-}
-
-static struct buffer_head *affs_find_entry(struct inode *dir,
-       const char *name, int namelen, int *ino)
-{
-       struct buffer_head *bh;
-       void *dir_data;
-       int key;
-
-       *ino = 0;
-
-       bh = affs_pread (dir, dir->i_ino, &dir_data);
-       if (!bh)
-               return NULL;
-
-       if (affs_match (namelen, name, ".", 1)) {
-               *ino = dir->i_ino;
-               return bh;
-       }
-       if (affs_match (namelen, name, "..", 2)) {
-               *ino = affs_parent_ino (dir);
-               return bh;
-       }
-       key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data,
-                                 affs_hash_name (name, namelen));
-
-       for (;;) {
-               char *cname;
-               int cnamelen;
-
-               brelse (bh);
-               if (key <= 0)
-                       return NULL;
-               bh = affs_pread (dir, key, &dir_data);
-               if (!bh)
-                       return NULL;
-               cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir),
-                                              dir_data, &cname);
-               if (affs_match (namelen, name, cname, cnamelen))
-                       break;
-               key = affs_get_fh_hash_link (AFFS_I2BSIZE (dir), dir_data);
-       }
-               
-       *ino = key;
-
-       return bh;
-}
-
-int affs_lookup(struct inode * dir,const char * name, int len,
-       struct inode ** result)
-{
-       int ino;
-       struct buffer_head *bh;
-
-       *result = NULL;
-       if (!dir)
-               return -ENOENT;
-
-#ifdef DEBUG
-       printk ("lookup: %d %d\n", dir->i_ino, len);
-#endif
-
-       if (!S_ISDIR(dir->i_mode)) {
-               iput(dir);
-               return -ENOENT;
-       }
-       if (!(bh = affs_find_entry(dir, name, len, &ino))) {
-         iput(dir);
-         return -ENOENT;
-       }
-       brelse(bh);
-       if (!(*result = iget(dir->i_sb, ino))) {
-               iput(dir);
-               return -EACCES;
-       }
-       iput (dir);
-       return 0;
-
-#if 0
-       ino = 0;
-       while(cache.lock);
-       cache.lock = 1;
-       if (dir->i_dev == cache.dev && 
-           dir->i_ino == cache.dir &&
-           len == cache.dlen && 
-           affs_match(len, name, cache.filename, cache.dlen))
-         {
-           ino = cache.ino;
-           ino_back = dir->i_ino;
-           /* These two cases are special, but since they are at the start
-              of the directory, we can just as easily search there */
-           if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
-           if (cache.dlen == 2 && cache.filename[0] == '.' && 
-               cache.filename[1] == '.') ino = 0;
-         };
-       cache.lock = 0;
-
-       if (!ino) {
-         if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) {
-           iput(dir);
-           return -ENOENT;
-         }
-         brelse(bh);
-       };
-
-       if (!(*result = iget(dir->i_sb,ino))) {
-               iput(dir);
-               return -EACCES;
-       }
-
-       /* We need this backlink for the .. entry */
-       
-       if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; 
-       
-       iput(dir);
-       return 0;
-#endif
-}
+/*
+ *  linux/fs/affs/namei.c
+ *
+ *  (c) 1996  Hans-Joachim Widmaier - Heavily hacked up.
+ *
+ *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ *  (C) 1991  Linus Torvalds - minix filesystem
+ */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+
+/* Simple toupper() for DOS\1 */
+
+static inline unsigned int
+affs_toupper(unsigned int ch)
+{
+       return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
+}
+
+/* International toupper() for DOS\3 */
+
+static inline unsigned int
+affs_intl_toupper(unsigned int ch)
+{
+       return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
+               && ch <= 0xFE && ch != 0xF7) ?
+               ch - ('a' - 'A') : ch;
+}
+
+/*
+ * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
+ */
+
+static int
+affs_match(const char *name, int len, const char *compare, int dlen, int intl)
+{
+       if (!compare)
+               return 0;
+
+       if (len > 30)
+               len = 30;
+       if (dlen > 30)
+               dlen = 30;
+
+       /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+       if (!len && dlen == 1 && compare[0] == '.')
+               return 1;
+       if (dlen != len)
+               return 0;
+       if (intl) {
+               while (dlen--) {
+                       if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
+                               return 0;
+                       name++;
+                       compare++;
+               }
+       } else {
+               while (dlen--) {
+                       if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
+                               return 0;
+                       name++;
+                       compare++;
+               }
+       }
+       return 1;
+}
+
+int
+affs_hash_name(const char *name, int len, int intl, int hashsize)
+{
+       unsigned int i, x;
+
+       if (len > 30)
+               len = 30;
+
+       x = len;
+       for (i = 0; i < len; i++)
+               if (intl)
+                       x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
+               else
+                       x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
+
+       return x % hashsize;
+}
+
+static struct buffer_head *
+affs_find_entry(struct inode *dir, const char *name, int namelen,
+               unsigned long *ino)
+{
+       struct buffer_head *bh;
+       int      intl;
+       ULONG    key;
+
+       pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
+
+       intl = AFFS_I2FSTYPE(dir);
+       bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+       if (!bh)
+               return NULL;
+
+       if (affs_match(name,namelen,".",1,intl)) {
+               *ino = dir->i_ino;
+               return bh;
+       }
+       if (affs_match(name,namelen,"..",2,intl)) {
+               *ino = affs_parent_ino(dir);
+               return bh;
+       }
+
+       key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
+
+       for (;;) {
+               char *cname;
+               int cnamelen;
+
+               affs_brelse(bh);
+               if (key == 0) {
+                       bh = NULL;
+                       break;
+               }
+               bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
+               if (!bh)
+                       break;
+               cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
+               if (affs_match(name,namelen,cname,cnamelen,intl))
+                       break;
+               key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
+       }
+       pr_debug("%lu\n",key);
+       *ino = key;
+       return bh;
+}
+
+int
+affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
+{
+       int res;
+       unsigned long ino;
+       struct buffer_head *bh;
+
+       pr_debug("AFFS: lookup(%.*s)\n",len,name);
+
+       *result = NULL;
+       if (!dir)
+               return -ENOENT;
+
+       res = -ENOENT;
+       if (S_ISDIR(dir->i_mode)) {
+               if ((bh = affs_find_entry(dir,name,len,&ino))) {
+                       if (FILE_END(bh->b_data,dir)->original)
+                               ino = htonl(FILE_END(bh->b_data,dir)->original);
+                       affs_brelse(bh);
+                       if ((*result = iget(dir->i_sb,ino))) 
+                               res = 0;
+                       else
+                               res = -EACCES;
+               }
+       }
+       iput(dir);
+       return res;
+}
+
+int
+affs_unlink(struct inode *dir, const char *name, int len)
+{
+       int                      retval;
+       struct buffer_head      *bh;
+       unsigned long            ino;
+       struct inode            *inode;
+
+       pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
+
+       bh      = NULL;
+       inode   = NULL;
+       retval  = -ENOENT;
+       if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+               goto unlink_done;
+       }
+       if (!(inode = iget(dir->i_sb,ino))) {
+               goto unlink_done;
+       }
+       if (S_ISDIR(inode->i_mode)) {
+               retval = -EPERM;
+               goto unlink_done;
+       }
+
+       if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
+                                        AFFS_I2HSIZE(dir)) + 6,ino,
+                                        FILE_END(bh->b_data,dir)->hash_chain)))
+               goto unlink_done;
+
+       if ((retval = affs_fixup(bh,inode)))
+               goto unlink_done;
+
+       inode->i_nlink=0;
+       inode->i_dirt=1;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       dir->i_version = ++event;
+       dir->i_dirt=1;
+unlink_done:
+       affs_brelse(bh);
+       iput(inode);
+       iput(dir);
+       return retval;
+}
+
+int
+affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
+{
+       struct inode    *inode;
+       int              error;
+       
+       pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+
+
+       *result = NULL;
+
+       if (!dir || !dir->i_sb) {
+               iput(dir);
+               return -EINVAL;
+       }
+       inode = affs_new_inode(dir);
+       if (!inode) {
+               iput (dir);
+               return -ENOSPC;
+       }
+       inode->i_op   = &affs_file_inode_operations;
+       inode->i_mode = mode;
+       error         = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
+       if (error) {
+               iput(dir);
+               inode->i_nlink = 0;
+               inode->i_dirt  = 1;
+               iput(inode);
+               return -ENOSPC;
+       }
+       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+
+       iput(dir);
+       *result = inode;
+
+       return 0;
+}
+
+int
+affs_mkdir(struct inode *dir, const char *name, int len, int mode)
+{
+       struct inode            *inode;
+       struct buffer_head      *bh;
+       unsigned long            i;
+       int                      error;
+       
+       pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+
+       if (!dir || !dir->i_sb) {
+               iput(dir);
+               return -EINVAL;
+       }
+       bh = affs_find_entry(dir,name,len,&i);
+       if (bh) {
+               affs_brelse(bh);
+               iput(dir);
+               return -EEXIST;
+       }
+       inode = affs_new_inode(dir);
+       if (!inode) {
+               iput (dir);
+               return -ENOSPC;
+       }
+       inode->i_op = &affs_dir_inode_operations;
+       error       = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
+       if (error) {
+               iput(dir);
+               inode->i_nlink = 0;
+               inode->i_dirt  = 1;
+               iput(inode);
+               return error;
+       }
+       inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
+       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+
+       iput(dir);
+       iput(inode);
+
+       return 0;
+}
+
+static int
+empty_dir(struct buffer_head *bh, int hashsize)
+{
+       while (--hashsize >= 0) {
+               if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
+                       return 0;
+       }
+       return 1;
+}
+
+int
+affs_rmdir(struct inode *dir, const char *name, int len)
+{
+       int                      retval;
+       unsigned long            ino;
+       struct inode            *inode;
+       struct buffer_head      *bh;
+
+       pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
+
+       inode  = NULL;
+       retval = -ENOENT;
+       if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+               goto rmdir_done;
+       }
+       if (!(inode = iget(dir->i_sb,ino))) {
+               goto rmdir_done;
+       }
+       retval = -EPERM;
+        if (!fsuser() && current->fsuid != inode->i_uid &&
+            current->fsuid != dir->i_uid)
+               goto rmdir_done;
+       if (inode->i_dev != dir->i_dev)
+               goto rmdir_done;
+       if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
+               goto rmdir_done;
+       if (!S_ISDIR(inode->i_mode)) {
+               retval = -ENOTDIR;
+               goto rmdir_done;
+       }
+       if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
+               retval = -ENOTEMPTY;
+               goto rmdir_done;
+       }
+       if (inode->i_count > 1) {
+               retval = -EBUSY;
+               goto rmdir_done;
+       }
+       if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
+                                        AFFS_I2HSIZE(dir)) + 6,ino,
+                                        FILE_END(bh->b_data,dir)->hash_chain)))
+               goto rmdir_done;
+
+       if ((retval = affs_fixup(bh,inode)))
+               goto rmdir_done;
+
+       inode->i_nlink=0;
+       inode->i_dirt=1;
+       inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+       dir->i_version = ++event;
+       dir->i_dirt=1;
+rmdir_done:
+       iput(dir);
+       iput(inode);
+       affs_brelse(bh);
+       return retval;
+}
+
+int
+affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
+{
+       struct buffer_head      *bh;
+       struct inode            *inode;
+       char                    *p;
+       unsigned long            tmp;
+       int                      i, maxlen;
+       char                     c, lc;
+
+       pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+       printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+       
+       maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+       inode  = affs_new_inode(dir);
+       if (!inode) {
+               iput(dir);
+               return -ENOSPC;
+       }
+       inode->i_op   = &affs_symlink_inode_operations;
+       inode->i_mode = S_IFLNK | 0777;
+       inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+       bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       if (!bh) {
+               iput(dir);
+               inode->i_nlink = 0;
+               inode->i_dirt  = 1;
+               iput(inode);
+               return -EIO;
+       }
+       i  = 0;
+       p  = ((struct slink_front *)bh->b_data)->symname;
+       lc = '/';
+       if (*symname == '/') {
+               while (*symname == '/')
+                       symname++;
+               while (inode->i_sb->u.affs_sb.s_volume[i])      /* Cannot overflow */
+                       *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
+       }
+       while (i < maxlen && (c = *symname++)) {
+               if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
+                       *p++ = '/';
+                       i++;
+                       symname += 2;
+                       lc = '/';
+               } else if (c == '.' && lc == '/' && *symname == '/') {
+                       symname++;
+                       lc = '/';
+               } else {
+                       *p++ = c;
+                       lc   = c;
+                       i++;
+               }
+               if (lc == '/')
+                       while (*symname == '/')
+                               symname++;
+       }
+       *p = 0;
+       mark_buffer_dirty(bh,1);
+       affs_brelse(bh);
+       inode->i_dirt = 1;
+       bh = affs_find_entry(dir,name,len,&tmp);
+       if (bh) {
+               inode->i_nlink = 0;
+               iput(inode);
+               affs_brelse(bh);
+               iput(dir);
+               return -EEXIST;
+       }
+       i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
+       if (i) {
+               inode->i_nlink = 0;
+               inode->i_dirt  = 1;
+               iput(inode);
+               affs_brelse(bh);
+               iput(dir);
+               return i;
+       }
+       iput(dir);
+       iput(inode);
+       
+       return 0;
+}
+
+int
+affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
+{
+       struct inode            *inode;
+       struct buffer_head      *bh;
+       unsigned long            i;
+       int                      error;
+       
+       pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
+
+       bh = affs_find_entry(dir,name,len,&i);
+       if (bh) {
+               affs_brelse(bh);
+               iput(oldinode);
+               iput(dir);
+               return -EEXIST;
+       }
+       if (oldinode->u.affs_i.i_hlink) {
+               i = oldinode->u.affs_i.i_original;
+               iput(oldinode);
+               oldinode = iget(dir->i_sb,i);
+               if (!oldinode) {
+                       printk("AFFS: link(): original does not exist.\n");
+                       iput(dir);
+                       return -ENOENT;
+               }
+       }
+       inode = affs_new_inode(dir);
+       if (!inode) {
+               iput(oldinode);
+               iput(dir);
+               return -ENOSPC;
+       }
+       inode->i_op                = oldinode->i_op;
+       inode->i_mode              = oldinode->i_mode;
+       inode->i_uid               = oldinode->i_uid;
+       inode->i_gid               = oldinode->i_gid;
+       inode->u.affs_i.i_protect  = mode_to_prot(inode->i_mode);
+       inode->u.affs_i.i_original = oldinode->i_ino;
+       inode->u.affs_i.i_hlink    = 1;
+
+       if (S_ISDIR(oldinode->i_mode))
+               error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
+       else
+               error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
+       if (error) {
+               inode->i_nlink = 0;
+               inode->i_dirt  = 1;
+       }
+       iput(dir);
+       iput(inode);
+       iput(oldinode);
+
+       return error;
+}
+
+static int
+subdir(struct inode * new_inode, struct inode * old_inode)
+{
+    int ino;
+    int result;
+
+    new_inode->i_count++;
+    result = 0;
+    for (;;) {
+        if (new_inode == old_inode) {
+           result = 1;
+           break;
+       }
+       if (new_inode->i_dev != old_inode->i_dev)
+           break;
+       ino = new_inode->i_ino;
+       if (affs_lookup(new_inode,"..",2,&new_inode))
+           break;
+       if (new_inode->i_ino == ino)
+           break;
+    }
+    iput(new_inode);
+    return result;
+}
+
+/* I'm afraid this might not be race proof. Maybe next time. */
+
+int
+affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+           struct inode *new_dir, const char *new_name, int new_len)
+{
+       struct inode            *old_inode;
+       struct inode            *new_inode;
+       struct buffer_head      *old_bh;
+       struct buffer_head      *new_bh;
+       unsigned long            old_ino;
+       unsigned long            new_ino;
+       int                      retval;
+
+       pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
+               new_dir->i_ino,new_len,new_name);
+       
+       if (new_len > 30)
+               new_len = 30;
+       goto start_up;
+retry:
+       affs_brelse(old_bh);
+       affs_brelse(new_bh);
+       iput(new_inode);
+       iput(old_inode);
+       current->counter = 0;
+       schedule();
+start_up:
+       old_inode = new_inode = NULL;
+       old_bh    = new_bh = NULL;
+       retval    = -ENOENT;
+
+       old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
+       if (!old_bh)
+               goto end_rename;
+       old_inode = __iget(old_dir->i_sb,old_ino,0);
+       if (!old_inode)
+               goto end_rename;
+       new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
+       if (new_bh) {
+               new_inode = __iget(new_dir->i_sb,new_ino,0);
+               if (!new_inode) {               /* What does this mean? */
+                       affs_brelse(new_bh);
+                       new_bh = NULL;
+               }
+       }
+       if (new_inode == old_inode) {           /* Won't happen */
+               retval = 0;
+               goto end_rename;
+       }
+       if (new_inode && S_ISDIR(new_inode->i_mode)) {
+               retval = -EISDIR;
+               if (!S_ISDIR(old_inode->i_mode))
+                       goto end_rename;
+               retval = -EINVAL;
+               if (subdir(new_dir,old_inode))
+                       goto end_rename;
+               retval = -ENOTEMPTY;
+               if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
+                       goto end_rename;
+               retval = -EBUSY;
+               if (new_inode->i_count > 1)
+                       goto end_rename;
+       }
+       if (S_ISDIR(old_inode->i_mode)) {
+               retval = -ENOTDIR;
+               if (new_inode && !S_ISDIR(new_inode->i_mode))
+                       goto end_rename;
+               retval = -EINVAL;
+               if (subdir(new_dir,old_inode))
+                       goto end_rename;
+               if (affs_parent_ino(old_inode) != old_dir->i_ino)
+                       goto end_rename;
+       }
+       /* Unlink destination if existant */
+       if (new_inode) {
+               if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
+                                                AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
+                                                new_ino,
+                                                FILE_END(new_bh->b_data,new_dir)->hash_chain)))
+                       goto retry;
+               if ((retval = affs_fixup(new_bh,new_inode)))
+                       goto retry;
+               mark_buffer_dirty(new_bh,1);
+               new_dir->i_version = ++event;
+               new_dir->i_dirt    = 1;
+               new_inode->i_nlink = 0;
+               new_inode->i_dirt  = 1;
+       }
+       retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
+                                   AFFS_I2HSIZE(old_dir)) + 6,old_ino,
+                                   FILE_END(old_bh->b_data,old_dir)->hash_chain);
+       if (retval)
+               goto retry;
+
+       retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
+                               htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
+
+       new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+       new_dir->i_version = ++event;
+       old_dir->i_version = ++event;
+       new_dir->i_dirt    = 1;
+       old_dir->i_dirt    = 1;
+       mark_buffer_dirty(old_bh,1);
+       
+end_rename:
+       affs_brelse(old_bh);
+       affs_brelse(new_bh);
+       iput(new_inode);
+       iput(old_inode);
+       iput(old_dir);
+       iput(new_dir);
+
+       return retval;
+}
+
+int
+affs_fixup(struct buffer_head *bh, struct inode *inode)
+{
+       ULONG                    key, link_key;
+       LONG                     type;
+       struct buffer_head      *nbh;
+       struct inode            *ofinode;
+
+       type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+       if (type == ST_LINKFILE || type == ST_LINKDIR) {
+               key = htonl(LINK_END(bh->b_data,inode)->original);
+               LINK_END(bh->b_data,inode)->original = 0;
+               if (!key) {
+                       printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
+                       return -ENOENT;
+               }
+               if (!(ofinode = iget(inode->i_sb,key)))
+                       return -ENOENT;
+               type = affs_fix_link_pred(ofinode,inode->i_ino,
+                                         FILE_END(bh->b_data,inode)->link_chain);
+               iput(ofinode);
+               return type;
+       } else if (type == ST_FILE || type == ST_USERDIR) {
+               if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
+                       /* Get first link, turn it to a file */
+                       if (!(ofinode = iget(inode->i_sb,key))) {
+                               printk("AFFS: fixup(): cannot read inode %u\n",key);
+                               return -ENOENT;
+                       }
+                       if (!ofinode->u.affs_i.i_hlink) {
+                               printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
+                                       inode->i_ino,key);
+                               iput(ofinode);
+                               return -ENOENT;
+                       }
+                       if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
+                               printk("AFFS: fixup(): cannot read block %u\n",key);
+                               iput(ofinode);
+                               return -ENOENT;
+                       }
+                       lock_super(inode->i_sb);
+                       memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
+                       FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
+                                                                         byte_size;
+                       FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
+                                                                         extension;
+                       FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
+                                                                         secondary_type;
+                       FILE_END(nbh->b_data,inode)->original = 0;
+
+                       ofinode->u.affs_i.i_original = 0;
+                       ofinode->u.affs_i.i_hlink    = 0;
+                       ofinode->i_size              = inode->i_size;
+                       ofinode->i_uid               = inode->i_uid;
+                       ofinode->i_gid               = inode->i_gid;
+                       ofinode->i_dirt              = 1;
+                       link_key                     = ofinode->i_ino;
+
+                       /* Let all remaining links point to the new file */
+                       while (1) {
+                               affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
+                               mark_buffer_dirty(nbh,1);
+                               key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
+                               affs_brelse(nbh);
+                               iput(ofinode);
+                               if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
+                                       break;
+                               if ((ofinode = iget(inode->i_sb,key))) {
+                                       if (!ofinode->u.affs_i.i_hlink)
+                                               printk("AFFS: fixup() inode %u in link chain is "
+                                                      "not a link\n",key);
+                                       ofinode->u.affs_i.i_original = link_key;
+                                       ofinode->i_dirt              = 1;
+                                       FILE_END(nbh->b_data,inode)->original = htonl(link_key);
+                               } else
+                                       printk("AFFS: fixup(): cannot get inode %u\n",key);
+                       }
+                       /* Turn old inode to a link */
+                       inode->u.affs_i.i_hlink = 1;
+                       unlock_super(inode->i_sb);
+               }
+               return 0;
+       } else if (type == ST_SOFTLINK) {
+               return 0;
+       } else {
+               printk("AFFS: fixup(): secondary type=%d\n",type);
+               return -EBADF;
+       }
+}
dissimilarity index 61%
index e54b387..ee305dd 100644 (file)
-/*
- *  linux/fs/affs/symlink.c
- *
- *  (C) 1995  Joerg Dorchain Modified for Amiga FFS filesystem
- *            based on:
- *
- *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  isofs symlink handling code.  This is only used with the Rock Ridge
- *  extensions to iso9660
- */
-
-#include <asm/segment.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/affs_fs.h>
-
-#include "amigaffs.h"
-
-static int affs_readlink(struct inode *, char *, int);
-static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations affs_symlink_inode_operations = {
-       NULL,                   /* no file-operations */
-       NULL,                   /* create */
-       NULL,                   /* lookup */
-       NULL,                   /* link */
-       NULL,                   /* unlink */
-       NULL,                   /* symlink */
-       NULL,                   /* mkdir */
-       NULL,                   /* rmdir */
-       NULL,                   /* mknod */
-       NULL,                   /* rename */
-       affs_readlink,          /* readlink */
-       affs_follow_link,       /* follow_link */
-       NULL,                   /* bmap */
-       NULL,                   /* truncate */
-       NULL                    /* permission */
-};
-
-static int affs_follow_link(struct inode * dir, struct inode * inode,
-       int flag, int mode, struct inode ** res_inode)
-{
-       int error;
-       char * pnt;
-       struct buffer_head *bh;
-       struct symlink_front *sy_data;
-
-       if (!dir) {
-               dir = current->fs->root;
-               dir->i_count++;
-       }
-       if (!inode) {
-               iput(dir);
-               *res_inode = NULL;
-               return -ENOENT;
-       }
-       if (!S_ISLNK(inode->i_mode)) {
-               iput(dir);
-               *res_inode = inode;
-               return 0;
-       }
-       if (current->link_count > 5) {
-               iput(dir);
-               iput(inode);
-               *res_inode = NULL;
-               return -ELOOP;
-       }
-       if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
-               printk("affs: unable to read block %ld",inode->i_ino);
-               return 0;
-       }
-
-       pnt = sy_data->symname;
-       iput(inode);
-       current->link_count++;
-       error = open_namei(pnt,flag,mode,res_inode,dir);
-       current->link_count--;
-       brelse(bh);
-       return error;
-}
-
-static char *affs_conv_path(char *affs_path)
-{
-static char unix_path[1024]="/";
-int up,ap;
-char dp,slash;
-
-
-dp=1;
-slash=1;
-ap=0;
-up=1;
-if (affs_path[0] == 0)
-  unix_path[up++]='.';
-while ((up < 1020) && (affs_path[ap]!=0))
- {
-  switch (affs_path[ap]) {
-    case ':':
-      if (dp == 0) {
-        slash=0;
-        unix_path[up++]=':';
-      }
-      else {
-        dp=0;
-        slash=1;
-        unix_path[up++]='/';
-      }
-      break;
-    case '/':
-      if (slash==0) {
-        slash=1;
-        unix_path[up++]='/';
-      }
-      else {
-        unix_path[up++]='.';
-        unix_path[up++]='.';
-        unix_path[up++]='/';
-      }
-      break;
-    default:
-      slash=0;
-      unix_path[up++]=affs_path[ap];
-      break;
-  }
-  ap++;
- }
-unix_path[up]=0;
-return unix_path+dp;
-}
-
-
-static int affs_readlink(struct inode * inode, char * buffer, int buflen)
-{
-        char * pnt;
-       int i;
-       char c;
-       struct buffer_head *bh;
-       struct symlink_front *sy_data;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               iput(inode);
-               return -EINVAL;
-       }
-
-       if (buflen > 1023)
-               buflen = 1023;
-       
-       if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
-               printk("affs: unable to read block %ld\n",inode->i_ino);
-               return -ENOENT;
-       }
-       
-       iput(inode);
-
-       pnt = sy_data->symname;
-       if (inode->i_sb->u.affs_sb.s_options.conv_links != 0)
-         pnt = affs_conv_path(pnt);
-
-       i = 0;
-
-       while (i<buflen && (c = pnt[i])) {
-               i++;
-               put_fs_byte(c,buffer++);
-       }
-       
-       brelse(bh);
-
-       return i;
-}
+/*
+ *  linux/fs/affs/symlink.c
+ *
+ *  1995  Hans-Joachim Widmaier - modified for AFFS.
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  affs symlink handling code
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+
+#include <asm/segment.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+static int affs_readlink(struct inode *, char *, int);
+static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
+
+struct inode_operations affs_symlink_inode_operations = {
+       NULL,                   /* no file-operations */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       affs_readlink,          /* readlink */
+       affs_follow_link,       /* follow_link */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL                    /* permission */
+};
+
+static int
+affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
+                struct inode **res_inode)
+{
+       struct buffer_head      *bh;
+       struct slink_front      *lf;
+       char                    *buffer;
+       int                      error;
+       int                      i, j;
+       char                     c;
+       char                     lc;
+
+       pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
+
+       *res_inode = NULL;
+       if (!dir) {
+               dir = current->fs->root;
+               dir->i_count++;
+       }
+       if (!inode) {
+               iput(dir);
+               return -ENOENT;
+       }
+       if (!S_ISLNK(inode->i_mode)) {
+               iput(dir);
+               *res_inode = inode;
+               return 0;
+       }
+       if (current->link_count > 5) {
+               iput(inode);
+               iput(dir);
+               return -ELOOP;
+       }
+       if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
+               iput(inode);
+               iput(dir);
+               return -ENOSPC;
+       }
+       bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       i  = 0;
+       j  = 0;
+       if (!bh) {
+               printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+               kfree(buffer);
+               iput(inode);
+               iput(dir);
+               return -EIO;
+       }
+       lf = (struct slink_front *)bh->b_data;
+       lc = 0;
+       if (strchr(lf->symname,':')) {          /* Handle assign or volume name */
+               while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i]))
+                       buffer[i++] = c;
+               while (i < 1023 && lf->symname[j] != ':')
+                       buffer[i++] = lf->symname[j++];
+               if (i < 1023)
+                        buffer[i++] = '/';
+               j++;
+               lc = '/';
+       }
+       while (i < 1023 && (c = lf->symname[j])) {
+               if (c == '/' && lc == '/' && i < 1020) {        /* parent dir */
+                       buffer[i++] = '.';
+                       buffer[i++] = '.';
+               }
+               buffer[i++] = c;
+               lc = c;
+               j++;
+       }
+       buffer[i] = '\0';
+       affs_brelse(bh);
+       iput(inode);
+       current->link_count++;
+       error = open_namei(buffer,flag,mode,res_inode,dir);
+       current->link_count--;
+       kfree(buffer);
+       return error;
+}
+
+static int
+affs_readlink(struct inode *inode, char *buffer, int buflen)
+{
+       struct buffer_head      *bh;
+       struct slink_front      *lf;
+       int                      i, j;
+       char                     c;
+       char                     lc;
+
+       pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
+
+       if (!S_ISLNK(inode->i_mode)) {
+               iput(inode);
+               return -EINVAL;
+       }
+       bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+       i  = 0;
+       j  = 0;
+       if (!bh) {
+               printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+               goto symlink_end;
+       }
+       lf = (struct slink_front *)bh->b_data;
+       lc = 0;
+       
+       if (strchr(lf->symname,':')) {          /* Handle assign or volume name */
+               while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) {
+                       put_user(c,buffer++);
+                       i++;
+               }
+               while (i < buflen && (c = lf->symname[j]) != ':') {
+                       put_user(c,buffer++);
+                       i++, j++;
+               }
+               if (i < buflen) {
+                       put_user('/',buffer++);
+                       i++, j++;
+               }
+               lc = '/';
+       }
+       while (i < buflen && (c = lf->symname[j])) {
+               if (c == '/' && lc == '/' && (i + 3 < buflen)) {        /* parent dir */
+                       put_user('.',buffer++);
+                       put_user('.',buffer++);
+                       i += 2;
+               }
+               put_user(c,buffer++);
+               lc = c;
+               i++, j++;
+       }
+symlink_end:
+       iput(inode);
+       affs_brelse(bh);
+       return i;
+}
index e57e17c..0ac60bc 100644 (file)
@@ -225,9+225,9 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
        if (block + blocks > size)
                blocks = size - block;
 
-       /* We do this in a two stage process.  We first try and request
+       /* We do this in a two stage process.  We first try to request
           as many blocks as we can, then we wait for the first one to
-          complete, and then we try and wrap up as many as are actually
+          complete, and then we try to wrap up as many as are actually
           done.  This routine is rather generic, in that it can be used
           in a filesystem by substituting the appropriate function in
           for getblk.
index c75c5ae..a600075 100644 (file)
@@ -86,7+86,7 @@ union bdflush_param{
                                activate bdflush */
                int ndirty;  /* Maximum number of dirty blocks to write out per
                                wake-cycle */
-               int nrefill; /* Number of clean buffers to try and obtain
+               int nrefill; /* Number of clean buffers to try to obtain
                                each time we call refill */
                int nref_dirt; /* Dirty buffer threshold for activating bdflush
                                  when trying to refill buffers. */
@@ -572,7+572,7 @@ void refill_freelist(int size)
           now so as to ensure that there are still clean buffers available
           for user processes to use (and dirty) */
        
-       /* We are going to try and locate this much memory */
+       /* We are going to try to locate this much memory */
        needed =bdf_prm.b_un.nrefill * size;  
 
        while (nr_free_pages > min_free_pages*2 && needed > 0 &&
@@ -592,7+592,7 @@ void refill_freelist(int size)
                 if(needed <= 0) return;
         };
 
-       /* OK, we cannot grow the buffer cache, now try and get some
+       /* OK, we cannot grow the buffer cache, now try to get some
           from the lru list */
 
        /* First set the candidate pointers to usable buffers.  This
@@ -885,8+885,7 @@ struct buffer_head * bread(kdev_t dev, int block, int size)
        struct buffer_head * bh;
 
        if (!(bh = getblk(dev, block, size))) {
-               printk("VFS: bread: READ error on device %s\n",
-                       kdevname(dev));
+               printk("VFS: bread: impossible error\n");
                return NULL;
        }
        if (buffer_uptodate(bh))
@@ -1867,7+1866,7 @@ static void wakeup_bdflush(int wait)
 
 
 /* 
- * Here we attempt to write back old buffers.  We also try and flush inodes 
+ * Here we attempt to write back old buffers.  We also try to flush inodes 
  * and supers as well, since this function is essentially "update", and 
  * otherwise there would be no way of ensuring that these quantities ever 
  * get written back.  Ideally, we would have a timestamp on the inodes
index 5515290..a00d0f4 100644 (file)
@@ -113,9+113,9 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i
                        blocks = size - block;
        }
 
-       /* We do this in a two stage process.  We first try and request
+       /* We do this in a two stage process.  We first try to request
           as many blocks as we can, then we wait for the first one to
-          complete, and then we try and wrap up as many as are actually
+          complete, and then we try to wrap up as many as are actually
           done.  This routine is rather generic, in that it can be used
           in a filesystem by substituting the appropriate function in
           for getblk.
index 0e31a95..ec5fb06 100644 (file)
@@ -380,6+380,7 @@ static int vfat_ioctl_fill(
 int fat_dir_ioctl(struct inode * inode, struct file * filp,
                  unsigned int cmd, unsigned long arg)
 {
+       int err;
        /*
         * We want to provide an interface for Samba to be able
         * to get the short filename for a given long filename.
@@ -389,6+390,9 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp,
        switch (cmd) {
        case VFAT_IOCTL_READDIR_BOTH: {
                struct dirent *d1 = (struct dirent *)arg;
+               err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+               if (err)
+                       return err;
                put_user(0, &d1->d_reclen);
                return fat_readdirx(inode,filp,(void *)arg,
                                    vfat_ioctl_fill, NULL, 0, 1, 1);
@@ -396,6+400,9 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp,
        case VFAT_IOCTL_READDIR_SHORT: {
                struct dirent *d1 = (struct dirent *)arg;
                put_user(0, &d1->d_reclen);
+               err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+               if (err)
+                       return err;
                return fat_readdirx(inode,filp,(void *)arg,
                                    vfat_ioctl_fill, NULL, 1, 0, 1);
        }
index 5b386af..9b9c613 100644 (file)
@@ -17,8+17,8 @@ void fat_ll_rw_block (struct super_block *sb, int opr,
 /* These macros exist to avoid modifying all the code */
 /* They should be removed one day I guess */
 
-/* The versioning mechanism of the modules system define those macros */
-/* This remove some warnings */
+/* The versioning mechanism of the modules system defines those macros */
+/* This removes some warnings */
 #ifdef brelse
        #undef brelse
 #endif
index 2d1d20e..20e89cf 100644 (file)
@@ -88,15+88,15 @@ static int parse_options(char *options, struct iso9660_options * popt)
                if (strncmp(this_char,"norock",6) == 0) {
                  popt->rock = 'n';
                  continue;
-               };
+               }
                if (strncmp(this_char,"unhide",6) == 0) {
                  popt->unhide = 'y';
                  continue;
-               };
+               }
                if (strncmp(this_char,"cruft",5) == 0) {
                  popt->cruft = 'y';
                  continue;
-               };
+               }
                if ((value = strchr(this_char,'=')) != NULL)
                        *value++ = 0;
                if (!strcmp(this_char,"map") && value) {
@@ -134,7+134,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
                    if(*vpnt <  '0' || *vpnt > '9') break;
                    ivalue = ivalue * 10 + (*vpnt - '0');
                    vpnt++;
-                 };
+                 }
                  if (*vpnt) return 0;
                  switch(*this_char) {
                  case 'b':
@@ -241,8+241,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
          while (i != 1){
            blocksize_bits++;
            i >>=1;
-         };
-       };
+         }
+       }
        set_blocksize(dev, opt.blocksize);
 
        lock_super(s);
@@ -251,15+251,15 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
 
        vol_desc_start = isofs_get_last_session(dev);
        
-       for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
-#if 0
-               printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
-#endif 0
-               if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
+       for (iso_blknum = vol_desc_start+16;
+             iso_blknum < vol_desc_start+100; iso_blknum++) {
+                int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
+
+               if (!(bh = bread(dev,b,opt.blocksize))) {
                        s->s_dev = 0;
                        printk("isofs_read_super: bread failed, dev "
-                              "%s iso_blknum %d\n",
-                              kdevname(dev), iso_blknum);
+                              "%s iso_blknum %d block %d\n",
+                              kdevname(dev), iso_blknum, b);
                        unlock_super(s);
                        MOD_DEC_USE_COUNT;
                        return NULL;
@@ -280,7+280,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
                        opt.rock = 'n';
                        h_pri = (struct hs_primary_descriptor *)vdp;
                        break;
-               };
+               }
                
                if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
                  if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
@@ -290,7+290,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
                
                        pri = (struct iso_primary_descriptor *)vdp;
                        break;
-               };
+               }
 
                brelse(bh);
              }
@@ -301,8+301,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
                unlock_super(s);
                MOD_DEC_USE_COUNT;
                return NULL;
-       };
-       
+       }
        
        if(high_sierra){
          rootp = (struct iso_directory_record *) h_pri->root_directory_record;
@@ -311,7+310,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
            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);
          s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size);
@@ -322,7+321,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
            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);
          s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size);
@@ -793,7+792,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent)
                        if(!(bh = bread(parent->i_dev,block,bufsize))) {
                                kfree(cpnt);
                                return -1;
-                       };
+                       }
                        memcpy((char *)cpnt+frag1, bh->b_data, offset);
                }
                
index 3df7f9a..09963f0 100644 (file)
@@ -319,7+319,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
        break;
       case SIG('T','F'):
        /* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
-          Try and handle this correctly for either case. */
+          Try to handle this correctly for either case. */
        cnt = 0; /* Rock ridge never appears on a High Sierra disk */
        if(rr->u.TF.flags & TF_CREATE) 
          inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
index 5d7ecc4..b8038e4 100644 (file)
@@ -639,7+639,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
                                locks_free_lock(new_fl);
                                return (-ERESTARTSYS);
                        }
-                       /* Try to avoid deadlocks due to pathalogical programs that
+                       /* Try to avoid deadlocks due to pathological programs that
                         * mix calls to flock() and fcntl(). Return EAGAIN, because
                         * EDEADLOCK isn't a documented return value for flock().
                         */
index 1c81c23..6581425 100644 (file)
@@ -292,7+292,7 @@ static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet
        unsigned long sip, tip;
        unsigned char *sha, *tha;               /* s for "source", t for "target" */
 
-       /* If this test doesn't pass, its not IP, or we should ignore it anyway */
+       /* If this test doesn't pass, it's not IP, or we should ignore it anyway */
        if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
                kfree_skb(skb, FREE_READ);
                return 0;
@@ -763,9+763,9 @@ static int root_bootp_string(char *dest, char *src, int len, int max)
  */
 static void root_do_bootp_ext(u8 *ext)
 {
+#ifdef NFSROOT_BOOTP_DEBUG
        u8 *c;
 
-#ifdef NFSROOT_BOOTP_DEBUG
        printk("BOOTP: Got extension %02x",*ext);
        for(c=ext+2; c<ext+2+ext[1]; c++)
                printk(" %02x", *c);
index a8d9a60..324a457 100644 (file)
@@ -92,9+92,9 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na
        struct vfsmount *lptr;
        char *tmp;
 
-       if ((lptr = (struct vfsmount *)
-            kmalloc(sizeof(struct vfsmount), GFP_KERNEL)) == (struct vfsmount *)NULL)
-               return ((struct vfsmount *)NULL);
+       lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
+        if (!lptr)
+               return NULL;
        memset(lptr, 0, sizeof(struct vfsmount));
 
        lptr->mnt_dev = dev;
index a7c7754..92175ac 100644 (file)
@@ -114,9+114,9 @@ int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int cou
                        blocks = size - block;
        }
 
-       /* We do this in a two stage process.  We first try and request
+       /* We do this in a two stage process.  We first try to request
           as many blocks as we can, then we wait for the first one to
-          complete, and then we try and wrap up as many as are actually
+          complete, and then we try to wrap up as many as are actually
           done.  This routine is rather generic, in that it can be used
           in a filesystem by substituting the appropriate function in
           for getblk.
index 371e3a7..f260c10 100644 (file)
 /*
  * Kernel module support added on 96/04/26 by
  * Stefan Reinauer <stepan@home.culture.mipt.ru>
+ *
+ * Module usage counts added on 96/04/29 by
+ * Gertjan van Wingerde <gertjan@cs.vu.nl>
  */
 
 #include <linux/module.h>
index fcda9ab..38682b5 100644 (file)
@@ -433,7+433,7 @@ static int umsdos_symlink_x(
                in unused entry of the EMD file. The other is to have a separate
                file dedicated to hold all symbolic links data.
 
-               Lets go for simplicity...
+               Let's go for simplicity...
        */
        struct inode *inode;
        int ret;
index 5a3d41f..354757b 100644 (file)
@@ -8,8+8,8 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := vfat.o
-O_OBJS   := namei.o
-OX_OBJS  := 
+O_OBJS   := 
+OX_OBJS  := namei.o
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
index 31d0c36..25bb17b 100644 (file)
@@ -1569,12+1569,26 @@ static struct file_system_type vfat_fs_type = {
        vfat_read_super, "vfat", 1, NULL
 };
 
+static struct symbol_table vfat_syms = {
+#include <linux/symtab_begin.h>
+       X(vfat_create),
+       X(vfat_unlink),
+       X(vfat_mkdir),
+       X(vfat_rmdir),
+       X(vfat_rename),
+       X(vfat_put_super),
+       X(vfat_read_super),
+       X(vfat_read_inode),
+       X(vfat_lookup),
+#include <linux/symtab_end.h>
+};                                           
+
 int init_vfat_fs(void)
 {
        int status;
 
        if ((status = register_filesystem(&vfat_fs_type)) == 0)
-               status = register_symtab(0);
+               status = register_symtab(&vfat_syms);
        return status;
 }
 
index 8dd63f6..bd5f8d3 100644 (file)
@@ -106,9+106,9 @@ xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
            zones = f_zones - zone_nr;
     }
 
-    /* We do this in a two stage process.  We first try and request
+    /* We do this in a two stage process.  We first try to request
        as many blocks as we can, then we wait for the first one to
-       complete, and then we try and wrap up as many as are actually
+       complete, and then we try to wrap up as many as are actually
        done.  This routine is rather generic, in that it can be used
        in a filesystem by substituting the appropriate function in
        for getblk.
index bccac4e..357d309 100644 (file)
@@ -21,7+21,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp)
        while(lock_set_bit(0,&sp->lock))
        {
                /*
-                *      Failed, but thats cos we own it!
+                *      Failed, but that's cos we own it!
                 */
                 
                if(sp->cpu==processor)
@@ -45,7+45,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp)
                }
                /*
                 *      Someone wrote the line, we go 'I' and get
-                *      the cache entry. Now try and regrab
+                *      the cache entry. Now try to regrab
                 */
        }
        sp->users++;sp->cpu=processor;
@@ -117,7+117,7 @@ extern __inline__ void spinunlock(struct spinlock *sp)
 extern __inline__ void spintestlock(struct spinlock *sp)
 {
        /*
-        *      We do no sanity checks, its legal to optimistically
+        *      We do no sanity checks, it's legal to optimistically
         *      get a lower lock.
         */
        prim_spin_lock_nb(sp);
index d65198f..8ea9092 100644 (file)
  * We do not have SMP m68k systems, so we don't have to deal with that.
  */
 
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
-
 typedef int atomic_t;
 
 static __inline__ void atomic_add(atomic_t i, atomic_t *v)
 {
-       __asm__ __volatile__(
-               "addl %1,%0"
-               :"=m" (__atomic_fool_gcc(v))
-               :"ir" (i), "0" (__atomic_fool_gcc(v)));
+       __asm__ __volatile__("addl %1,%0" : : "m" (*v), "id" (i));
 }
 
 static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
 {
-       __asm__ __volatile__(
-               "subl  %1,%0"
-               :"=m" (__atomic_fool_gcc(v))
-               :"ir" (i), "0" (__atomic_fool_gcc(v)));
+       __asm__ __volatile__("subl %1,%0" : : "m" (*v), "id" (i));
 }
 
 static __inline__ void atomic_inc(atomic_t *v)
 {
-       __asm__ __volatile__(
-               "addql #1,%0"
-               :"=m" (__atomic_fool_gcc(v))
-               :"0" (__atomic_fool_gcc(v)));
+       __asm__ __volatile__("addql #1,%0" : : "m" (*v));
 }
 
 static __inline__ void atomic_dec(atomic_t *v)
 {
-       __asm__ __volatile__(
-               "subql #1,%0"
-               :"=m" (__atomic_fool_gcc(v))
-               :"0" (__atomic_fool_gcc(v)));
+       __asm__ __volatile__("subql #1,%0" : : "m" (*v));
 }
 
 static __inline__ int atomic_dec_and_test(atomic_t *v)
 {
        char c;
-       __asm__ __volatile__(
-               "subql #1,%0; seq %1"
-               :"=m" (__atomic_fool_gcc(v)), "=d" (c)
-               :"0" (__atomic_fool_gcc(v)));
+       __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c) : "m" (*v));
        return c != 0;
 }
 
index 5b61880..12c89df 100644 (file)
@@ -111,6+111,54 @@ extern __inline__ unsigned long ffz(unsigned long word)
        return res ^ 31;
 }
 
+extern __inline__ int find_first_one_bit(void * vaddr, unsigned size)
+{
+       unsigned long *p = vaddr, *addr = vaddr;
+       int res;
+       unsigned long num;
+
+       if (!size)
+               return 0;
+
+       while (!*p++)
+       {
+               if (size <= 32)
+                       return (p - addr) << 5;
+               size -= 32;
+       }
+
+       num = *--p;
+       __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+                             : "=d" (res) : "d" (num & -num));
+       return ((p - addr) << 5) + (res ^ 31);
+}
+
+extern __inline__ int find_next_one_bit (void *vaddr, int size,
+                                     int offset)
+{
+       unsigned long *addr = vaddr;
+       unsigned long *p = addr + (offset >> 5);
+       int set = 0, bit = offset & 31UL, res;
+
+       if (offset >= size)
+               return size;
+
+       if (bit) {
+               unsigned long num = *p & (~0UL << bit);
+
+               /* Look for one in first longword */
+               __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+                                     : "=d" (res) : "d" (num & -num));
+               if (res < 32)
+                       return (offset & ~31UL) + (res ^ 31);
+                set = 32 - bit;
+               p++;
+       }
+       /* No one yet, search remaining full bytes for a one */
+       res = find_first_one_bit (p, size - 32 * (p - addr));
+       return (offset + set + res);
+}
+
 /* Bitmap functions for the minix filesystem */
 
 extern __inline__ int
index 4f9595a..eb9f6f7 100644 (file)
@@ -108,7+108,6 @@ static inline unsigned int csum_fold(unsigned int sum)
  * in icmp.c
  */
 
-#if 1
 static inline unsigned short
 ip_compute_csum(unsigned char * buff, int len)
 {
@@ -124,52+123,5 @@ ip_compute_csum(unsigned char * buff, int len)
                : "0" (csum_partial(buff, len, 0)));
        return ~sum;
 }
-#else
-static inline unsigned short
-ip_compute_csum(unsigned char * buff, int len)
-{
-       unsigned long sum = 0;
-
-  /* Do the first multiple of 4 bytes and convert to 16 bits. */
-  if (len > 3)
-    {
-      int dummy;
-      __asm__ ("subql #1,%2\n\t"
-              "1:\t"
-              "movel %1@+,%/d0\n\t"
-              "addxl %/d0,%0\n\t"
-              "dbra %2,1b\n\t"
-              "movel %0,%/d0\n\t"
-              "swap %/d0\n\t"
-              "addxw %/d0,%0\n\t"
-              "clrw %/d0\n\t"
-              "addxw %/d0,%0"
-              : "=d" (sum), "=a" (buff), "=d" (dummy)
-              : "0" (sum), "1" (buff), "2" (len >> 2)
-              : "d0");
-    }
-  if (len & 2)
-    {
-      __asm__ ("addw %1@+,%0\n\t"
-              "addxw %2,%0"
-              : "=d" (sum), "=a" (buff)
-              : "d" (0), "0" (sum), "1" (buff));
-    }
-  if (len & 1)
-    {
-      __asm__ ("movew %1@,%/d0\n\t"
-              "clrb %/d0\n\t"
-              "addw %/d0,%0\n\t"
-              "clrw %/d0\n\t"
-              "addxw %/d0,%0"
-              : "=d" (sum)
-              : "a" (buff), "0" (sum)
-              : "d0");
-    }
-
-       sum =~sum;
-       return(sum & 0xffff);
-}
-#endif
 
 #endif /* _M68K_CHECKSUM_H */
index c6dc656..cb43d15 100644 (file)
@@ -12,11+12,6 @@ typedef unsigned long elf_greg_t;
 #define ELF_NGREG 20 /* d1-d7/a0-a6/d0/usp/orig_d0/sr/pc/fmtvec */
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
-/* XXX temporary */
-/*
-typedef unsigned long elf_fpregset_t;
-*/
-
 typedef struct user_m68kfp_struct elf_fpregset_t;
 
 #endif
index 00c52e8..7ec3d6f 100644 (file)
@@ -14,7+14,6 @@ do {  \
                __asm__ __volatile__("pflusha\n"::); \
 } while (0)
 
-#if 1
 static inline void __flush_tlb_one(unsigned long addr)
 {
        if (m68k_is040or060) {
@@ -24,9+23,6 @@ static inline void __flush_tlb_one(unsigned long addr)
        } else
                __asm__ __volatile__("pflush #0,#0,(%0)" : : "a" (addr));
 }
-#else
-#define __flush_tlb_one(addr) __flush_tlb()
-#endif
 
 #define flush_tlb() __flush_tlb()
 #define flush_tlb_all() flush_tlb()
@@ -573,15+569,14 @@ 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.
+ * swapping hasn't been working on the 68040.
  */
 
-#if 0
 #define SWP_TYPE(entry)  (((entry) >> 2) & 0x7f)
+#if 0
 #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
diff --git a/include/asm-m68k/serial.h b/include/asm-m68k/serial.h
new file mode 100644 (file)
index 0000000..a9a086f
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * include/linux/serial.h
+ *
+ * Copyright (C) 1992 by Theodore Ts'o.
+ * 
+ * Redistribution of this file is permitted under the terms of the GNU 
+ * Public License (GPL)
+ */
+
+#ifndef _M68K_SERIAL_H
+#define _M68K_SERIAL_H
+
+
+/* m68k serial port types are numbered from 100 to avoid interference
+ * with the PC types (1..4)
+ */
+#define PORT_UNKNOWN   0
+#define PORT_8250      1
+#define PORT_16450     2
+#define PORT_16550     3
+#define PORT_16550A    4
+#define PORT_CIRRUS     5
+#define SER_SCC_NORM   100     /* standard SCC channel */
+#define        SER_SCC_DMA     101     /* SCC channel with DMA support */
+#define        SER_MFP_CTRL    102     /* standard MFP port with modem control signals */
+#define        SER_MFP_BARE    103     /* MFP port without modem controls */
+#define        SER_MIDI        104     /* Atari MIDI */
+#define        SER_AMIGA       105     /* Amiga built-in serial port */
+#define SER_IOEXT      106     /* Amiga GVP IO-Extender (16c552) */
+#define SER_MFC_III    107     /* Amiga BSC Multiface Card III (MC68681) */
+
+
+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 ASYNC_CLOSING_WAIT_INF 0
+#define ASYNC_CLOSING_WAIT_NONE        65535
+
+/* This function tables does the abstraction from the underlying
+ * hardware:
+ *
+ *   init(): Initialize the port as necessary, set RTS and DTR and
+ *      enable interrupts. It does not need to set the speed and other
+ *      parameters, because change_speed() is called, too.
+ *   deinit(): Stop and shutdown the port (e.g. disable interrupts, ...)
+ *   enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
+ *      independently from other interrupt sources. If the int is
+ *      enabled, the transmitter should also be restarted, i.e. if there
+ *      are any chars to be sent, they should be put into the Tx
+ *      register. The real en/disabling of the interrupt may be a no-op
+ *      if there is no way to do this or it is too complex. This Tx ints
+ *      are just disabled to save some interrupts if the transmitter is
+ *      stopped anyway. But the restarting must be implemented!
+ *   check_custom_divisor(): Check the given custom divisor for legality
+ *      and return 0 if OK, non-zero otherwise.
+ *   change_speed(): Set port speed, character size, number of stop
+ *      bits and parity from the termios structure. If the user wants
+ *      to set the speed with a custom divisor, he is required to
+ *      check the baud_base first!
+ *   throttle(): Set or clear the RTS line according to 'status'.
+ *   set_break(): Set or clear the 'Send a Break' flag.
+ *   get_serial_info(): Fill in the baud_base and custom_divisor
+ *      fields of a serial_struct. It may also modify other fields, if
+ *      needed.
+ *   get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
+ *   set_modem_info(): Set the status of RTS and DTR according to
+ *      'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
+ *   ioctl(): Process any port-specific ioctl's. This pointer may be
+ *      NULL, if the port has no own ioctl's.
+ *   stop_receive(): Turn off the Rx part of the port, so no more characters
+ *      will be received. This is called before shutting the port down.
+ *   trans_empty(): Return !=0 if there are no more characters still to be
+ *      sent out (Tx buffer register and FIFOs empty)
+ *   check_open(): Is called before the port is opened. The driver can check
+ *      if that's ok and return an error code, or keep track of the opening
+ *      even before init() is called. Use deinit() for matching closing of the
+ *      port.
+ *
+ */
+
+struct async_struct;
+
+typedef struct {
+       void (*init)( struct async_struct *info );
+       void (*deinit)( struct async_struct *info, int leave_dtr );
+       void (*enab_tx_int)( struct async_struct *info, int enab_flag );
+       int  (*check_custom_divisor)( struct async_struct *info, int baud_base,
+                                    int divisor );
+       void (*change_speed)( struct async_struct *info );
+       void (*throttle)( struct async_struct *info, int status );
+       void (*set_break)( struct async_struct *info, int break_flag );
+       void (*get_serial_info)( struct async_struct *info,
+                               struct serial_struct *retinfo );
+       unsigned int (*get_modem_info)( struct async_struct *info );
+       int  (*set_modem_info)( struct async_struct *info, int new_dtr,
+                              int new_rts );
+       int  (*ioctl)( struct tty_struct *tty, struct file *file,
+                     struct async_struct *info, unsigned int cmd,
+                     unsigned long arg );
+       void (*stop_receive)( struct async_struct *info );
+       int  (*trans_empty)( struct async_struct *info );
+       int  (*check_open)( struct async_struct *info, struct tty_struct *tty,
+                          struct file *file );
+} SERIALSWITCH;
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field
+ */
+#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+                                  on the callout port */
+#define ASYNC_FOURPORT  0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ASYNC_SAK      0x0004  /* Secure Attention Key (Orange book) */
+#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ASYNC_SPD_MASK 0x0030
+#define ASYNC_SPD_HI   0x0010  /* Use 56000 instead of 38400 bps */
+
+#define ASYNC_SPD_VHI  0x0020  /* Use 115200 instead of 38400 bps */
+#define ASYNC_SPD_CUST 0x0030  /* Use user-specified divisor */
+
+#define ASYNC_SKIP_TEST        0x0040 /* Skip UART test during autoconfiguration */
+#define ASYNC_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ASYNC_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ASYNC_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ASYNC_FLAGS    0x0FFF  /* Possible legal async flags */
+#define ASYNC_USR_MASK 0x0430  /* Legal flags that non-privileged
+                                * users can set or reset */
+
+/* Internal flags used only by drivers/char/m68kserial.c */
+#define ASYNC_INITIALIZED      0x80000000 /* Serial port was initialized */
+#define ASYNC_CALLOUT_ACTIVE   0x40000000 /* Call out device is active */
+#define ASYNC_NORMAL_ACTIVE    0x20000000 /* Normal device is active */
+#define ASYNC_BOOT_AUTOCONF    0x10000000 /* Autoconfigure port on bootup */
+#define ASYNC_CLOSING          0x08000000 /* Serial port is closing */
+#define ASYNC_CTS_FLOW         0x04000000 /* Do CTS flow control */
+#define ASYNC_CHECK_CD         0x02000000 /* i.e., CLOCAL */
+
+/*
+ * Serial input interrupt line counters -- external structure
+ * Four lines can interrupt: CTS, DSR, RI, DCD
+ */
+struct serial_icounter_struct {
+       int cts, dsr, rng, dcd;
+       int reserved[16];
+};
+
+
+#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
+ */
+
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+       __u32   cts, dsr, rng, dcd;     
+};
+
+struct async_struct {
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+       int                     flags;          /* defined in tty.h */
+       int                     hub6;           /* HUB6 plus one */
+       int                     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;
+       int                     IER;    /* Interrupt Enable Register */
+       int                     MCR;    /* Modem control register */
+       int                     MCR_noint; /* MCR with interrupts off */
+       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;
+       struct wait_queue       *delta_msr_wait;
+       struct async_icount     icount; /* kernel counters for the 4 input interrupts */
+       struct async_struct     *next_port; /* For the linked list */
+       struct async_struct     *prev_port;
+       void                    *board_base; /* board-base address for use with
+                                               boards carrying several UART's,
+                                               like some Amiga boards. */
+       unsigned short          nr_uarts;    /* UART-counter, that indicates
+                                               how manu UART's there are on
+                                               the board.  If the board has a
+                                               IRQ-register, this can be used
+                                               to check if any of the uarts,
+                                               on the board has requested an
+                                               interrupt, instead of checking
+                                               IRQ-registers on all UART's */
+       SERIALSWITCH            *sw;            /* functions to manage this port */
+};
+
+#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
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Export to allow PCMCIA to use this - Dave Hinds */
+extern int register_serial(struct serial_struct *req);
+extern void unregister_serial(int line);
+extern struct async_struct rs_table[];
+extern task_queue tq_serial;
+
+
+/*
+ * 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 async_struct *info, int event)
+{
+       info->event |= 1 << event;
+       queue_task_irq(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+static __inline__ void rs_receive_char( struct async_struct *info,
+                                           int ch, int err )
+{
+       struct tty_struct *tty = info->tty;
+       
+       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+               return;
+       tty->flip.count++;
+       if (err == TTY_BREAK) {
+               if (info->flags & ASYNC_SAK)
+                       do_SAK(tty);
+       }
+       *tty->flip.flag_buf_ptr++ = err;
+       *tty->flip.char_buf_ptr++ = ch;
+       queue_task_irq(&tty->flip.tqueue, &tq_timer);
+}
+
+static __inline__ int rs_get_tx_char( struct async_struct *info )
+{
+       unsigned char ch;
+       
+       if (info->x_char) {
+               ch = info->x_char;
+               info->x_char = 0;
+               return( ch );
+       }
+
+       if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped)
+               return( -1 );
+
+       ch = info->xmit_buf[info->xmit_tail++];
+       info->xmit_tail &= SERIAL_XMIT_SIZE - 1;
+       if (--info->xmit_cnt < WAKEUP_CHARS)
+               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+       return( ch );
+}
+
+static __inline__ int rs_no_more_tx( struct async_struct *info )
+{
+       return( info->xmit_cnt <= 0 ||
+                       info->tty->stopped ||
+                       info->tty->hw_stopped );
+}
+
+static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd )
+
+{
+       /* update input line counter */
+       info->icount.dcd++;
+       wake_up_interruptible(&info->delta_msr_wait);
+
+       if (info->flags & ASYNC_CHECK_CD) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttyS%d CD now %s...", info->line,
+                      dcd ? "on" : "off");
+#endif         
+               if (dcd) {
+                       wake_up_interruptible(&info->open_wait);
+               } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                            (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("scheduling hangup...");
+#endif
+                       queue_task_irq(&info->tqueue_hangup,
+                                      &tq_scheduler);
+               }
+       }
+}
+
+
+void rs_stop( struct tty_struct *tty );
+void rs_start( struct tty_struct *tty );
+
+static __inline__ void rs_check_cts( struct async_struct *info, int cts )
+{
+       /* update input line counter */
+       info->icount.cts++;
+       wake_up_interruptible(&info->delta_msr_wait);
+       
+       if ((info->flags & ASYNC_CTS_FLOW) && info->tty)
+               if (info->tty->hw_stopped) {
+                       if (cts) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->tty->hw_stopped = 0;
+                               rs_start( info->tty );
+                               rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!cts) {
+                               info->tty->hw_stopped = 1;
+                               rs_stop( info->tty );
+                       }
+               }
+               
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _M68K_SERIAL_H */
index a7563e5..242027a 100644 (file)
@@ -64,6+64,7 @@ struct __xchg_dummy { unsigned long a[100]; };
 #endif /* machine compilation types */ 
 #define cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
 #define nop() __asm__ __volatile__ ("nop"::)
+#define mb()  __asm__ __volatile__ (""   : : :"memory")
 
 #define save_flags(x) \
 __asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
index b2441c8..9c5a38a 100644 (file)
 #define SHMALL                         /* max shm system wide (pages) */ \
        (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
 /*
- * This constant is very large but the ABI in it's wisdom says ...
+ * This constant is very large but the ABI in its wisdom says ...
  */
 #define        SHMLBA 0x40000                  /* attach addr a multiple of this */
 #define SHMSEG SHMMNI                  /* max shared segs per process */
index 9fa5f63..bf1f31a 100644 (file)
@@ -290,7+290,7 @@ static int sun_floppy_init(void)
                /* We certainly don't have a floppy controller. */
                goto no_sun_fdc;
        }
-       /* Well, try and find one. */
+       /* Well, try to find one. */
        tnode = prom_getchild(prom_root_node);
        fd_node = prom_searchsiblings(tnode, "obio");
        if(fd_node != 0) {
index 8e6aec9..0664988 100644 (file)
 #define NMI_TRAP \
         rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop;
 
-/* Window overflows/underflows are special and we need to try and be as
+/* Window overflows/underflows are special and we need to try to be as
  * efficient as possible here....
  */
 #define WINDOW_SPILL \
index ba71156..3462769 100644 (file)
 
 #ifndef __ASSEMBLY__
 /* The debug vector is passed in %o1 at boot time.  It is a pointer to
- * a structure in the debuggers address space.  Here is it's format.
+ * a structure in the debuggers address space.  Here is its format.
  */
 
 typedef unsigned int (*debugger_funct)(void);
index 1c5ab02..e3d8ddb 100644 (file)
@@ -26,7+26,7 @@ extern struct prom_cpuinfo linux_cpus[NCPUS];
 /* Per processor Sparc parameters we need. */
 
 struct cpuinfo_sparc {
-       unsigned long udelay_val; /* thats it */
+       unsigned long udelay_val; /* that's it */
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
index 4e9854d..5c2826d 100644 (file)
@@ -40,7+40,7 @@ extern struct linux_romvec *romvec;
 #define halt() romvec->pv_halt()
 
 /* When a context switch happens we must flush all user windows so that
- * the windows of the current process are flushed onto it's stack. This
+ * the windows of the current process are flushed onto its stack. This
  * way the windows are all clean for the next process and the stack
  * frames are up to date.
  */
index 670349f..b373e52 100644 (file)
@@ -129,7+129,7 @@ enum machine_type {
 
 #ifdef linux
 #include <asm/page.h>
-#ifdef __i386__
+#if defined(__i386__) || defined(__mc68000__)
 #define SEGMENT_SIZE   1024
 #else
 #ifndef SEGMENT_SIZE
dissimilarity index 91%
index 68a8188..520935d 100644 (file)
-
-#ifndef _AFFS_FS_H
-#define _AFFS_FS_H
-
-#include <linux/types.h>
-/*
- * The affs filesystem constants/structures
- */
-
-#define AFFS_BLOCK_BITS 9
-#define AFFS_BLOCK_SIZE 512
-
-#define AFFS_BUFFER_BITS 9
-#define AFFS_BUFFER_SIZE 512
-
-#define AFFS_BLOCK_NUMBER(X) (X<<1)
-
-#define AFFS_SUPER_MAGIC 0xadff
-
-/* Get the filesystem block size given an inode. */
-#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size)
-
-/* Read the device block that contains filesystem block ("sector"). */
-
-static inline struct buffer_head *affs_sread(int dev,int sector,void **start)
-{
-       struct buffer_head *bh;
-       int mask;
-
-       bh = bread (dev, sector >> (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS), 1024);
-       if (!bh)
-               return NULL;
-       mask = (1 << (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS)) - 1;
-       *start = bh->b_data + ((sector & mask) << AFFS_BLOCK_BITS);
-       return bh;
-}
-
-/* Use affs_sread() to read a "sector", but take the filesystems partition
-   offset into account. */
-
-static inline struct buffer_head *affs_pread(struct inode *inode,
-                                            int sector, void **start)
-{
-       int offset = inode->i_sb->u.affs_sb.s_partition_offset;
-       return affs_sread (inode->i_dev, sector + offset, start);
-}
-
-/* amigaffs.c prototypes */
-
-extern int affs_get_key_entry (int bsize, void *data, int entry_pos);
-extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos);
-extern int affs_get_fh_hash_link (int bsize, void *fh_data);
-extern int affs_get_file_name (int bsize, void *fh_data, char **name);
-extern int affs_get_extension (int bsize, void *fh_data);
-extern int affs_checksum_block (int bsize, void *data, int *ptype, int *stype);
-
-/* The stuff that follows may be totally unneeded. I have not checked to see 
- which prototypes we are still using.  */
-
-extern int affs_open(struct inode * inode, struct file * filp);
-extern void affs_release(struct inode * inode, struct file * filp);
-extern int affs_lookup(struct inode * dir,const char * name, int len,
-       struct inode ** result);
-extern unsigned long affs_count_free_inodes(struct super_block *sb);
-extern int affs_new_block(int dev);
-extern int affs_free_block(int dev, int block);
-extern int affs_bmap(struct inode *,int);
-
-extern void affs_put_super(struct super_block *);
-extern struct super_block *affs_read_super(struct super_block *,void *,int);
-extern void affs_read_inode(struct inode *);
-extern void affs_put_inode(struct inode *);
-extern void affs_statfs(struct super_block *, struct statfs *, int);
-extern int affs_parent_ino(struct inode *dir);
-extern int affs_lseek(struct inode *, struct file *, off_t, int);
-extern int affs_read(struct inode *, struct file *, char *, int);
-extern int affs_file_read(struct inode *, struct file *, char *, int);
-extern int init_affs_fs(void);
-
-extern struct inode_operations affs_file_inode_operations;
-extern struct inode_operations affs_dir_inode_operations;
-extern struct inode_operations affs_symlink_inode_operations;
-extern struct inode_operations affs_chrdev_inode_operations;
-extern struct inode_operations affs_blkdev_inode_operations;
-
-extern struct file_operations affs_file_operations;
-extern struct file_operations affs_dir_operations;
-
-/* The following macros are used to check for memory leaks. */
-#ifdef LEAK_CHECK
-#define free_s leak_check_free_s
-#define malloc leak_check_malloc
-#define bread leak_check_bread
-#define brelse leak_check_brelse
-extern void * leak_check_malloc(unsigned int size);
-extern void leak_check_free_s(void * obj, int size);
-extern struct buffer_head * leak_check_bread(int dev, int block, int size);
-extern void leak_check_brelse(struct buffer_head * bh);
-#endif /* LEAK_CHECK */
-
-#endif
+#ifndef _AFFS_FS_H
+#define _AFFS_FS_H
+/*
+ * The affs filesystem constants/structures
+ */
+
+#include <linux/types.h>
+#include <linux/amigaffs.h>
+
+#define AFFS_SUPER_MAGIC 0xadff
+
+/* Get the filesystem block size given an inode. */
+#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize)
+
+/* Get the filesystem hash table size given an inode. */
+#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
+
+/* Get the block number bits given an inode */
+#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits)
+
+/* Get the fs type given an inode */
+#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
+
+/* --- Prototypes -----------------------------------------------------------------------------        */
+
+/* amigaffs.c */
+
+extern int                affs_get_key_entry(int bsize, void *data, int entry_pos);
+extern int                affs_find_next_hash_entry(int bsize, void *dir_data, ULONG *hash_pos);
+extern int                affs_get_file_name(int bsize, void *fh_data, char **name);
+extern ULONG              affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype);
+extern void               affs_fix_checksum(int bsize, void *data, int cspos);
+extern void               secs_to_datestamp(int secs, struct DateStamp *ds);
+extern int                prot_to_mode(ULONG prot);
+extern ULONG              mode_to_prot(int mode);
+extern int                affs_fix_hash_pred(struct inode *startino, int startoffset,
+                                             LONG key, LONG newkey);
+extern int                affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey);
+
+/* bitmap. c */
+
+extern int                affs_count_free_blocks(struct super_block *s);
+extern int                affs_count_free_bits(int blocksize, const UBYTE *data);
+extern void               affs_free_block(struct super_block *sb, LONG block);
+extern LONG               affs_new_header(struct inode *inode);
+extern LONG               affs_new_data(struct inode *inode);
+extern void               affs_make_zones(struct super_block *sb);
+
+/* namei.c */
+
+extern int                affs_hash_name(const char *name, int len, int intl, int hashsize);
+extern int                affs_lookup(struct inode *dir,const char *name, int len,
+                                      struct inode **result);
+extern int                affs_unlink(struct inode *dir, const char *name, int len);
+extern int                affs_create(struct inode *dir, const char *name, int len, int mode,
+                                      struct inode **result);
+extern int                affs_mkdir(struct inode *dir, const char *name, int len, int mode);
+extern int                affs_rmdir(struct inode *dir, const char *name, int len);
+extern int                affs_link(struct inode *oldinode, struct inode *dir,
+                                    const char *name, int len);
+extern int                affs_symlink(struct inode *dir, const char *name, int len,
+                                       const char *symname);
+extern int                affs_fixup(struct buffer_head *bh, struct inode *inode);
+extern int                affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+                                      struct inode *new_dir, const char *new_name, int new_len);
+
+/* inode.c */
+
+extern struct buffer_head *affs_bread(kdev_t dev, int block, int size);
+extern void               affs_brelse(struct buffer_head *buf);
+extern void               affs_put_super(struct super_block *);
+extern int                affs_parent_ino(struct inode *dir);
+extern struct super_block *affs_read_super(struct super_block *,void *, int);
+extern void               affs_statfs(struct super_block *, struct statfs *, int bufsiz);
+extern void               affs_read_inode(struct inode *);
+extern void               affs_write_inode(struct inode *);
+extern int                affs_notify_change(struct inode *inode, struct iattr *attr);
+extern void               affs_put_inode(struct inode *);
+extern struct inode      *affs_new_inode(const struct inode *dir);
+extern int                affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
+                                         const char *name, int len, LONG type);
+
+/* file.c */
+
+extern int                affs_bmap(struct inode *inode, int block);
+extern struct buffer_head *affs_getblock(struct inode *inode, int block);
+extern void               affs_truncate(struct inode *);
+extern void               affs_truncate_ofs(struct inode *);
+
+/* dir.c */
+
+extern void               affs_dir_truncate(struct inode *);
+
+/* jump tables */
+
+extern struct inode_operations  affs_file_inode_operations;
+extern struct inode_operations  affs_file_inode_operations_ofs;
+extern struct inode_operations  affs_dir_inode_operations;
+extern struct inode_operations  affs_symlink_inode_operations;
+extern struct inode_operations  affs_chrdev_inode_operations;
+extern struct inode_operations  affs_blkdev_inode_operations;
+
+extern int init_affs_fs(void);
+#endif
index 0e6298d..62785ba 100644 (file)
 #ifndef _AFFS_FS_I
 #define _AFFS_FS_I
 
+#define EXT_CACHE_SIZE 16
+#define MAX_PREALLOC   8       /* MUST be a power of 2 */
+
 /*
  * affs fs inode data in memory
  */
 struct affs_inode_info {
        int i_protect;  /* unused attribute bits */
        int i_parent;   /* parent ino */
+       int i_original; /* if != 0, this is the key of the original */
+       __u32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */
+       __u32 i_data[MAX_PREALLOC]; /* preallocated blocks */
+       short i_max_ext; /* last known extension block */
+       short i_pa_cnt; /* number of preallocated blocks */
+       short i_pa_next;  /* Index of next block in i_data[] */
+       short i_pa_last;  /* Index of next free slot in i_data[] */
+       short i_zone;   /* write zone */
+       unsigned char i_hlink;  /* This is a fake */
+       unsigned char i_pad;
 };
 
 #endif
dissimilarity index 72%
index 377739d..8e70834 100644 (file)
-#ifndef _AFFS_FS_SB
-#define _AFFS_FS_SB
-
-/*
- * super-block data in memory
- *
- * Block numbers are for FFS-sized (normally 512 bytes) blocks.
- *
- */
-
-/* Mount options */
-
-struct affs_options {
-       int offset;
-       int size;
-       int root;
-       int nocase:1;                   /* Ignore case in filenames. */
-       int conv_links:1;               /* convert pathnames symlinks point to */
-};
-
-struct affs_sb_info {
-       int s_partition_offset;         /* Offset to start in blocks. */
-       int s_partition_size;           /* Partition size in blocks. */
-       int s_root_block;               /* Absolute FFS root block number. */
-       int s_block_size;               /* Block size in bytes. */
-       char s_volume_name[42];
-       struct affs_options s_options;
-};
-
-#endif
-
-
-
-
-
-
-
+#ifndef _AFFS_FS_SB
+#define _AFFS_FS_SB
+
+/*
+ * super-block data in memory
+ *
+ * Block numbers are adjusted for their actual size
+ *
+ */
+
+#include <linux/amigaffs.h>
+
+#define MAX_ZONES              8
+#define AFFS_DATA_MIN_FREE     30      /* Percentage of free blocks needed for a data zone */
+#define AFFS_HDR_MIN_FREE      10      /* Same for header blocks */
+
+struct affs_bm_info {
+       struct buffer_head *bm_bh;      /* Buffer for bitmap. */
+       int bm_free;                    /* Free blocks. */
+       int bm_size;                    /* Size in bits, rounded to multiple of 32. */
+       int bm_firstblk;                /* Block number of first bit in this map */
+};
+
+struct affs_zone {
+       unsigned long z_ino;            /* Associated inode number */
+       struct affs_bm_info *z_bm;      /* Zone lies in this bitmap */
+       int z_start;                    /* Index of first word in bitmap */
+       int z_zone_no;                  /* Zone number */
+       unsigned long z_lru_time;       /* Time of last usage */
+};
+
+struct affs_sb_info {
+       int s_partition_size;           /* Partition size in blocks. */
+       int s_root_block;               /* FFS root block number. */
+       int s_hashsize;                 /* Size of hash table. */
+       unsigned long s_flags;          /* See below. */
+       short s_uid;                    /* uid to override */
+       short s_gid;                    /* gid to override */
+       umode_t s_mode;                 /* mode to override */
+       int s_reserved;                 /* Number of reserved blocks. */
+       struct buffer_head *s_root_bh;  /* Cached root block. */
+       struct affs_bm_info *s_bitmap;  /* Bitmap infos. */
+       int s_bm_count;                 /* Number of bitmap blocks. */
+       int s_nextzone;                 /* Next zone to look for free blocks. */
+       int s_num_zones;                /* Total number of zones. */
+       struct affs_zone *s_zones;      /* The zones themselfes. */
+       char *s_zonemap;                /* Bitmap for zones. */
+       char *s_prefix;                 /* Prefix for volumes and assignes. */
+       int s_prefix_len;               /* Length of prefix. */
+       char s_volume[32];              /* Volume prefix for absolute symlinks. */
+};
+
+#define SF_INTL                0x0001          /* International filesystem. */
+#define SF_BM_VALID    0x0002          /* Bitmap is valid. */
+#define SF_IMMUTABLE   0x0004          /* Protection bits cannot be changed */
+#define SF_QUIET       0x0008          /* chmod errors will be not reported */
+#define SF_SETUID      0x0010          /* Ignore Amiga uid */
+#define SF_SETGID      0x0020          /* Ignore Amiga gid */
+#define SF_SETMODE     0x0040          /* Ignore Amiga protection bits */
+#define SF_USE_MP      0x0080          /* Use uid and gid from mount point */
+#define SF_MUFS                0x0100          /* Use MUFS uid/gid mapping */
+#define SF_OFS         0x0200          /* Old filesystem */
+#define SF_PREFIX      0x0400          /* Buffer for prefix is allocated */
+#define SF_VERBOSE     0x0800          /* Talk about fs when mounting */
+
+#endif
diff --git a/include/linux/affs_hardblocks.h b/include/linux/affs_hardblocks.h
new file mode 100644 (file)
index 0000000..ea3cc5a
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef        AFFS_HARDBLOCKS_H
+#define        AFFS_HARDBLOCKS_H
+
+/* Just the needed definitions for the RDB of an Amiga HD. */
+
+#ifndef AMIGAFFS_H
+#include <linux/amigaffs.h>
+#endif
+
+struct RigidDiskBlock {
+       ULONG   rdb_ID;
+       ULONG   rdb_SummedLongs;
+       LONG    rdb_ChkSum;
+       ULONG   rdb_HostID;
+       ULONG   rdb_BlockBytes;
+       ULONG   rdb_Flags;
+       ULONG   rdb_BadBlockList;
+       ULONG   rdb_PartitionList;
+       ULONG   rdb_FileSysHeaderList;
+       ULONG   rdb_DriveInit;
+       ULONG   rdb_Reserved1[6];
+       ULONG   rdb_Cylinders;
+       ULONG   rdb_Sectors;
+       ULONG   rdb_Heads;
+       ULONG   rdb_Interleave;
+       ULONG   rdb_Park;
+       ULONG   rdb_Reserved2[3];
+       ULONG   rdb_WritePreComp;
+       ULONG   rdb_ReducedWrite;
+       ULONG   rdb_StepRate;
+       ULONG   rdb_Reserved3[5];
+       ULONG   rdb_RDBBlocksLo;
+       ULONG   rdb_RDBBlocksHi;
+       ULONG   rdb_LoCylinder;
+       ULONG   rdb_HiCylinder;
+       ULONG   rdb_CylBlocks;
+       ULONG   rdb_AutoParkSeconds;
+       ULONG   rdb_HighRDSKBlock;
+       ULONG   rdb_Reserved4;
+       char    rdb_DiskVendor[8];
+       char    rdb_DiskProduct[16];
+       char    rdb_DiskRevision[4];
+       char    rdb_ControllerVendor[8];
+       char    rdb_ControllerProduct[16];
+       char    rdb_ControllerRevision[4];
+       ULONG   rdb_Reserved5[10];
+};
+
+#define        IDNAME_RIGIDDISK        0x5244534B      /* "RDSK" */
+
+struct PartitionBlock {
+       ULONG   pb_ID;
+       ULONG   pb_SummedLongs;
+       LONG    pb_ChkSum;
+       ULONG   pb_HostID;
+       ULONG   pb_Next;
+       ULONG   pb_Flags;
+       ULONG   pb_Reserved1[2];
+       ULONG   pb_DevFlags;
+       UBYTE   pb_DriveName[32];
+       ULONG   pb_Reserved2[15];
+       ULONG   pb_Environment[17];
+       ULONG   pb_EReserved[15];
+};
+
+#define        IDNAME_PARTITION        0x50415254      /* "PART" */
+
+#define RDB_ALLOCATION_LIMIT   16
+
+#endif /* AFFS_HARDBLOCKS_H */
diff --git a/include/linux/amigaffs.h b/include/linux/amigaffs.h
new file mode 100644 (file)
index 0000000..68a5dad
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef AMIGAFFS_H
+#define AMIGAFFS_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+/* Ugly macros make the code more pretty. */
+
+#define GET_END_PTR(st,p,sz)            ((st *)((char *)(p)+((sz)-sizeof(st))))
+#define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey])
+#define AFFS_BLOCK(data,ino,blk)        ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-blk]
+
+#define FILE_END(p,i)  GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END(p,i)  GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
+#define DIR_END(p,i)   GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
+#define LINK_END(p,i)  GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END_S(p,s)        GET_END_PTR(struct root_end,p,(s)->s_blocksize)
+
+/* Only for easier debugging if need be */
+#define affs_bread     bread
+#define affs_brelse    brelse
+
+#ifdef __LITTLE_ENDIAN
+#define BO_EXBITS      0x18UL
+#elif defined(__BIG_ENDIAN)
+#define BO_EXBITS      0x00UL
+#else
+#error Endianess must be known for affs to work.
+#endif
+
+/* The following constants will be checked against the values read native */
+
+#define FS_OFS         0x444F5300
+#define FS_FFS         0x444F5301
+#define FS_INTLOFS     0x444F5302
+#define FS_INTLFFS     0x444F5303
+#define FS_DCOFS       0x444F5304
+#define FS_DCFFS       0x444F5305
+#define MUFS_FS                0x6d754653   /* 'muFS' */
+#define MUFS_OFS       0x6d754600   /* 'muF\0' */
+#define MUFS_FFS       0x6d754601   /* 'muF\1' */
+#define MUFS_INTLOFS   0x6d754602   /* 'muF\2' */
+#define MUFS_INTLFFS   0x6d754603   /* 'muF\3' */
+#define MUFS_DCOFS     0x6d754604   /* 'muF\4' */
+#define MUFS_DCFFS     0x6d754605   /* 'muF\5' */
+
+typedef __u32  ULONG;
+typedef __u16  UWORD;
+typedef __u8   UBYTE;
+
+typedef __s32  LONG;
+typedef __s16  WORD;
+typedef __s8   BYTE;
+
+struct DateStamp
+{
+  ULONG ds_Days;
+  ULONG ds_Minute;
+  ULONG ds_Tick;
+};
+
+#define T_SHORT                2
+#define T_LIST         16
+#define T_DATA         8
+
+#define ST_LINKFILE    -4
+#define ST_FILE                -3
+#define ST_ROOT                1
+#define ST_USERDIR     2
+#define ST_SOFTLINK    3
+#define ST_LINKDIR     4
+
+struct root_front
+{
+  LONG primary_type;
+  ULONG spare1[2];
+  ULONG hash_size;
+  ULONG spare2;
+  ULONG checksum;
+  ULONG hashtable[0];
+};
+
+struct root_end
+{
+  LONG bm_flag;
+  ULONG bm_keys[25];
+  ULONG bm_extend;
+  struct DateStamp dir_altered;
+  UBYTE disk_name[40];
+  struct DateStamp disk_altered;
+  struct DateStamp disk_made;
+  ULONG spare1[3];
+  LONG secondary_type;
+};
+
+struct dir_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+  ULONG hashtable[0];
+};
+
+struct dir_end
+{
+  ULONG spare1;
+  UWORD owner_uid;
+  UWORD owner_gid;
+  ULONG protect;
+  ULONG spare2;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE dir_name[32];
+  ULONG spare3[2];
+  ULONG link_chain;
+  ULONG spare4[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare5;
+  LONG secondary_type;
+};
+
+struct file_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG block_count;
+  ULONG unknown1;
+  ULONG first_data;
+  ULONG checksum;
+  ULONG blocks[0];
+};
+
+struct file_end
+{
+  ULONG spare1;
+  UWORD owner_uid;
+  UWORD owner_gid;
+  ULONG protect;
+  ULONG byte_size;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE file_name[32];
+  ULONG spare2;
+  ULONG original;      /* not really in file_end */
+  ULONG link_chain;
+  ULONG spare3[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG extension;
+  LONG secondary_type;
+};
+
+struct hlink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+};
+
+struct hlink_end
+{
+  ULONG spare1;
+  UWORD owner_uid;
+  UWORD owner_gid;
+  ULONG protect;
+  UBYTE comment[92];
+  struct DateStamp created;
+  UBYTE link_name[32];
+  ULONG spare2;
+  ULONG original;
+  ULONG link_chain;
+  ULONG spare3[5];
+  ULONG hash_chain;
+  ULONG parent;
+  ULONG spare4;
+  LONG secondary_type;
+};
+
+struct slink_front
+{
+  LONG primary_type;
+  ULONG own_key;
+  ULONG spare1[3];
+  ULONG checksum;
+  UBYTE        symname[288];   /* depends on block size */
+};
+
+/* Permission bits */
+
+#define FIBF_OTR_READ          0x8000
+#define FIBF_OTR_WRITE         0x4000
+#define FIBF_OTR_EXECUTE       0x2000
+#define FIBF_OTR_DELETE                0x1000
+#define FIBF_GRP_READ          0x0800
+#define FIBF_GRP_WRITE         0x0400
+#define FIBF_GRP_EXECUTE       0x0200
+#define FIBF_GRP_DELETE                0x0100
+
+#define FIBF_SCRIPT            0x0040
+#define FIBF_PURE              0x0020          /* no use under linux */
+#define FIBF_ARCHIVE           0x0010          /* never set, always cleared on write */
+#define FIBF_READ              0x0008          /* 0 means allowed */
+#define FIBF_WRITE             0x0004          /* 0 means allowed */
+#define FIBF_EXECUTE           0x0002          /* 0 means allowed, ignored under linux */
+#define FIBF_DELETE            0x0001          /* 0 means allowed */
+
+#define FIBF_OWNER             0x000F          /* Bits pertaining to owner */
+
+#define AFFS_UMAYWRITE(prot)   (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
+#define AFFS_UMAYREAD(prot)    ((prot) & FIBF_READ)
+#define AFFS_UMAYEXECUTE(prot) (((prot) & (FIBF_SCRIPT|FIBF_READ)) == (FIBF_SCRIPT|FIBF_READ))
+#define AFFS_GMAYWRITE(prot)   (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\
+                                                       (FIBF_GRP_WRITE|FIBF_GRP_DELETE))
+#define AFFS_GMAYREAD(prot)    ((prot) & FIBF_GRP_READ)
+#define AFFS_GMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_GRP_READ))==(FIBF_SCRIPT|FIBF_GRP_READ))
+#define AFFS_OMAYWRITE(prot)   (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\
+                                                       (FIBF_OTR_WRITE|FIBF_OTR_DELETE))
+#define AFFS_OMAYREAD(prot)    ((prot) & FIBF_OTR_READ)
+#define AFFS_OMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_OTR_READ))==(FIBF_SCRIPT|FIBF_OTR_READ))
+
+#endif
index a028fb2..535cdef 100644 (file)
 #endif
 
 /* These two have identical behaviour; use the second one if DOS fdisk gets
-   confused about extended/logical partitions starting past cylinder 1023. */  
+   confused about extended/logical partitions starting past cylinder 1023. */
 #define DOS_EXTENDED_PARTITION 5
 #define LINUX_EXTENDED_PARTITION 0x85
 
index 4f49647..4d33990 100644 (file)
@@ -8,7+8,7 @@
 
 #define HD_IRQ 14              /* the standard disk interrupt */
 
-/* ide.c has it's own port definitions in "ide.h" */
+/* ide.c has its own port definitions in "ide.h" */
 
 /* Hd controller regs. Ref: IBM AT Bios-listing */
 #define HD_DATA                0x1f0   /* _CTL when writing */
index 7f972a5..9e177e3 100644 (file)
@@ -111,18+111,16 @@ struct arphdr
 
 #define ARPD_UPDATE    0x01
 #define ARPD_LOOKUP    0x02
+#define ARPD_FLUSH     0x03
 
 struct arpd_request
 {
        unsigned short  req;                    /* request type */
        __u32           ip;                     /* ip address of entry */
-       __u32           mask;                   /* netmask - used for proxy */
+       unsigned long   dev;                    /* Device entry is tied to */
+       unsigned long   stamp;
+       unsigned long   updated;
        unsigned char   ha[MAX_ADDR_LEN];       /* Hardware address */
-       unsigned long   last_used;              /* For expiry */
-       unsigned long   last_updated;           /* For expiry */
-       unsigned int    flags;                  /* Control status */
-       struct device   *dev;                   /* Device entry is tied to */
-       int             loc;                    /* Debugging call location */
 };
 
 #endif /* _LINUX_IF_ARP_H */
index 52afe58..bacb44b 100644 (file)
@@ -3,7+3,7 @@
  *             created for each DLCI associated with a FRAD.  The FRAD driver
  *             is not truly a network device, but the lower level device
  *             handler.  This allows other FRAD manufacturers to use the DLCI
- *             code, including it's RFC1490 encapsulation along side the current
+ *             code, including its RFC1490 encapsulation alongside the current
  *             implementation for the Sangoma cards.
  *
  * Version:    @(#)if_ifrad.h  0.15    31 Mar 96
index c8e156e..f839f98 100644 (file)
@@ -129,7+129,7 @@ struct sockaddr_in {
 
 /*
  *     IPv6 definitions as we start to include them. This is just
- *     a beginning dont get excited 8)
+ *     a beginning -- don't get excited 8)
  */
  
 struct in_addr6
index 8e9c037..bc33fa1 100644 (file)
@@ -184,7+184,7 @@ typedef struct {
 #ifdef CONFIG_ISDN_PPP
 
 #ifdef CONFIG_ISDN_PPP_VJ
-#  include "/usr/src/linux/drivers/net/slhc.h"
+#  include <net/slhc_vj.h>
 #endif
 
 #include <linux/ppp_defs.h>
index ab8d35d..875fc81 100644 (file)
@@ -2,7+2,7 @@
  *
  * Linux ISDN subsystem
  *
- * Definition of the interface between the subsystem and it's lowlevel-drivers.
+ * Definition of the interface between the subsystem and its low-level drivers.
  *
  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
  * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg
@@ -136,7+136,7 @@ typedef struct {
  * The interface-struct itself (initialized at load-time of lowlevel-driver)
  *
  * See Documentation/isdn/INTERFACE for a description, how the communication
- * between the ISDN subsystem and it's drivers is done.
+ * between the ISDN subsystem and its drivers is done.
  *
  */
 typedef struct {
index e07049f..cac9f5d 100644 (file)
@@ -57,8+57,13 @@ extern int kill_sl(int sess, int sig, int priv);
 asmlinkage int printk(const char * fmt, ...)
        __attribute__ ((format (printf, 1, 2)));
 
-#define pr_debug(show,fmt,arg...) \
-       do { if (show) printk(KERN_DEBUG fmt,##arg); } while (0)
+#if DEBUG
+#define pr_debug(fmt,arg...) \
+       printk(KERN_DEBUG fmt,##arg)
+#else
+#define pr_debug(fmt,arg...) \
+       do { } while (0)
+#endif
 
 #define pr_info(fmt,arg...) \
        printk(KERN_INFO fmt,##arg)
index 0d9606d..b3708ef 100644 (file)
@@ -1,6+1,10 @@
 #ifndef _LINUX_MATH_EMU_H
 #define _LINUX_MATH_EMU_H
 
+
+void restore_i387_soft(struct _fpstate *buf);
+struct _fpstate * save_i387_soft(struct _fpstate * buf);
+
 struct fpu_reg {
        char sign;
        char tag;
index 55b535f..2d43892 100644 (file)
@@ -124,4+124,22 @@ outb_p((val),RTC_PORT(1)); \
 #define RTC_IRQP_READ  0x0b            /* Read periodic IRQ rate (Hz)  */
 #define RTC_IRQP_SET   0x0c            /* Set periodic IRQ rate (Hz)   */
 
+/*
+ * The struct used to pass data via the above ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel 
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+
+struct rtc_time {
+       int tm_sec;
+       int tm_min;
+       int tm_hour;
+       int tm_mday;
+       int tm_mon;
+       int tm_year;
+       int tm_wday;
+       int tm_yday;
+       int tm_isdst;
+};
+
 #endif /* _MC146818RTC_H */
index 38aa312..6772a60 100644 (file)
@@ -112,7+112,7 @@ struct igmpmsg
 };
 
 /*
- *     Thats all usermode folks
+ *     That's all usermode folks
  */
 
 #ifdef __KERNEL__
index c5c5304..ddc7ce9 100644 (file)
@@ -256,6+256,21 @@ extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
 /* fatfs_syms.c */
 extern int init_fat_fs(void);
 
+/* vfat/namei.c - these are for dmsdos */
+extern int vfat_create(struct inode *dir,const char *name,int len,int mode,
+                      struct inode **result);
+extern int vfat_unlink(struct inode *dir,const char *name,int len);
+extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
+extern int vfat_rmdir(struct inode *dir,const char *name,int len);
+extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
+                      struct inode *new_dir,const char *new_name,int new_len);
+extern void vfat_put_super(struct super_block *sb);
+extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
+                                          int silent);
+extern void vfat_read_inode(struct inode *inode);
+extern int vfat_lookup(struct inode *dir,const char *name,int len,
+                      struct inode **result);
+
 #endif /* __KERNEL__ */
 
 #endif
index 329787c..5b5919e 100644 (file)
@@ -71,7+71,7 @@ struct hh_cache
                                         * any address resolution module,
                                         * not only ARP.
                                         */
-       unsigned int    hh_refcnt;      /* number of users */
+       int             hh_refcnt;      /* number of users */
        unsigned short  hh_type;        /* protocol identifier, f.e ETH_P_IP */
        char            hh_uptodate;    /* hh_data is valid */
        char            hh_data[16];    /* cached hardware header */
@@ -218,7+218,7 @@ extern struct packet_type *ptype_base[16];
 
 extern int             ip_addr_match(unsigned long addr1, unsigned long addr2);
 extern int             ip_chk_addr(unsigned long addr);
-extern struct device   *ip_dev_check(unsigned long daddr);
+extern struct device   *ip_dev_bynet(unsigned long daddr, unsigned long mask);
 extern unsigned long   ip_my_addr(void);
 extern unsigned long   ip_get_mask(unsigned long addr);
 extern struct device   *ip_dev_find(unsigned long addr);
@@ -246,7+246,7 @@ extern void         dev_init(void);
 extern int             dev_lockct;
 
 /*
- *     These two dont currently need to be interrupt safe
+ *     These two don't currently need to be interrupt-safe
  *     but they may do soon. Do it properly anyway.
  */
 
index 1ffa729..82b1c81 100644 (file)
@@ -392,7+392,11 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, int len)
        skb->tail+=len;
        skb->len+=len;
        if(skb->tail>skb->end)
-               panic("skput:over: %p:%d", __builtin_return_address(0),len);
+       {
+               __label__ here;
+               panic("skput:over: %p:%d", &&here,len);
+here:
+       }
        return tmp;
 }
 
@@ -401,7+405,11 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, int len)
        skb->data-=len;
        skb->len+=len;
        if(skb->data<skb->head)
-               panic("skpush:under: %p:%d", __builtin_return_address(0),len);
+       {
+               __label__ here;
+               panic("skpush:under: %p:%d", &&here,len);
+here:
+       }
        return skb->data;
 }
 
index e9162b3..3b795a0 100644 (file)
@@ -17,6+17,7 @@ extern char * strncpy(char *,const char *,size_t);
 extern char * strcat(char *, const char *);
 extern char * strncat(char *, const char *, size_t);
 extern char * strchr(const char *,int);
+extern char * strrchr(const char *,int);
 extern char * strpbrk(const char *,const char *);
 extern char * strtok(char *,const char *);
 extern char * strstr(const char *,const char *);
index b1412ea..f907d4a 100644 (file)
@@ -2,7+2,7 @@
 #define __NET_NETLINK_H
 
 #define NET_MAJOR 36           /* Major 18 is reserved for networking                                          */
-#define MAX_LINKS 8            /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved      */
+#define MAX_LINKS 9            /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved      */
                                /* 4-7 are psi0-psi3 */
 #define MAX_QBYTES 32768       /* Maximum bytes in the queue                                                   */
 
@@ -19,6+19,7 @@ extern int init_netlink(void);
 #define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
 #define NETLINK_FIREWALL       3       /* Firewalling hook                             */
 #define NETLINK_PSI            4       /* PSI devices - 4 to 7 */
+#define NETLINK_ARPD           8
 
 #ifdef CONFIG_RTNETLINK
 extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
index b805f38..de59bda 100644 (file)
 #define RTF_LOCAL 0x8000
 #endif
 
-/*
- * Semaphores.
- */
-#if defined(__alpha__)
-
-static __inline__ void ATOMIC_INCR(unsigned int * addr)
-{
-       unsigned tmp;
-
-       __asm__ __volatile__(
-               "1:\n\
-                ldl_l %1,%2\n\
-                addl  %1,1,%1\n\
-                stl_c %1,%0\n\
-                beq   %1,1b\n"
-               : "m=" (*addr), "r=&" (tmp)
-               : "m"(*addr));
-}
-
-static __inline__ void ATOMIC_DECR(unsigned int * addr)
-{
-       unsigned tmp;
-
-       __asm__ __volatile__(
-               "1:\n\
-                ldl_l %1,%2\n\
-                subl  %1,1,%1\n\
-                stl_c %1,%0\n\
-                beq   %1,1b\n"
-               : "m=" (*addr), "r=&" (tmp)
-               : "m"(*addr));
-}
-
-static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr)
-{
-       unsigned tmp;
-       int result;
-
-       __asm__ __volatile__(
-               "1:\n\
-                ldl_l %1,%3\n\
-                subl  %1,1,%1\n\
-                mov   %1,%2\n\
-                stl_c %1,%0\n\
-                beq   %1,1b\n"
-               : "m=" (*addr), "r=&" (tmp), "r=&"(result)
-               : "m"(*addr));
-       return result;
-}
-
-#elif defined(__i386__)
-#include <asm/bitops.h>
-
-extern __inline__ void ATOMIC_INCR(void * addr)
-{
-       __asm__ __volatile__(
-               "incl %0"
-               :"=m" (ADDR));
-}
-
-extern __inline__ void ATOMIC_DECR(void * addr)
-{
-       __asm__ __volatile__(
-               "decl %0"
-               :"=m" (ADDR));
-}
-
-/*
- * It is DECR that is ATOMIC, not CHECK!
- * If you want to do atomic checks, use cli()/sti(). --ANK
- */
-
-extern __inline__ unsigned long ATOMIC_DECR_AND_CHECK(void * addr)
-{
-       unsigned long retval;
-       __asm__ __volatile__(
-               "decl %0\nmovl %0,%1"
-               : "=m" (ADDR), "=r"(retval));
-       return retval;
-}
-
-
-#else
-
-static __inline__ void ATOMIC_INCR(unsigned int * addr)
-{
-       (*(__volatile__ unsigned int*)addr)++;
-}
-
-static __inline__ void ATOMIC_DECR(unsigned int * addr)
-{
-       (*(__volatile__ unsigned int*)addr)--;
-}
-
-static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr)
-{
-       ATOMIC_DECR(addr);
-       return *(volatile unsigned int*)addr;
-}
-
-#endif
-
-
-
 struct rtable 
 {
        struct rtable           *rt_next;
        __u32                   rt_dst;
        __u32                   rt_src;
        __u32                   rt_gateway;
-       unsigned                rt_refcnt;
-       unsigned                rt_use;
+       atomic_t                rt_refcnt;
+       atomic_t                rt_use;
        unsigned long           rt_window;
-       unsigned long           rt_lastuse;
+       atomic_t                rt_lastuse;
        struct hh_cache         *rt_hh;
        struct device           *rt_dev;
        unsigned short          rt_flags;
@@ -185,6+81,7 @@ struct rtable
 };
 
 extern void            ip_rt_flush(struct device *dev);
+extern void            ip_rt_update(int event, struct device *dev);
 extern void            ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev);
 extern struct rtable   *ip_rt_slow_route(__u32 daddr, int local);
 extern int             rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy);
@@ -196,23+93,23 @@ extern void                ip_rt_check_expire(void);
 extern void            ip_rt_advice(struct rtable **rp, int advice);
 
 extern void            ip_rt_run_bh(void);
-extern int             ip_rt_lock;
+extern atomic_t                ip_rt_lock;
 extern unsigned                ip_rt_bh_mask;
 extern struct rtable   *ip_rt_hash_table[RT_HASH_DIVISOR];
 
 extern __inline__ void ip_rt_fast_lock(void)
 {
-       ATOMIC_INCR(&ip_rt_lock);
+       atomic_inc(&ip_rt_lock);
 }
 
 extern __inline__ void ip_rt_fast_unlock(void)
 {
-       ATOMIC_DECR(&ip_rt_lock);
+       atomic_dec(&ip_rt_lock);
 }
 
 extern __inline__ void ip_rt_unlock(void)
 {
-       if (!ATOMIC_DECR_AND_CHECK(&ip_rt_lock) && ip_rt_bh_mask)
+       if (atomic_dec_and_test(&ip_rt_lock) && ip_rt_bh_mask)
                ip_rt_run_bh();
 }
 
@@ -227,7+124,7 @@ extern __inline__ void ip_rt_put(struct rtable * rt)
 #ifndef MODULE
 {
        if (rt)
-               ATOMIC_DECR(&rt->rt_refcnt);
+               atomic_dec(&rt->rt_refcnt);
 }
 #else
 ;
@@ -248,8+145,8 @@ extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local)
                if (rth->rt_dst == daddr)
                {
                        rth->rt_lastuse = jiffies;
-                       ATOMIC_INCR(&rth->rt_use);
-                       ATOMIC_INCR(&rth->rt_refcnt);
+                       atomic_inc(&rth->rt_use);
+                       atomic_inc(&rth->rt_refcnt);
                        ip_rt_unlock();
                        return rth;
                }
similarity index 100%
rename from drivers/net/slhc.h
rename to include/net/slhc_vj.h
index e777d3c..a9af984 100644 (file)
@@ -488,7+488,7 @@ extern struct sk_buff               *sock_alloc_send_skb(struct sock *skb,
  *     protocols can't normally use this as they need to fit buffers in
  *     and play with them.
  *
- *     Inlined as its very short and called for pretty much every
+ *     Inlined as it's very short and called for pretty much every
  *     packet ever received.
  */
 
index fd0a424..315ced5 100644 (file)
@@ -192,50+192,7 @@ static __inline__ int tcp_old_window(struct sock * sk)
        return sk->window - (sk->acked_seq - sk->lastwin_seq);
 }
 
-static __inline__ int tcp_new_window(struct sock * sk)
-{
-       int window = sock_rspace(sk);
-
-       if (window > 1024)
-               window &= ~0x3FF;       /* make free space a multiple of 1024 */
-
-       if (sk->window_clamp && sk->window_clamp < window)
-               window = sk->window_clamp;
-
-       /*
-        * RFC 1122 says:
-        *
-        * "the suggested [SWS] avoidance algorithm for the receiver is to keep
-        *  RECV.NEXT + RCV.WIN fixed until:
-        *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
-        *
-        * Experiments against BSD and Solaris machines show that following
-        * these rules results in the BSD and Solaris machines making very
-        * bad guesses about how much data they can have in flight.
-        *
-        * Instead we follow the BSD lead and offer a window that gives
-        * the size of the current free space, truncated to a multiple
-        * of 1024 bytes. If the window is smaller than
-        *      min(sk->mss, MAX_WINDOW/2)
-        * then we advertise the window as having size 0, unless this
-        * would shrink the window we offered last time.
-        * This results in as much as double the throughput as the original
-        * implementation.
-        */
-
-       if (sk->mss == 0)
-               sk->mss = sk->mtu;
-
-       /* BSD style SWS avoidance
-        * Note that RFC1122 only says we must do silly window avoidance,
-        * it does not require that we use the suggested algorithm.
-        */
-
-       if (window < min(sk->mss, MAX_WINDOW/2))
-               window = 0;
-
-       return window;
-}
+extern int tcp_new_window(struct sock *);
 
 /*
  * Return true if we should raise the window when we
@@ -247,7+204,8 @@ static __inline__ int tcp_new_window(struct sock * sk)
  */
 static __inline__ int tcp_raise_window(struct sock * sk)
 {
-       return tcp_new_window(sk) >= 2*tcp_old_window(sk);
+       int new = tcp_new_window(sk);
+       return new && (new >= 2*tcp_old_window(sk));
 }
 
 static __inline__ unsigned short tcp_select_window(struct sock *sk)
index 43a005d..e62d9c4 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -159,7+159,8 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg
  * Take care of missing kerneld, especially in case of multiple daemons
  */
 #define KERNELD_TIMEOUT 1 * (HZ)
-#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)
+#define DROP_TIMER del_timer(&kd_timer)
+/*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/
 
 static void kd_timeout(unsigned long msgid)
 {
@@ -185,7+186,7 @@ static void kd_timeout(unsigned long msgid)
 
 static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
 {
-       struct timer_list kd_timer;
+       struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
        struct msqid_ds *msq;
        struct ipc_perm *ipcp;
        struct msg *tmsg, *leastp = NULL;
@@ -229,16+230,20 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
         *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
         */
        while (!nmsg) {
-               if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
+               if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
+                       DROP_TIMER;
                        return -EIDRM;
+               }
                if ((msgflg & IPC_KERNELD) == 0) {
                        /*
                         * Non-root processes may receive from kerneld! 
                         * i.e. no permission check if called from the kernel
                         * otoh we don't want user level non-root snoopers...
                         */
-                       if (ipcperms (ipcp, S_IRUGO))
+                       if (ipcperms (ipcp, S_IRUGO)) {
+                               DROP_TIMER;
                                return -EACCES;
+                       }
                }
                if (msgtyp == 0) 
                        nmsg = msq->msg_first;
@@ -267,8+272,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
                
                if (nmsg) { /* done finding a message */
                        DROP_TIMER;
-                       if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
+                       if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
+                               DROP_TIMER;
                                return -E2BIG;
+                       }
                        msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
                        if (nmsg ==  msq->msg_first)
                                msq->msg_first = nmsg->msg_next;
@@ -315,6+322,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
                                memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
                        }
                        kfree(nmsg);
+                       DROP_TIMER;
                        return msgsz;
                } else {  /* did not find a message */
                        if (msgflg & IPC_NOWAIT) {
index edde5fb..4f7702b 100644 (file)
 
 #ifdef CONFIG_MODULES          /* a *big* #ifdef block... */
 
-#ifdef DEBUG_MODULE
-#define PRINTK(a) printk a
-#else
-#define PRINTK(a) /* */
-#endif
-
 static struct module kernel_module;
 static struct module *module_list = &kernel_module;
 
@@ -127,8+121,8 @@ sys_create_module(char *module_name, unsigned long size)
        * (long *) addr = 0;    /* set use count to zero */
        module_list = mp;       /* link it in */
 
-       PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
-               mp->name, (unsigned long) mp->size, (unsigned long) mp->addr));
+       pr_debug("module `%s' (%lu pages @ 0x%08lx) created\n",
+               mp->name, (unsigned long) mp->size, (unsigned long) mp->addr);
        return (unsigned long) addr;
 }
 
@@ -167,8+161,8 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
 
        if ((error = get_mod_name(module_name, name)) != 0)
                return error;
-       PRINTK(("initializing module `%s', %d (0x%x) bytes\n",
-               name, codesize, codesize));
+       pr_debug("initializing module `%s', %d (0x%x) bytes\n",
+               name, codesize, codesize);
        memcpy_fromfs(&rt, routines, sizeof rt);
        if ((mp = find_module(name)) == NULL)
                return -ENOENT;
@@ -185,8+179,8 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
        memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize);
        memset((char *)mp->addr + sizeof (long) + codesize, 0,
                mp->size * PAGE_SIZE - (codesize + sizeof (long)));
-       PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
-               (unsigned long) rt.init, (unsigned long) rt.cleanup));
+       pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
+               (unsigned long) rt.init, (unsigned long) rt.cleanup);
        mp->cleanup = rt.cleanup;
 
        /* update kernel symbol table */
index f58e7ce..65aa995 100644 (file)
@@ -121,8+121,7 @@ static inline void add_to_runqueue(struct task_struct * p)
        init_task.prev_run = p;
 #ifdef __SMP__
        /* this is safe only if called with cli()*/
-       while(set_bit(31,&smp_process_available));
-#if 0  
+       while(set_bit(31,&smp_process_available))
        {
                while(test_bit(31,&smp_process_available))
                {
@@ -133,7+132,6 @@ static inline void add_to_runqueue(struct task_struct * p)
                        }
                }
        }
-#endif 
        smp_process_available++;
        clear_bit(31,&smp_process_available);
        if ((0!=p->pid) && smp_threads_ready)
@@ -242,6+240,11 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
        /* We are not permitted to run a task someone else is running */
        if (p->processor != NO_PROC_ID)
                return -1000;
+#ifdef PAST_2_0                
+       /* This process is locked to a processor group */
+       if (p->processor_mask && !(p->processor_mask & (1<<this_cpu))
+               return -1000;
+#endif         
 #endif
 
        /*
@@ -340,7+343,7 @@ asmlinkage void schedule(void)
         *      This is safe as we do not permit re-entry of schedule()
         */
        prev->processor = NO_PROC_ID;
-#define idle_task (task[this_cpu])
+#define idle_task (task[cpu_number_map[this_cpu]])
 #else
 #define idle_task (&init_task)
 #endif 
index f467512..c3a1f86 100644 (file)
@@ -779,7+779,8 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
                free_page(page);
                return new_page;
        }
-       flush_page_to_ram(page);
+       if (page)
+               flush_page_to_ram(page);
        return page;
 }
 
index af842d8..52f6715 100644 (file)
@@ -187,6+187,7 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
                return 1;
        }
        set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
+       flush_tlb_page(vma, address);
        ++vma->vm_mm->rss;
        swap_free(pte_val(pte));
        return 1;
index 4bd4782..170b25a 100644 (file)
@@ -376,7+376,7 @@ o   TCP socket cache gets things wrong very very occasionally under high
        load.                                           [TRYING THINGS]
 o      AX.25/NetROM needs more locking.
 o      NFS flow control is needed with the new multirequest NFS support.
-o      Need to be able to turn off the intelligent arp refreshing as its not so
+o      Need to be able to turn off the intelligent arp refreshing as it's not so
        hot over AX.25 and upsets some people with very dumb ISDN bridges.
 o      Matti Arnio's TCP problem.
 o      Should unix domain connect never block ?
@@ -435,7+435,7 @@ working out how to do it so it runs like greased lightning. Quite a big
 problem. [See the LiS project]
 
 10.    Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board
-driver but thats for an internal project and its general release is still
+driver but that's for an internal project and its general release is still
 a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
 Mike McLagan][Friz Elfert is doing the isdn4linux kit].
  
index 28f98f6..bd60661 100644 (file)
@@ -35,7+35,7 @@ MAX_WINDOW            Offered maximum window (tunable)
 MAX_HEADER             Largest physical header (tunable)
 MAX_ADDR_LEN           Largest physical address (tunable)
 SOCK_ARRAY_SIZE                IP socket array hash size (tunable)
-ARP_RES_TIME           Time we try and resolve (tunable)
+ARP_RES_TIME           Time we try to resolve (tunable)
 ARP_DEAD_RES_TIME      Time the entry stays dead (tunable)
 ARP_MAX_TRIES          Maximum tries (tunable)
 ARP_TIMEOUT            Timeout on an ARP (tunable)
index dd9f41e..f151fbb 100644 (file)
  *             2 of the License, or (at your option) any later version.
  *
  *     History
- *     AX.25 006       Alan(GW4PTS)            Nearly died of shock - its working 8-)
+ *     AX.25 006       Alan(GW4PTS)            Nearly died of shock - it's working 8-)
  *     AX.25 007       Alan(GW4PTS)            Removed the silliest bugs
  *     AX.25 008       Alan(GW4PTS)            Cleaned up, fixed a few state machine problems, added callbacks
  *     AX.25 009       Alan(GW4PTS)            Emergency patch kit to fix memory corruption
  *                                             Correct receive on SOCK_DGRAM.
  *     AX.25 013       Alan(GW4PTS)            Send DM to all unknown frames, missing initialiser fixed
  *                                             Leave spare SSID bits set (DAMA etc) - thanks for bug report,
- *                                             removed device registration (its not used or needed). Clean up for
+ *                                             removed device registration (it's not used or needed). Clean up for
  *                                             gcc 2.5.8. PID to AX25_P_
  *     AX.25 014       Alan(GW4PTS)            Cleanup and NET3 merge
  *     AX.25 015       Alan(GW4PTS)            Internal test version.
@@ -409,7+409,7 @@ static void ax25_destroy_timer(unsigned long data)
  *     Once it is removed from the queue no interrupt or bottom half will
  *     touch it and we are (fairly 8-) ) safe.
  */
-void ax25_destroy_socket(ax25_cb *ax25)        /* Not static as its used by the timer */
+void ax25_destroy_socket(ax25_cb *ax25)        /* Not static as it's used by the timer */
 {
        struct sk_buff *skb;
        unsigned long flags;
@@ -1893,7+1893,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
  */
 static int kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
-       skb->sk = NULL;         /* Initially we don't know who its for */
+       skb->sk = NULL;         /* Initially we don't know who it's for */
 
        if ((*skb->data & 0x0F) != 0) {
                kfree_skb(skb, FREE_READ);      /* Not a KISS data frame */
@@ -1914,7+1914,7 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *
        ax25_address *port_call;
        int len;
 
-       skb->sk = NULL;         /* Initially we don't know who its for */
+       skb->sk = NULL;         /* Initially we don't know who it's for */
 
        if ((port_call = ax25_bpq_get_addr(dev)) == NULL) {
                kfree_skb(skb, FREE_READ);      /* We have no port callsign */
@@ -2546,7+2546,7 @@ int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long des
                if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) 
                {
                        /*
-                        *      This is a workaround to try and keep the device locking
+                        *      This is a workaround to try to keep the device locking
                         *      straight until skb->free=0 is abolished post 1.4.
                         *
                         *      We clone the buffer and release the original thereby
index 396c62c..c81aabc 100644 (file)
@@ -389,7+389,7 @@ void dama_enquiry_response(ax25_cb *ax25)
 
        /* The FLEXNET DAMA master implementation refuses to send us ANY */
        /* I frame for this connection if we send a REJ here, probably   */
-       /* due to it's frame collector scheme? A simple RR or  RNR will  */
+       /* due to its frame collector scheme? A simple RR or  RNR will   */
        /* invoke the retransmission, and in fact REJs are superfluous   */
        /* in DAMA mode anyway...                                        */
        
index f06b1e4..b2c837b 100644 (file)
@@ -248,7+248,7 @@ void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
 /*
  *     Send a 'DM' to an unknown connection attempt, or an invalid caller.
  *
- *     Note: src here is the sender, thus its the target of the DM
+ *     Note: src here is the sender, thus it's the target of the DM
  */
 void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
 {
index d068ec4..9598a09 100644 (file)
@@ -291,13+291,7 @@ int dev_close(struct device *dev)
         *      Flush the multicast chain
         */
        dev_mc_discard(dev);
-       /*
-        *      Blank the IP addresses
-        */
-       dev->pa_addr = 0;
-       dev->pa_dstaddr = 0;
-       dev->pa_brdaddr = 0;
-       dev->pa_mask = 0;
+
        /*
         *      Purge any queued packets when we down the link 
         */
@@ -1082,6+1076,17 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                        }
                        else
                        {
+                               u32 new_pa_addr = (*(struct sockaddr_in *)
+                                        &ifr.ifr_addr).sin_addr.s_addr;
+                               u16 new_family = ifr.ifr_addr.sa_family;
+
+                               if (new_family == dev->family &&
+                                   new_pa_addr == dev->pa_addr) {
+                                       ret =0;
+                                       break;
+                               }
+                               if (dev->flags & IFF_UP)
+                                       notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
 
                                /*
                                 *      if dev is an alias, must rehash to update
@@ -1092,16+1097,19 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                                if (net_alias_is(dev))
                                net_alias_dev_rehash(dev ,&ifr.ifr_addr);
 #endif
-                               dev->pa_addr = (*(struct sockaddr_in *)
-                                        &ifr.ifr_addr).sin_addr.s_addr;
-                               dev->family = ifr.ifr_addr.sa_family;
+                               dev->pa_addr = new_pa_addr;
+                               dev->family = new_family;
                        
 #ifdef CONFIG_INET     
                                /* This is naughty. When net-032e comes out It wants moving into the net032
                                   code not the kernel. Till then it can sit here (SIGH) */             
-                               dev->pa_mask = ip_get_mask(dev->pa_addr);
+                               if (!dev->pa_mask)
+                                       dev->pa_mask = ip_get_mask(dev->pa_addr);
 #endif                 
-                               dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+                               if (!dev->pa_brdaddr)
+                                       dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+                               if (dev->flags & IFF_UP)
+                                       notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
                                ret = 0;
                        }
                        break;
index 8870346..0a1785c 100644 (file)
@@ -1122,7+1122,7 @@ net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct s
   if (main_dev == NULL) return NULL;
 
   /*
-   * if not aliased, dont bother any more
+   * if not aliased, don't bother any more
    */
 
   if ((alias_info = main_dev->alias_info) == NULL)
@@ -1194,7+1194,7 @@ net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 ds
   if (main_dev == NULL) return NULL;
 
   /*
-   * if not aliased, dont bother any more
+   * if not aliased, don't bother any more
    */
 
   if ((alias_info = main_dev->alias_info) == NULL)
index 8f4c003..bc35bbb 100644 (file)
@@ -154,7+154,7 @@ int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst,
        }
 
        /*
-        *      Try and get ARP to resolve the header.
+        *      Try to get ARP to resolve the header.
         */
 #ifdef CONFIG_INET      
        return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
index 7c88999..fef4901 100644 (file)
@@ -22,7+22,7 @@ if [ "$CONFIG_NET_ALIAS" = "y" ]; then
        tristate 'IP: aliasing support' CONFIG_IP_ALIAS
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "$CONFIG_KERNELD" = "y" ]; then
+  if [ "$CONFIG_NETLINK" = "y" ]; then
     bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
   fi
 fi
index 93fc850..5a127ab 100644 (file)
 #include <linux/net_alias.h>
 #endif
 #ifdef CONFIG_ARPD
-#include <linux/kerneld.h>
-#endif /* CONFIG_ARPD */
+#include <net/netlink.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <stdarg.h>
 
 /*
- *     This structure defines the ARP mapping cache. As long as we make changes
- *     in this structure, we keep interrupts off. But normally we can copy the
- *     hardware address and the device pointer in a local variable and then 
- *     make any "long calls" to send a packet out.
+ *     Configurable Parameters
  */
 
-struct arp_table
-{
-       struct arp_table                *next;                  /* Linked entry list            */
-       unsigned long                   last_used;              /* For expiry                   */
-       unsigned long                   last_updated;           /* For expiry                   */
-       unsigned int                    flags;                  /* Control status               */
-       u32                             ip;                     /* ip address of entry          */
-       u32                             mask;                   /* netmask - used for generalised proxy arps (tridge)           */
-       unsigned char                   ha[MAX_ADDR_LEN];       /* Hardware address             */
-       struct device                   *dev;                   /* Device the entry is tied to  */
+/*
+ *     After that time, an unused entry is deleted from the arp table.
+ *     RFC1122 recommends set it to 60*HZ, if your site uses proxy arp
+ *     and dynamic routing.
+ */
 
-       /*
-        *      The following entries are only used for unresolved hw addresses.
-        */
-       
-       struct timer_list               timer;                  /* expire timer                 */
-       int                             retries;                /* remaining retries            */
-       struct sk_buff_head             skb;                    /* list of queued packets       */
-       struct hh_cache                 *hh;
-};
+#ifndef CONFIG_ARPD
+#define ARP_TIMEOUT            (600*HZ)
+#else
+#define ARP_TIMEOUT            (60*HZ)
+#define ARPD_TIMEOUT           (600*HZ)
+#endif
+
+/*
+ *     How often is ARP cache checked for expire.
+ *     It is useless to set ARP_CHECK_INTERVAL > ARP_TIMEOUT
+ */
 
+#define ARP_CHECK_INTERVAL     (60*HZ)
 
 /*
- *     Configurable Parameters (don't touch unless you know what you are doing
+ *     Soft limit on ARP cache size.
+ *     Note that this number should be greater, than
+ *     number of simultaneously opened sockets, else
+ *     hardware header cache will be not efficient.
  */
 
+#if RT_CACHE_DEBUG >= 2
+#define ARP_MAXSIZE    4
+#else
+#ifdef CONFIG_ARPD
+#define ARP_MAXSIZE    64
+#else
+#define ARP_MAXSIZE    256
+#endif /* CONFIG_ARPD */
+#endif
+
 /*
  *     If an arp request is send, ARP_RES_TIME is the timeout value until the
  *     next request is send.
  *     RFC1122: OK.  Throttles ARPing, as per 2.3.2.1. (MUST)
  *     The recommended minimum timeout is 1 second per destination.
- *     This timeout is prolongated to ARP_DEAD_RES_TIME, if
- *     destination does not respond.
+ *
  */
 
 #define ARP_RES_TIME           (5*HZ)
-#define ARP_DEAD_RES_TIME      (60*HZ)
 
 /*
- *     The number of times an arp request is send, until the host is
- *     considered temporarily unreachable.
+ *     The number of times an broadcast arp request is send, until
+ *     the host is considered temporarily unreachable.
  */
 
 #define ARP_MAX_TRIES          3
 
 /*
- *     After that time, an unused entry is deleted from the arp table.
+ *     The entry is reconfirmed by sending point-to-point ARP
+ *     request after ARP_CONFIRM_INTERVAL.
+ *     RFC1122 recommends 60*HZ.
+ *
+ *     Warning: there exist nodes, that answer only broadcast
+ *     ARP requests (Cisco-4000 in hot standby mode?)
+ *     Now arp code should work with such nodes, but
+ *     it still will generate redundant broadcast requests, so that
+ *     this interval should be enough long.
  */
 
-#define ARP_TIMEOUT            (600*HZ)
+#define ARP_CONFIRM_INTERVAL   (300*HZ)
 
 /*
- *     How often is the function 'arp_check_retries' called.
- *     An unused entry is invalidated in the time between ARP_TIMEOUT and
- *     (ARP_TIMEOUT+ARP_CHECK_INTERVAL).
+ *     We wait for answer to unicast request for ARP_CONFIRM_TIMEOUT.
  */
 
-#define ARP_CHECK_INTERVAL     (60*HZ)
+#define ARP_CONFIRM_TIMEOUT    ARP_RES_TIME
 
 /*
- *     The entry is reconfirmed by sending point-to-point ARP
- *     request after ARP_CONFIRM_INTERVAL. If destinations does not respond
- *     for ARP_CONFIRM_TIMEOUT, normal broadcast resolution scheme is started.
+ *     The number of times an unicast arp request is retried, until
+ *     the cache entry is considered suspicious.
+ *     Value 0 means that no unicast pings will be sent.
+ *     RFC1122 recommends 2.
  */
 
-#define ARP_CONFIRM_INTERVAL   (300*HZ)
-#define ARP_CONFIRM_TIMEOUT    ARP_RES_TIME
+#define ARP_MAX_PINGS          1
+
+/*
+ *     When a host is dead, but someone tries to connect it,
+ *     we do not remove corresponding cache entry (it would
+ *     be useless, it will be created again immediately)
+ *     Instead we prolongate interval between broadcasts
+ *     to ARP_DEAD_RES_TIME.
+ *     This interval should be not very long.
+ *     (When the host will be up again, we will notice it only
+ *     when ARP_DEAD_RES_TIME expires, or when the host will arp us.
+ */
+
+#define ARP_DEAD_RES_TIME      (60*HZ)
+
+/*
+ *     This structure defines the ARP mapping cache.
+ */
+
+struct arp_table
+{
+       struct arp_table                *next;                  /* Linked entry list            */
+       unsigned long                   last_used;              /* For expiry                   */
+       unsigned long                   last_updated;           /* For expiry                   */
+       unsigned int                    flags;                  /* Control status               */
+       u32                             ip;                     /* ip address of entry          */
+       u32                             mask;                   /* netmask - used for generalised proxy arps (tridge)           */
+       unsigned char                   ha[MAX_ADDR_LEN];       /* Hardware address             */
+       struct device                   *dev;                   /* Device the entry is tied to  */
+       struct hh_cache                 *hh;                    /* Hardware headers chain       */
+
+       /*
+        *      The following entries are only used for unresolved hw addresses.
+        */
+       
+       struct timer_list               timer;                  /* expire timer                 */
+       int                             retries;                /* remaining retries            */
+       struct sk_buff_head             skb;                    /* list of queued packets       */
+};
+
+
+static atomic_t arp_size = 0;
+
+#ifdef CONFIG_ARPD
+static int arpd_not_running;
+static int arpd_stamp;
+#endif
 
-static unsigned int arp_lock;
 static unsigned int arp_bh_mask;
 
 #define ARP_BH_BACKLOG 1
 
+/*
+ *     Backlog for ARP updates.
+ */
 static struct arp_table *arp_backlog;
 
-/* If we have arpd configured, assume that we will be running arpd and keep
-   the internal cache small */
-#ifdef CONFIG_ARPD
-#define ARP_MAXSIZE    256
-#endif /* CONFIG_ARPD */
+/*
+ *     Backlog for incomplete entries.
+ */
+static struct arp_table *arp_req_backlog;
 
-static unsigned int arp_size = 0;
 
 static void arp_run_bh(void);
 static void arp_check_expire (unsigned long);  
+static int  arp_update (u32 sip, char *sha, struct device * dev,
+           struct arp_table *ientry, int grat);
 
 static struct timer_list arp_timer =
        { NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire };
@@ -216,12+276,10 @@ static struct timer_list arp_timer =
 
 /*
  *     The size of the hash table. Must be a power of two.
- *     Maybe we should remove hashing in the future for arp and concentrate
- *     on Patrick Schaaf's Host-Cache-Lookup...
  */
 
-#define ARP_TABLE_SIZE  16
-#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1)
+#define ARP_TABLE_SIZE         16
+#define FULL_ARP_TABLE_SIZE    (ARP_TABLE_SIZE+1)
 
 struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] =
 {
@@ -238,22+296,47 @@ struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] =
 #define HASH(paddr)            (htonl(paddr) & (ARP_TABLE_SIZE - 1))
 
 /*
- * Lock/unlock arp_table chains.
+ *     ARP cache semaphore.
+ *
+ *     Every time when someone wants to traverse arp table,
+ *     he MUST call arp_fast_lock.
+ *     It will guarantee that arp cache list will not change
+ *     by interrupts and the entry that you found will not
+ *     disappear unexpectedly.
+ *     
+ *     If you want to modify arp cache lists, you MUST
+ *     call arp_fast_lock, and check that you are the only
+ *     owner of semaphore (arp_lock == 1). If it is not the case
+ *     you can defer your operation or forgot it,
+ *     but DO NOT TOUCH lists.
+ *
+ *     However, you are allowed to change arp entry contents.
+ *
+ *     Assumptions:
+ *          -- interrupt code MUST have lock/unlock balanced,
+ *             you cannot lock cache on interrupt and defer unlocking
+ *             to callback.
+ *             In particular, it means that lock/unlock are allowed
+ *             to be non-atomic. They are made atomic, but it was not
+ *             necessary.
+ *          -- nobody is allowed to sleep while
+ *             it keeps arp locked. (route cache has similar locking
+ *             scheme, but allows sleeping)
+ *             
  */
 
-static __inline__ void arp_fast_lock(void)
-{
-       ATOMIC_INCR(&arp_lock);
-}
+static atomic_t arp_lock;
 
-static __inline__ void arp_fast_unlock(void)
+#define ARP_LOCKED() (arp_lock != 1)
+
+static __inline__ void arp_fast_lock(void)
 {
-       ATOMIC_DECR(&arp_lock);
+       atomic_inc(&arp_lock);
 }
 
 static __inline__ void arp_unlock(void)
 {
-       if (!ATOMIC_DECR_AND_CHECK(&arp_lock) && arp_bh_mask)
+       if (atomic_dec_and_test(&arp_lock) && arp_bh_mask)
                arp_run_bh();
 }
 
@@ -306,7+389,7 @@ static struct arp_table * arp_dequeue(struct arp_table **q)
  * Purge all linked skb's of the entry.
  */
 
-static void arp_release_entry(struct arp_table *entry)
+static void arp_purge_send_q(struct arp_table *entry)
 {
        struct sk_buff *skb;
        unsigned long flags;
@@ -328,6+411,7 @@ static void arp_release_entry(struct arp_table *entry)
 /*
  *     Release the entry and all resources linked to it: skb's, hh's, timer
  *     and certainly memory.
+ *     The entry should be already removed from lists.
  */
 
 static void arp_free_entry(struct arp_table *entry)
@@ -336,280+420,416 @@ static void arp_free_entry(struct arp_table *entry)
        struct hh_cache *hh, *next;
 
        del_timer(&entry->timer);
+       arp_purge_send_q(entry);
 
        save_flags(flags);
        cli();
-       arp_release_entry(entry);
+       hh = entry->hh;
+       entry->hh = NULL;
+       restore_flags(flags);
 
-       for (hh = entry->hh; hh; hh = next)
+       for ( ; hh; hh = next)
        {
                next = hh->hh_next;
-               hh->hh_arp = NULL;
                hh->hh_uptodate = 0;
-               if (!--hh->hh_refcnt)
+               hh->hh_next = NULL;
+               hh->hh_arp = NULL;
+               if (atomic_dec_and_test(&hh->hh_refcnt))
                        kfree_s(hh, sizeof(struct(struct hh_cache)));
        }
-       restore_flags(flags);
 
        kfree_s(entry, sizeof(struct arp_table));
-       --arp_size;
+       atomic_dec(&arp_size);
        return;
 }
 
 /*
- * How many users has this entry?
+ *     Hardware header cache.
+ *
+ *     BEWARE! Hardware header cache has no locking, so that
+ *     it requires especially careful handling.
+ *     It is the only part of arp+route, where a list
+ *     should be traversed with masked interrupts.
+ *     Luckily, this list contains one element 8), as rule.
+ */
+
+/*
+ *     How many users has this entry?
+ *     The answer is reliable only when interrupts are masked.
  */
 
 static __inline__ int arp_count_hhs(struct arp_table * entry)
 {
-       struct hh_cache *hh, **hhp;
+       struct hh_cache *hh;
        int count = 0;
 
-       hhp = &entry->hh;
-       while ((hh=*hhp) != NULL)
-       {
-               if (hh->hh_refcnt == 1)
-               {
-                       *hhp = hh->hh_next;
-                       kfree_s(hh, sizeof(struct hh_cache));
-                       continue;
-               }
+       for (hh = entry->hh; hh; hh = hh->hh_next)
                count += hh->hh_refcnt-1;
-               hhp = &hh->hh_next;
-       }
 
        return count;
 }
 
-
 /*
- *     Force the expiry of an entry in the internal cache so the memory
- *     can be used for a new request or for loading a query from arpd.
- *     I'm not really sure what the best algorithm should be, so I just
- *     search for the oldest.  NOTE:  make sure the cache is locked before
- *      jumping into this function!  If someone wants to do something
- *     other than searching the whole cache, by all means do so!
+ * Signal to device layer, that hardware address may be changed.
  */
 
-#ifdef CONFIG_ARPD
-static int arp_force_expire(void)
+static __inline__ void arp_update_hhs(struct arp_table * entry)
 {
-       int i;
-       struct arp_table *entry = NULL;
-       struct arp_table **pentry = NULL;
-       struct arp_table **oldest_entry = NULL, **last_resort = NULL;
-       unsigned long oldest_used = ~0;
-
-#if RT_CACHE_DEBUG >= 2
-       printk("Looking for something to force expire.\n");
-#endif
-       for (i = 0; i < ARP_TABLE_SIZE; i++)
-       {
-               pentry = &arp_tables[i];
+       struct hh_cache *hh;
 
-               while ((entry = *pentry) != NULL)
-               {
-                       if (entry->last_used < oldest_used)
-                       {
-                               if (arp_count_hhs(entry) == 0)
-                               {
-                                       oldest_entry = pentry;
-                               }
-                               last_resort = pentry;
-                               oldest_used = entry->last_used;
-                       }
-                       pentry = &entry->next;  /* go to next entry */
-               }
-       }
-       if (oldest_entry == NULL)
-       {
-               if (last_resort == NULL)
-                       return -1;
-               oldest_entry = last_resort;
-       }
-               
-       entry = *oldest_entry;
-       *oldest_entry = (*oldest_entry)->next;
-#if RT_CACHE_DEBUG >= 2
-       printk("Force expiring %08x\n", entry->ip);
-#endif
-       arp_free_entry(entry);
-       return 0;
+       for (hh=entry->hh; hh; hh=hh->hh_next)
+               entry->dev->header_cache_update(hh, entry->dev, entry->ha);
 }
-#endif /* CONFIG_ARPD */
 
+/*
+ *     Invalidate all hh's, so that higher level will not try to use it.
+ */
 
-static void arpd_update(struct arp_table * entry, int loc)
+static __inline__ void arp_invalidate_hhs(struct arp_table * entry)
 {
-#ifdef CONFIG_ARPD
-       static struct arpd_request arpreq;
-
-       arpreq.req = ARPD_UPDATE;
-       arpreq.ip = entry->ip;
-       arpreq.mask = entry->mask;
-       memcpy (arpreq.ha, entry->ha, MAX_ADDR_LEN);
-       arpreq.loc = loc;
-       arpreq.last_used = entry->last_used;
-       arpreq.last_updated = entry->last_updated;
-       arpreq.flags = entry->flags;
-       arpreq.dev = entry->dev;
-
-       kerneld_send(KERNELD_ARP, 0, sizeof(arpreq),
-                               (char *) &arpreq, NULL);
-#endif /* CONFIG_ARPD */
+       struct hh_cache *hh;
+
+       for (hh=entry->hh; hh; hh=hh->hh_next)
+               hh->hh_uptodate = 0;
 }
 
-/* 
- * Allocate memory for a new entry.  If we are at the maximum limit
- * of the internal ARP cache, arp_force_expire() an entry.  NOTE:  
- * arp_force_expire() needs the cache to be locked, so therefore
- * arp_add_entry() should only be called with the cache locked too!
+/*
+ *     Atomic attaching new hh entry.
+ *     Return 1, if entry has been freed, rather than attached.
  */
 
-static struct arp_table * arp_add_entry(void)
+static int arp_set_hh(struct hh_cache **hhp, struct hh_cache *hh)
 {
-       struct arp_table * entry;
+       unsigned long flags;
+       struct hh_cache *hh1;
+       struct arp_table *entry;
 
-#ifdef CONFIG_ARPD
-       if (arp_size >= ARP_MAXSIZE)
+       atomic_inc(&hh->hh_refcnt);
+
+       save_flags(flags);
+       cli();
+       if ((hh1 = *hhp) == NULL)
        {
-               if (arp_force_expire() < 0)
-                       return NULL;
+               *hhp = hh;
+               restore_flags(flags);
+               return 0;
        }
-#endif /* CONFIG_ARPD */
 
-       entry = (struct arp_table *)
-               kmalloc(sizeof(struct arp_table),GFP_ATOMIC);
+       entry = (struct arp_table*)hh->hh_arp;
 
-       if (entry != NULL)
-               ++arp_size;
-       return entry;
+       /*
+        *      An hh1 entry is already attached to this point.
+        *      Is it not linked to arp entry? Link it!
+        */
+       if (!hh1->hh_arp && entry)
+       {
+               atomic_inc(&hh1->hh_refcnt);
+               hh1->hh_next = entry->hh;
+               entry->hh = hh1;
+               hh1->hh_arp = (void*)entry;
+               restore_flags(flags);
+
+               if (entry->flags & ATF_COM)
+                       entry->dev->header_cache_update(hh1, entry->dev, entry->ha);
+#if RT_CACHE_DEBUG >= 1
+               printk("arp_set_hh: %08x is reattached. Good!\n", entry->ip);
+#endif
+       }
+#if RT_CACHE_DEBUG >= 1
+       else if (entry)
+               printk("arp_set_hh: %08x rr1 ok!\n", entry->ip);
+#endif
+       restore_flags(flags);
+       if (atomic_dec_and_test(&hh->hh_refcnt))
+               kfree_s(hh, sizeof(struct hh_cache));
+       return 1;
 }
 
+static __inline__ struct hh_cache * arp_alloc_hh(int htype)
+{
+       struct hh_cache *hh;
+       hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+       if (hh)
+       {
+               memset(hh, 0, sizeof(struct hh_cache));
+               hh->hh_type = htype;
+       }
+       return hh;
+}
 
 /*
- * Lookup ARP entry by (addr, dev) pair in the arpd.
+ * Test if a hardware address is all zero
  */
 
-static struct arp_table * arpd_lookup(u32 addr, unsigned short flags, 
-                                               struct device * dev,
-                                               int loc)
+static __inline__ int empty(unsigned char * addr, int len)
 {
+       while (len > 0)
+       {
+               if (*addr)
+                       return 0;
+               len--;
+               addr++;
+       }
+       return 1;
+}
+
+
 #ifdef CONFIG_ARPD
-       static struct arpd_request arpreq, retreq;
-       struct arp_table * entry;
-       int rv, i;
-
-       arpreq.req = ARPD_LOOKUP;
-       arpreq.ip = addr;
-       arpreq.loc = loc;
-
-       rv = kerneld_send(KERNELD_ARP, 
-                       sizeof(retreq) | KERNELD_WAIT,
-                       sizeof(arpreq),
-                       (char *) &arpreq,
-                       (char *) &retreq);
-       /* don't worry about rv != 0 too much, it's probably
-          because arpd isn't running or an entry couldn't
-          be found */
-
-       if (rv != 0)
-               return NULL;
-       if (dev != retreq.dev)
-               return NULL;
-       if (! memcmp (retreq.ha, "\0\0\0\0\0\0", 6))
-               return NULL;
 
-       arp_fast_lock();
-       entry = arp_add_entry();
-       arp_unlock();
+/*
+ *     Send ARPD message.
+ */
+static void arpd_send(int req, u32 addr, struct device * dev, char *ha,
+                     unsigned long updated)
+{
+       int retval;
+       struct sk_buff *skb;
+       struct arpd_request *arpreq;
 
-       if (entry == NULL)
-               return NULL;
-
-       entry->next = NULL;
-       entry->last_used = retreq.last_used;
-       entry->last_updated = retreq.last_updated;
-       entry->flags = retreq.flags;
-       entry->ip = retreq.ip;
-       entry->mask = retreq.mask;
-       memcpy (entry->ha, retreq.ha, MAX_ADDR_LEN);
-       arpreq.dev = entry->dev;
-
-       skb_queue_head_init(&entry->skb);
-       entry->hh = NULL;
-       entry->retries = 0;
+       if (arpd_not_running)
+               return;
 
-#if RT_CACHE_DEBUG >= 2
-       printk("Inserting arpd entry %08x\n in local cache.", entry->ip);
-#endif
-       i = HASH(entry->ip);
-       arp_fast_lock();
-       entry->next = arp_tables[i]->next;
-       arp_tables[i]->next = entry;
-       arp_unlock();
-       return entry;
-#endif /* CONFIG_ARPD */
-       return NULL;
-}
+       skb = alloc_skb(sizeof(struct arpd_request), GFP_ATOMIC);
+       if (skb == NULL)
+               return;
 
+       skb->free=1;
+       arpreq=(struct arpd_request *)skb_put(skb, sizeof(struct arpd_request));
+       arpreq->req = req;
+       arpreq->ip  = addr;
+       arpreq->dev = (unsigned long)dev;
+       arpreq->stamp = arpd_stamp;
+       arpreq->updated = updated;
+       if (ha)
+               memcpy(arpreq->ha, ha, sizeof(arpreq->ha));
+
+       retval = netlink_post(NETLINK_ARPD, skb);
+       if (retval)
+       {
+               kfree_skb(skb, FREE_WRITE);
+               if (retval == -EUNATCH)
+                       arpd_not_running = 1;
+       }
+}
 
 /*
- * Invalidate all hh's, so that higher level will not try to use it.
+ *     Send ARPD update message.
  */
 
-static __inline__ void arp_invalidate_hhs(struct arp_table * entry)
+static __inline__ void arpd_update(struct arp_table * entry)
 {
-       struct hh_cache *hh;
-
-       for (hh=entry->hh; hh; hh=hh->hh_next)
-               hh->hh_uptodate = 0;
+       if (arpd_not_running)
+               return;
+       arpd_send(ARPD_UPDATE, entry->ip, entry->dev, entry->ha,
+                 entry->last_updated);
 }
 
 /*
- * Signal to device layer, that hardware address may be changed.
+ *     Send ARPD lookup request.
  */
 
-static __inline__ void arp_update_hhs(struct arp_table * entry)
+static __inline__ void arpd_lookup(u32 addr, struct device * dev)
 {
-       struct hh_cache *hh;
-
-       for (hh=entry->hh; hh; hh=hh->hh_next)
-               entry->dev->header_cache_update(hh, entry->dev, entry->ha);
+       if (arpd_not_running)
+               return;
+       arpd_send(ARPD_LOOKUP, addr, dev, NULL, 0);
 }
 
 /*
- *     Check if there are too old entries and remove them. If the ATF_PERM
- *     flag is set, they are always left in the arp cache (permanent entry).
- *      If an entry was not be confirmed  for ARP_CONFIRM_INTERVAL,
- *     declare it invalid and send point-to-point ARP request.
- *     If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
- *     give it to shred by arp_expire_entry.
+ *     Send ARPD flush message.
  */
 
-static void arp_check_expire(unsigned long dummy)
+static __inline__ void arpd_flush(struct device * dev)
 {
-       int i;
-       unsigned long now = jiffies;
+       if (arpd_not_running)
+               return;
+       arpd_send(ARPD_FLUSH, 0, dev, NULL, 0);
+}
 
-       del_timer(&arp_timer);
 
-       if (!arp_lock)
+static int arpd_callback(struct sk_buff *skb)
+{
+       struct device * dev;
+       struct arpd_request *retreq;
+
+       arpd_not_running = 0;
+
+       if (skb->len != sizeof(struct arpd_request))
+       {
+               kfree_skb(skb, FREE_READ);
+               return -EINVAL;
+       }
+
+       retreq = (struct arpd_request *)skb->data;
+       dev = (struct device*)retreq->dev;
+
+       if (retreq->stamp != arpd_stamp || !dev)
+       {
+               kfree_skb(skb, FREE_READ);
+               return -EINVAL;
+       }
+
+       if (!retreq->updated || empty(retreq->ha, sizeof(retreq->ha)))
+       {
+/*
+ *     Invalid mapping: drop it and send ARP broadcast.
+ */
+               arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL, 
+                        dev->dev_addr, NULL);
+       }
+       else
        {
                arp_fast_lock();
+               arp_update(retreq->ip, retreq->ha, dev, NULL, 0);
+               arp_unlock();
+
+/*
+ *     Old mapping: we cannot trust it, send ARP broadcast to confirm it.
+ *     If it will answer, the entry will be updated,
+ *     if not ... we are lost. We will use it for ARP_CONFIRM_INTERVAL.
+ */
+               if (jiffies - retreq->updated < ARPD_TIMEOUT)
+                       arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL, 
+                                dev->dev_addr, NULL);
+       }
+
+       kfree_skb(skb, FREE_READ);
+       return sizeof(struct arpd_request);
+}
+
+#else
+
+static __inline__ void arpd_update(struct arp_table * entry)
+{
+       return;
+}
+
+#endif /* CONFIG_ARPD */
+
+
+
+
+/*
+ *     ARP expiration routines.
+ */
+
+/*
+ *     Force the expiry of an entry in the internal cache so the memory
+ *     can be used for a new request.
+ */
+
+static int arp_force_expire(void)
+{
+       int i;
+       struct arp_table *entry, **pentry;
+       struct arp_table **oldest_entry = NULL;
+       unsigned long oldest_used = ~0;
+       unsigned long flags;
+       unsigned long now = jiffies;
+       int result = 0;
+
+       static last_index;
+
+       if (ARP_LOCKED())
+               return 0;
+
+       save_flags(flags);
+
+       if (last_index >= ARP_TABLE_SIZE)
+               last_index = 0;
+
+       for (i = 0; i < ARP_TABLE_SIZE; i++, last_index++)
+       {
+               pentry = &arp_tables[last_index & (ARP_TABLE_SIZE-1)];
+
+               while ((entry = *pentry) != NULL)
+               {
+                       if (!(entry->flags & ATF_PERM))
+                       {
+                               int users;
+                               cli();
+                               users = arp_count_hhs(entry);
+
+                               if (!users && now - entry->last_used > ARP_TIMEOUT)
+                               {
+                                       *pentry = entry->next;
+                                       restore_flags(flags);
+#if RT_CACHE_DEBUG >= 2
+                                       printk("arp_force_expire: %08x expired\n", entry->ip);
+#endif
+                                       arp_free_entry(entry);
+                                       result++;
+                                       if (arp_size < ARP_MAXSIZE)
+                                               goto done;
+                                       continue;
+                               }
+                               restore_flags(flags);
+                               if (!users && entry->last_used < oldest_used)
+                               {
+                                       oldest_entry = pentry;
+                                       oldest_used = entry->last_used;
+                               }
+                       }
+                       pentry = &entry->next;
+               }
+       }
+
+done:
+       if (result || !oldest_entry)
+               return result;
+
+       entry = *oldest_entry;
+       *oldest_entry = entry->next;
+#if RT_CACHE_DEBUG >= 2
+       printk("arp_force_expire: expiring %08x\n", entry->ip);
+#endif
+       arp_free_entry(entry);
+       return 1;
+}
+
+/*
+ *     Check if there are too old entries and remove them. If the ATF_PERM
+ *     flag is set, they are always left in the arp cache (permanent entry).
+ *      If an entry was not be confirmed  for ARP_CONFIRM_INTERVAL,
+ *     send point-to-point ARP request.
+ *     If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
+ *     give it to shred by arp_expire_entry.
+ */
+
+static void arp_check_expire(unsigned long dummy)
+{
+       int i;
+       unsigned long now = jiffies;
+
+       del_timer(&arp_timer);
+
+#ifdef CONFIG_ARPD
+       arpd_not_running = 0;
+#endif
+
+       ip_rt_check_expire();
+
+       arp_fast_lock();
+
+       if (!ARP_LOCKED())
+       {
 
                for (i = 0; i < ARP_TABLE_SIZE; i++)
                {
-                       struct arp_table *entry;
-                       struct arp_table **pentry;
+                       struct arp_table *entry, **pentry;
                
                        pentry = &arp_tables[i];
 
                        while ((entry = *pentry) != NULL)
                        {
+                               if (entry->flags & ATF_PERM)
+                               {
+                                       pentry = &entry->next;
+                                       continue;
+                               }
+
                                cli();
                                if (now - entry->last_used > ARP_TIMEOUT
-                                   && !(entry->flags & ATF_PERM)
                                    && !arp_count_hhs(entry))
                                {
                                        *pentry = entry->next;
@@ -618,17+838,15 @@ static void arp_check_expire(unsigned long dummy)
                                        printk("arp_expire: %08x expired\n", entry->ip);
 #endif
                                        arp_free_entry(entry);
+                                       continue;
                                }
-                               else if (entry->last_updated
-                                        && now - entry->last_updated > ARP_CONFIRM_INTERVAL
-                                        && !(entry->flags & ATF_PERM))
+                               sti();
+                               if (entry->last_updated
+                                   && now - entry->last_updated > ARP_CONFIRM_INTERVAL
+                                   && !(entry->flags & ATF_PERM))
                                {
                                        struct device * dev = entry->dev;
-                                       pentry = &entry->next;
-                                       entry->flags &= ~ATF_COM;
-                                       arp_invalidate_hhs(entry);
-                                       sti();
-                                       entry->retries = ARP_MAX_TRIES+1;
+                                       entry->retries = ARP_MAX_TRIES+ARP_MAX_PINGS;
                                        del_timer(&entry->timer);
                                        entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT;
                                        add_timer(&entry->timer);
@@ -639,14+857,12 @@ static void arp_check_expire(unsigned long dummy)
                                        printk("arp_expire: %08x requires confirmation\n", entry->ip);
 #endif
                                }
-                               else
-                                       pentry = &entry->next;  /* go to next entry */
+                               pentry = &entry->next;  /* go to next entry */
                        }
                }
-               arp_unlock();
        }
 
-       ip_rt_check_expire();
+       arp_unlock();
 
        /*
         *      Set the timer again.
@@ -669,34+885,46 @@ static void arp_expire_request (unsigned long arg)
        unsigned long hash;
        unsigned long flags;
 
+       arp_fast_lock();
+
        save_flags(flags);
        cli();
+       del_timer(&entry->timer);
 
        /*
-        *      Since all timeouts are handled with interrupts enabled, there is a
-        *      small chance, that this entry has just been resolved by an incoming
-        *      packet. This is the only race condition, but it is handled...
+        *      If arp table is locked, defer expire processing.
         */
-       
-       if (entry->flags & ATF_COM)
+       if (ARP_LOCKED())
        {
+#if RT_CACHE_DEBUG >= 1
+               printk(KERN_DEBUG "arp_expire_request: %08x deferred\n", entry->ip);
+#endif
+               entry->timer.expires = jiffies + HZ/10;
+               add_timer(&entry->timer);
                restore_flags(flags);
+               arp_unlock();
                return;
        }
 
-       if (arp_lock)
+       /*
+        *      Since all timeouts are handled with interrupts enabled, there is a
+        *      small chance, that this entry has just been resolved by an incoming
+        *      packet. This is the only race condition, but it is handled...
+        *
+        *      One exception: if entry is COMPLETE but old,
+        *      it means that point-to-point ARP ping has been failed
+        *      (It really occurs with Cisco 4000 routers)
+        *      We should reconfirm it.
+        */
+       
+       if ((entry->flags & ATF_COM) && entry->last_updated
+           && jiffies - entry->last_updated <= ARP_CONFIRM_INTERVAL)
        {
-#if RT_CACHE_DEBUG >= 1
-               printk("arp_expire_request: %08x postponed\n", entry->ip);
-#endif
-               del_timer(&entry->timer);
-               entry->timer.expires = jiffies + HZ/10;
-               add_timer(&entry->timer);
                restore_flags(flags);
+               arp_unlock();
                return;
        }
 
-       arp_fast_lock();
        restore_flags(flags);
 
        if (entry->last_updated && --entry->retries > 0)
@@ -707,29+935,47 @@ static void arp_expire_request (unsigned long arg)
                printk("arp_expire_request: %08x timed out\n", entry->ip);
 #endif
                /* Set new timer. */
-               del_timer(&entry->timer);
                entry->timer.expires = jiffies + ARP_RES_TIME;
                add_timer(&entry->timer);
-               arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, 
-                        NULL, dev->dev_addr, NULL);
+               arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr,
+                        entry->retries > ARP_MAX_TRIES ? entry->ha : NULL,
+                        dev->dev_addr, NULL);
                arp_unlock();
                return;
        }
 
-       arp_release_entry(entry);
+       /*
+        *      The host is really dead.
+        */
+
+       arp_purge_send_q(entry);
 
        cli();
        if (arp_count_hhs(entry))
        {
+               /*
+                *      The host is dead, but someone refers to it.
+                *      It is useless to drop this entry just now,
+                *      it will be born again, so that
+                *      we keep it, but slow down retransmitting
+                *      to ARP_DEAD_RES_TIME.
+                */
+
                struct device *dev = entry->dev;
 #if RT_CACHE_DEBUG >= 2
                printk("arp_expire_request: %08x is dead\n", entry->ip);
 #endif
-               arp_release_entry(entry);
                entry->retries = ARP_MAX_TRIES;
+               entry->flags &= ~ATF_COM;
+               arp_invalidate_hhs(entry);
                restore_flags(flags);
+
+               /*
+                *      Declare the entry dead.
+                */
                entry->last_updated = 0;
-               del_timer(&entry->timer);
+               arpd_update(entry);
+
                entry->timer.expires = jiffies + ARP_DEAD_RES_TIME;
                add_timer(&entry->timer);
                arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, 
@@ -739,30+985,65 @@ static void arp_expire_request (unsigned long arg)
        }
        restore_flags(flags);
 
+       entry->last_updated = 0;
+       arpd_update(entry);
+
        hash = HASH(entry->ip);
 
        pentry = &arp_tables[hash];
 
        while (*pentry != NULL)
        {
-               if (*pentry == entry)
+               if (*pentry != entry)
                {
-                       cli();
-                       *pentry = entry->next;
-                       restore_flags(flags);
+                       pentry = &(*pentry)->next;
+                       continue;
+               }
+               *pentry = entry->next;
 #if RT_CACHE_DEBUG >= 2
-                       printk("arp_expire_request: %08x is killed\n", entry->ip);
+               printk("arp_expire_request: %08x is killed\n", entry->ip);
 #endif
-                       arp_free_entry(entry);
-                       arp_unlock();
-                       return;
-               }
-               pentry = &(*pentry)->next;
+               arp_free_entry(entry);
        }
-       printk("arp_expire_request: bug: ARP entry is lost!\n");
        arp_unlock();
 }
 
+
+/* 
+ * Allocate memory for a new entry.  If we are at the maximum limit
+ * of the internal ARP cache, arp_force_expire() an entry.  NOTE:  
+ * arp_force_expire() needs the cache to be locked, so therefore
+ * arp_alloc_entry() should only be called with the cache locked too!
+ */
+
+static struct arp_table * arp_alloc_entry(void)
+{
+       struct arp_table * entry;
+
+
+       if (arp_size >= ARP_MAXSIZE)
+               arp_force_expire();
+
+       entry = (struct arp_table *)
+               kmalloc(sizeof(struct arp_table),GFP_ATOMIC);
+
+       if (entry != NULL)
+       {
+               atomic_inc(&arp_size);
+               memset(entry, 0, sizeof(struct arp_table));
+
+                entry->mask = DEF_ARP_NETMASK;
+               init_timer(&entry->timer);
+               entry->timer.function = arp_expire_request;
+               entry->timer.data = (unsigned long)entry;
+               entry->last_updated = entry->last_used = jiffies;
+               skb_queue_head_init(&entry->skb);
+       }
+       return entry;
+}
+
+
+
 /*
  *     Purge a device from the ARP queue
  */
@@ -774,15+1055,17 @@ int arp_device_event(struct notifier_block *this, unsigned long event, void *ptr
        
        if (event != NETDEV_DOWN)
                return NOTIFY_DONE;
-       /*
-        *      This is a bit OTT - maybe we need some arp semaphores instead.
-        */
 
-#if RT_CACHE_DEBUG >= 1         
-       if (arp_lock)
-               printk("arp_device_event: bug\n");
+#ifdef  CONFIG_ARPD
+       arpd_flush(dev);
+       arpd_stamp++;
 #endif
+
        arp_fast_lock();
+#if RT_CACHE_DEBUG >= 1         
+       if (ARP_LOCKED())
+               printk("arp_device_event: impossible\n");
+#endif
 
        for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
        {
@@ -805,104+1088,29 @@ int arp_device_event(struct notifier_block *this, unsigned long event, void *ptr
 }
 
 
+
 /*
- *     Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
- *     message.
+ *     This will try to retransmit everything on the queue.
  */
 
-void arp_send(int type, int ptype, u32 dest_ip, 
-             struct device *dev, u32 src_ip, 
-             unsigned char *dest_hw, unsigned char *src_hw,
-             unsigned char *target_hw)
+static void arp_send_q(struct arp_table *entry)
 {
        struct sk_buff *skb;
-       struct arphdr *arp;
-       unsigned char *arp_ptr;
 
-       /*
-        *      No arp on this interface.
-        */
-       
-       if (dev->flags&IFF_NOARP)
-               return;
+       unsigned long flags;
 
        /*
-        *      Allocate a buffer
+        *      Empty the entire queue, building its data up ready to send
         */
        
-       skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
-                               + dev->hard_header_len, GFP_ATOMIC);
-       if (skb == NULL)
+       if(!(entry->flags&ATF_COM))
        {
-               printk("ARP: no memory to send an arp packet\n");
-               return;
-       }
-       skb_reserve(skb, dev->hard_header_len);
-       arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
-       skb->arp = 1;
-       skb->dev = dev;
-       skb->free = 1;
-       skb->protocol = htons (ETH_P_IP);
-
-       /*
-        *      Fill the device header for the ARP frame
-        */
-
-       dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len);
-
-       /* Fill out the arp protocol part. */
-       arp->ar_hrd = htons(dev->type);
-#ifdef CONFIG_AX25
-#ifdef CONFIG_NETROM
-       arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP);
-#else
-       arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP);
-#endif
-#else
-       arp->ar_pro = htons(ETH_P_IP);
-#endif
-       arp->ar_hln = dev->addr_len;
-       arp->ar_pln = 4;
-       arp->ar_op = htons(type);
-
-       arp_ptr=(unsigned char *)(arp+1);
-
-       memcpy(arp_ptr, src_hw, dev->addr_len);
-       arp_ptr+=dev->addr_len;
-       memcpy(arp_ptr, &src_ip,4);
-       arp_ptr+=4;
-       if (target_hw != NULL)
-               memcpy(arp_ptr, target_hw, dev->addr_len);
-       else
-               memset(arp_ptr, 0, dev->addr_len);
-       arp_ptr+=dev->addr_len;
-       memcpy(arp_ptr, &dest_ip, 4);
-
-       dev_queue_xmit(skb, dev, 0);
-}
-
-/*
- *     This will try to retransmit everything on the queue.
- */
-
-static void arp_send_q(struct arp_table *entry)
-{
-       struct sk_buff *skb;
-
-       unsigned long flags;
-
-       /*
-        *      Empty the entire queue, building its data up ready to send
-        */
-       
-       if(!(entry->flags&ATF_COM))
-       {
-               printk("arp_send_q: incomplete entry for %s\n",
-                               in_ntoa(entry->ip));
-               /* Can't flush the skb, because RFC1122 says to hang on to */
-               /* at least one from any unresolved entry.  --MS */
-               /* What's happened is that someone has 'unresolved' the entry
-                  as we got to use it - this 'can't happen' -- AC */
+               printk("arp_send_q: incomplete entry for %s\n",
+                               in_ntoa(entry->ip));
+               /* Can't flush the skb, because RFC1122 says to hang on to */
+               /* at least one from any unresolved entry.  --MS */
+               /* What's happened is that someone has 'unresolved' the entry
+                  as we got to use it - this 'can't happen' -- AC */
                return;
        }
 
@@ -927,435+1135,137 @@ static void arp_send_q(struct arp_table *entry)
 }
 
 
-/*
- *     Delete an ARP mapping entry in the cache.
- */
-
-static void arp_destroy(struct arp_table * entry)
+static int
+arp_update (u32 sip, char *sha, struct device * dev,
+           struct arp_table *ientry, int grat)
 {
-       struct arp_table *entry1;
-       struct arp_table **pentry;
+       struct arp_table * entry;
+       unsigned long hash;
 
-       if (entry->flags & ATF_PUBL)
-               pentry = &arp_proxy_list;
-       else
-               pentry = &arp_tables[HASH(entry->ip)];
+       hash = HASH(sip);
+
+       for (entry=arp_tables[hash]; entry; entry = entry->next)
+               if (entry->ip == sip && entry->dev == dev)
+                       break;
 
-       while ((entry1 = *pentry) != NULL)
+       if (entry)
        {
-               if (entry1 == entry)
+/*
+ *     Entry found; update it only if it is not a permanent entry.
+ */
+               if (!(entry->flags & ATF_PERM)) 
                {
-                       *pentry = entry1->next;
                        del_timer(&entry->timer);
-                       arp_free_entry(entry);
-                       return;
+                       entry->last_updated = jiffies;
+                       if (memcmp(entry->ha, sha, dev->addr_len)!=0)
+                       {
+                               memcpy(entry->ha, sha, dev->addr_len);
+                               if (entry->flags & ATF_COM)
+                                       arp_update_hhs(entry);
+                       }
+                       arpd_update(entry);
                }
-               pentry = &entry1->next;
-       }
-}
 
+               if (!(entry->flags & ATF_COM))
+               {
 /*
- *     Receive an arp request by the device layer. Maybe I rewrite it, to
- *     use the incoming packet for the reply. The time for the current
- *     "overhead" isn't that high...
+ *     This entry was incomplete.  Delete the retransmit timer
+ *     and switch to complete status.
  */
-
-int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
-/*
- *     We shouldn't use this type conversion. Check later.
+                       entry->flags |= ATF_COM;
+                       arp_update_hhs(entry);
+/* 
+ *     Send out waiting packets. We might have problems, if someone is 
+ *     manually removing entries right now -- entry might become invalid 
+ *     underneath us.
  */
-       
-       struct arphdr *arp = (struct arphdr *)skb->h.raw;
-       unsigned char *arp_ptr= (unsigned char *)(arp+1);
-       struct arp_table *entry;
-       struct arp_table *proxy_entry;
-       unsigned long hash, grat=0;
-       unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */
-       unsigned char *sha,*tha;
-       u32 sip,tip;
-       
-/*
- *     The hardware length of the packet should match the hardware length
- *     of the device.  Similarly, the hardware types should match.  The
- *     device should be ARP-able.  Also, if pln is not 4, then the lookup
- *     is not from an IP number.  We can't currently handle this, so toss
- *     it. 
- */  
-       if (arp->ar_hln != dev->addr_len    || 
-               dev->type != ntohs(arp->ar_hrd) || 
-               dev->flags & IFF_NOARP          ||
-               arp->ar_pln != 4)
-       {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-               /* Should this be an error/printk?  Seems like something */
-               /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */
+                       arp_send_q(entry);
+               }
+               return 1;
        }
 
 /*
- *     Another test.
- *     The logic here is that the protocol being looked up by arp should 
- *     match the protocol the device speaks.  If it doesn't, there is a
- *     problem, so toss the packet.
+ *     No entry found.  Need to add a new entry to the arp table.
  */
-/* Again, should this be an error/printk? -- MS */
-
-       switch (dev->type)
-       {
-#ifdef CONFIG_AX25
-               case ARPHRD_AX25:
-                       if(arp->ar_pro != htons(AX25_P_IP))
-                       {
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       break;
-#endif
-#ifdef CONFIG_NETROM
-               case ARPHRD_NETROM:
-                       if(arp->ar_pro != htons(AX25_P_IP))
-                       {
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       break;
-#endif
-               case ARPHRD_ETHER:
-               case ARPHRD_ARCNET:
-               case ARPHRD_METRICOM:
-                       if(arp->ar_pro != htons(ETH_P_IP))
-                       {
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       break;
+       entry = ientry;
 
-               case ARPHRD_IEEE802:
-                       if(arp->ar_pro != htons(ETH_P_IP))
-                       {
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       break;
+       if (grat && !entry)
+               return 0;
 
-               default:
-                       printk("ARP: dev->type mangled!\n");
-                       kfree_skb(skb, FREE_READ);
+       if (!entry)
+       {
+               entry = arp_alloc_entry();
+               if (!entry)
                        return 0;
+
+               entry->ip = sip;
+               entry->flags = ATF_COM;
+               memcpy(entry->ha, sha, dev->addr_len);
+               entry->dev = dev;
        }
 
-/*
- *     Extract fields
- */
+       entry->last_updated = entry->last_used = jiffies;
+       arpd_update(entry);
 
-       sha=arp_ptr;
-       arp_ptr += dev->addr_len;
-       memcpy(&sip, arp_ptr, 4);
-       arp_ptr += 4;
-       tha=arp_ptr;
-       arp_ptr += dev->addr_len;
-       memcpy(&tip, arp_ptr, 4);
-  
-/* 
- *     Check for bad requests for 127.x.x.x and requests for multicast
- *     addresses.  If this is one such, delete it.
- */
-       if (LOOPBACK(tip) || MULTICAST(tip))
+       if (!ARP_LOCKED())
        {
-               kfree_skb(skb, FREE_READ);
+               entry->next = arp_tables[hash];
+               arp_tables[hash] = entry;
                return 0;
        }
+#if RT_CACHE_DEBUG >= 2
+       printk("arp_update: %08x backlogged\n", entry->ip);
+#endif
+       arp_enqueue(&arp_backlog, entry);
+       arp_bh_mask |= ARP_BH_BACKLOG;
+       return 0;
+}
 
-/*
- *  Process entry.  The idea here is we want to send a reply if it is a
- *  request for us or if it is a request for someone else that we hold
- *  a proxy for.  We want to add an entry to our cache if it is a reply
- *  to us or if it is a request for our address.  
- *  (The assumption for this last is that if someone is requesting our 
- *  address, they are probably intending to talk to us, so it saves time 
- *  if we cache their address.  Their address is also probably not in 
- *  our cache, since ours is not in their cache.)
- * 
- *  Putting this another way, we only care about replies if they are to
- *  us, in which case we add them to the cache.  For requests, we care
- *  about those for us and those for our proxies.  We reply to both,
- *  and in the case of requests for us we add the requester to the arp 
- *  cache.
- */
+
+
+static __inline__ struct arp_table *arp_lookup(u32 paddr, struct device * dev)
+{
+       struct arp_table *entry;
+
+       for (entry = arp_tables[HASH(paddr)]; entry != NULL; entry = entry->next)
+               if (entry->ip == paddr && (!dev || entry->dev == dev))
+                       return entry;
+       return NULL;
+}
 
 /*
- *     try to switch to alias device whose addr is tip or closest to sip.
+ *     Find an arp mapping in the cache. If not found, return false.
  */
 
-#ifdef CONFIG_NET_ALIAS
-       if (tip != dev->pa_addr && net_alias_has(skb->dev)) 
-       {
-               /*
-                *      net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
-                */
-               dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+int arp_query(unsigned char *haddr, u32 paddr, struct device * dev)
+{
+       struct arp_table *entry;
 
-               if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
+       arp_fast_lock();
+
+       entry = arp_lookup(paddr, dev);
+
+       if (entry != NULL)
+       {
+               entry->last_used = jiffies;
+               if (entry->flags & ATF_COM)
                {
-                       kfree_skb(skb, FREE_READ);
-                       return 0;
+                       memcpy(haddr, entry->ha, dev->addr_len);
+                       arp_unlock();
+                       return 1;
                }
        }
-#endif
+       arp_unlock();
+       return 0;
+}
 
-       if (arp->ar_op == htons(ARPOP_REQUEST))
-       { 
-/*
- * Only reply for the real device address or when it's in our proxy tables
- */
-               if (tip != dev->pa_addr)
-               {
-/*
- *     To get in here, it is a request for someone else.  We need to
- *     check if that someone else is one of our proxies.  If it isn't,
- *     we can toss it.
- */
-                       arp_fast_lock();
 
-                       for (proxy_entry=arp_proxy_list;
-                            proxy_entry;
-                            proxy_entry = proxy_entry->next)
-                       {
-                               /* we will respond to a proxy arp request
-                                  if the masked arp table ip matches the masked
-                                  tip. This allows a single proxy arp table
-                                  entry to be used on a gateway machine to handle
-                                  all requests for a whole network, rather than
-                                  having to use a huge number of proxy arp entries
-                                  and having to keep them uptodate.
-                                  */
-                               if (proxy_entry->dev == dev &&
-                                   !((proxy_entry->ip^tip)&proxy_entry->mask))
-                                       break;
-
-                       }
-                       if (proxy_entry)
-                       {
-                               memcpy(ha, proxy_entry->ha, dev->addr_len);
-                               arp_unlock();
-                               arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha);
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       else
-                       {
-                               arp_unlock();
-                       }
-               }
-               else
-               {
-/*
- *     To get here, it must be an arp request for us.  We need to reply.
- */
-                       arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
-               }
-               grat = 1;
-               goto gratuitous;
-       }
-/*
- *     It is now an arp reply.
- */
-       if(ip_chk_addr(tip)!=IS_MYADDR)
-       {
-/*
- *     Replies to other machines get tossed.
- */
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-/*
- * Now all replies are handled.  Next, anything that falls through to here
- * needs to be added to the arp cache, or have its entry updated if it is 
- * there.
- */
-gratuitous:
-
-       arp_fast_lock();
-
-
-       hash = HASH(sip);
-       for (entry=arp_tables[hash]; entry; entry=entry->next)
-               if (entry->ip == sip && entry->dev == dev)
-                       break;
-
-       if (entry)
-       {
-/*
- *     Entry found; update it only if it is not a permanent entry.
- */
-               if (!(entry->flags & ATF_PERM)) 
-               {
-                       if(memcmp(entry->ha, sha,dev->addr_len)!=0)
-                       {
-                               memcpy(entry->ha, sha, dev->addr_len);
-                               if(entry->flags & ATF_COM)
-                                       arp_update_hhs(entry);
-                       }
-                       entry->last_updated = jiffies;
-                       arpd_update(entry, __LINE__);
-               }
-               if (!(entry->flags & ATF_COM))
-               {
-/*
- *     This entry was incomplete.  Delete the retransmit timer
- *     and switch to complete status.
- */
-                       del_timer(&entry->timer);
-                       entry->flags |= ATF_COM;
-                       arp_update_hhs(entry);
-/* 
- *     Send out waiting packets. We might have problems, if someone is 
- *     manually removing entries right now -- entry might become invalid 
- *     underneath us.
- */
-                       arp_send_q(entry);
-               }
-       }
-       else
-       {
-/*
- *     No entry found.  Need to add a new entry to the arp table.
- */
-
-               if (grat) 
-                       goto end;
-
-                entry = arp_add_entry();
-               if(entry == NULL)
-               {
-                       arp_unlock();
-#if RT_CACHE_DEBUG >= 2
-                       printk("ARP: no memory for new arp entry\n");
-#endif
-                       kfree_skb(skb, FREE_READ);
-                       return 0;
-               }
-
-                entry->mask = DEF_ARP_NETMASK;
-               entry->ip = sip;
-               entry->flags = ATF_COM;
-               entry->hh    = NULL;
-               init_timer(&entry->timer);
-               entry->timer.function = arp_expire_request;
-               entry->timer.data = (unsigned long)entry;
-               memcpy(entry->ha, sha, dev->addr_len);
-               entry->last_updated = entry->last_used = jiffies;
-               arpd_update(entry, __LINE__);
-/*
- *     make entry point to     'correct' device
- */
-
-#ifdef CONFIG_NET_ALIAS
-               entry->dev = dev;
-#else
-               entry->dev = skb->dev;
-#endif
-               skb_queue_head_init(&entry->skb);
-               if (arp_lock == 1)
-               {
-                       entry->next = arp_tables[hash];
-                       arp_tables[hash] = entry;
-               }
-               else
-               {
-#if RT_CACHE_DEBUG >= 2
-                       printk("arp_rcv: %08x backlogged\n", entry->ip);
-#endif
-                       arp_enqueue(&arp_backlog, entry);
-                       arp_bh_mask |= ARP_BH_BACKLOG;
-               }
-       }
-
-/*
- *     Replies have been sent, and entries have been added.  All done.
- */
-
-end:
-       kfree_skb(skb, FREE_READ);
-       arp_unlock();
-       return 0;
-}
-
-/*
- * Lookup ARP entry by (addr, dev) pair.
- * Flags: ATF_PUBL - search for proxy entries
- *       ATF_NETMASK - search for proxy network entry.
- * NOTE:  should be called with locked ARP tables.
- */
-
-static struct arp_table *arp_lookup(u32 paddr, unsigned short flags, struct device * dev)
-{
-       struct arp_table *entry;
-
-       if (!(flags & ATF_PUBL))
-       {
-               for (entry = arp_tables[HASH(paddr)];
-                    entry != NULL; entry = entry->next)
-                       if (entry->ip == paddr && (!dev || entry->dev == dev))
-                               break;
-               return entry;
-       }
-
-       if (!(flags & ATF_NETMASK))
-       {
-               for (entry = arp_proxy_list;
-                    entry != NULL; entry = entry->next)
-                       if (entry->ip == paddr && (!dev || entry->dev == dev))
-                               break;
-               return entry;
-       }
-
-       for (entry=arp_proxy_list; entry != NULL; entry = entry->next)
-               if (!((entry->ip^paddr)&entry->mask) && 
-                                                 (!dev || entry->dev == dev))
-                       break;
-       return entry;
-}
-
-/*
- *     Find an arp mapping in the cache. If not found, return false.
- */
-
-int arp_query(unsigned char *haddr, u32 paddr, struct device * dev)
-{
-       struct arp_table *entry;
-
-       arp_fast_lock();
-
-       entry = arp_lookup(paddr, 0, dev);
-       if (entry == NULL)
-               entry = arpd_lookup(paddr, 0, dev, __LINE__);
-
-       if (entry != NULL)
-       {
-               entry->last_used = jiffies;
-               if (entry->flags & ATF_COM)
-               {
-                       memcpy(haddr, entry->ha, dev->addr_len);
-                       arpd_update(entry, __LINE__);
-                       arp_unlock();
-                       return 1;
-               }
-       }
-       arpd_update(entry, __LINE__);
-       arp_unlock();
-       return 0;
-}
-
-
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, __u32 paddr, struct device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct device * dev)
 {
        switch (addr_hint)
        {
                case IS_MYADDR:
-                       printk("ARP: arp called for own IP address\n");
+                       printk(KERN_DEBUG "ARP: arp called for own IP address\n");
                        memcpy(haddr, dev->dev_addr, dev->addr_len);
                        return 1;
 #ifdef CONFIG_IP_MULTICAST
@@ -1387,325+1297,221 @@ static int arp_set_predefined(int addr_hint, unsigned char * haddr, __u32 paddr,
 }
 
 /*
- *     Find an arp mapping in the cache. If not found, post a request.
+ *     Create a new unresolved entry.
  */
 
-int arp_find(unsigned char *haddr, u32 paddr, struct device *dev,
-            u32 saddr, struct sk_buff *skb)
+struct arp_table * arp_new_entry(u32 paddr, struct device *dev, struct hh_cache *hh, struct sk_buff *skb)
 {
        struct arp_table *entry;
-       unsigned long hash;
-
-       if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev))
-       {
-               if (skb)
-                       skb->arp = 1;
-               return 0;
-       }
-
-       hash = HASH(paddr);
-       arp_fast_lock();
-
-       /*
-        *      Find an entry
-        */
-       entry = arp_lookup(paddr, 0, dev);
-       if (entry == NULL)
-               entry = arpd_lookup(paddr, 0, dev, __LINE__);
-
-       if (entry != NULL)      /* It exists */
-       {
-               if (!(entry->flags & ATF_COM))
-               {
-                       /*
-                        *      A request was already send, but no reply yet. Thus
-                        *      queue the packet with the previous attempt
-                        */
-                       
-                       if (skb != NULL)
-                       {
-                               if (entry->last_updated)
-                               {
-                                       skb_queue_tail(&entry->skb, skb);
-                                       skb_device_unlock(skb);
-                               }
-                               /*
-                                * If last_updated==0 host is dead, so
-                                * drop skb's and set socket error.
-                                */
-                               else
-                               {
-#if 0                          
-                                       /*
-                                        * FIXME: ICMP HOST UNREACHABLE should be
-                                        *        sent in this situation. --ANK
-                                        */
-                                       if (skb->sk)
-                                       {
-                                               skb->sk->err = EHOSTDOWN;
-                                               skb->sk->error_report(skb->sk);
-                                       }
-#else
-                                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
-#endif                                                                         
-                                       dev_kfree_skb(skb, FREE_WRITE);
-                               }
-                       }
-                       arp_unlock();
-                       return 1;
-               }
 
-               /*
-                *      Update the record
-                */
-               
-               entry->last_used = jiffies;
-               memcpy(haddr, entry->ha, dev->addr_len);
-               arpd_update(entry, __LINE__);
-               if (skb)
-                       skb->arp = 1;
-               arp_unlock();
-               return 0;
-       }
+       entry = arp_alloc_entry();
 
-       /*
-        *      Create a new unresolved entry.
-        */
-       
-       entry = arp_add_entry();
        if (entry != NULL)
        {
-               entry->last_updated = entry->last_used = jiffies;
-               entry->flags = 0;
                entry->ip = paddr;
-               entry->mask = DEF_ARP_NETMASK;
-               memset(entry->ha, 0, dev->addr_len);
                entry->dev = dev;
-               entry->hh    = NULL;
-               arpd_update(entry, __LINE__);
-               init_timer(&entry->timer);
-               entry->timer.function = arp_expire_request;
-               entry->timer.data = (unsigned long)entry;
+               if (hh)
+               {
+                       entry->hh = hh;
+                       atomic_inc(&hh->hh_refcnt);
+                       hh->hh_arp = (void*)entry;
+               }
                entry->timer.expires = jiffies + ARP_RES_TIME;
-               skb_queue_head_init(&entry->skb);
+
                if (skb != NULL)
                {
                        skb_queue_tail(&entry->skb, skb);
                        skb_device_unlock(skb);
                }
-               if (arp_lock == 1)
+
+               if (!ARP_LOCKED())
                {
+                       unsigned long hash = HASH(paddr);
                        entry->next = arp_tables[hash];
                        arp_tables[hash] = entry;
                        add_timer(&entry->timer);
                        entry->retries = ARP_MAX_TRIES;
+#ifdef CONFIG_ARPD
+                       if (!arpd_not_running)
+                               arpd_lookup(paddr, dev);
+                       else
+#endif
+                               arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL, 
+                                        dev->dev_addr, NULL);
                }
                else
                {
 #if RT_CACHE_DEBUG >= 2
-                       printk("arp_find: %08x backlogged\n", entry->ip);
+                       printk("arp_new_entry: %08x backlogged\n", entry->ip);
 #endif
-                       arp_enqueue(&arp_backlog, entry);
+                       arp_enqueue(&arp_req_backlog, entry);
                        arp_bh_mask |= ARP_BH_BACKLOG;
                }
        }
-       else if (skb != NULL)
-               dev_kfree_skb(skb, FREE_WRITE);
-       arp_unlock();
-
-       /*
-        *      If we didn't find an entry, we will try to send an ARP packet.
-        */
-       
-       arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, saddr, NULL, 
-                dev->dev_addr, NULL);
-
-       return 1;
+       return entry;
 }
 
 
 /*
- *     Write the contents of the ARP cache to a PROCfs file.
+ *     Find an arp mapping in the cache. If not found, post a request.
  */
 
-#define HBUFFERLEN 30
-
-int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+int arp_find(unsigned char *haddr, u32 paddr, struct device *dev,
+            u32 saddr, struct sk_buff *skb)
 {
-       int len=0;
-       off_t pos=0;
-       int size;
        struct arp_table *entry;
-       char hbuffer[HBUFFERLEN];
-       int i,j,k;
-       const char hexbuf[] =  "0123456789ABCDEF";
-
-       size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask     Device\n");
+       unsigned long hash;
 
-       pos+=size;
-       len+=size;
+       if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev))
+       {
+               if (skb)
+                       skb->arp = 1;
+               return 0;
+       }
 
+       hash = HASH(paddr);
        arp_fast_lock();
 
-       for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
+       /*
+        *      Find an entry
+        */
+       entry = arp_lookup(paddr, dev);
+
+       if (entry != NULL)      /* It exists */
        {
-               for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
+               if (entry->flags & ATF_COM)
                {
-/*
- *     Convert hardware address to XX:XX:XX:XX ... form.
- */
-#ifdef CONFIG_AX25
-#ifdef CONFIG_NETROM
-                       if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM)
-                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
-                       else {
-#else
-                       if(entry->dev->type==ARPHRD_AX25)
-                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
-                       else {
-#endif
-#endif
+                       entry->last_used = jiffies;
+                       memcpy(haddr, entry->ha, dev->addr_len);
+                       if (skb)
+                               skb->arp = 1;
+                       arp_unlock();
+                       return 0;
+               }
 
-                       for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->dev->addr_len;j++)
+               /*
+                *      A request was already send, but no reply yet. Thus
+                *      queue the packet with the previous attempt
+                */
+                       
+               if (skb != NULL)
+               {
+                       if (entry->last_updated)
                        {
-                               hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
-                               hbuffer[k++]=hexbuf[  entry->ha[j]&15     ];
-                               hbuffer[k++]=':';
+                               skb_queue_tail(&entry->skb, skb);
+                               skb_device_unlock(skb);
                        }
-                       hbuffer[--k]=0;
-       
-#ifdef CONFIG_AX25
+                       /*
+                        * If last_updated==0 host is dead, so
+                        * drop skb's and set socket error.
+                        */
+                       else
+                       {
+                               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
+                               dev_kfree_skb(skb, FREE_WRITE);
                        }
-#endif
-                       size = sprintf(buffer+len,
-                               "%-17s0x%-10x0x%-10x%s",
-                               in_ntoa(entry->ip),
-                               (unsigned int)entry->dev->type,
-                               entry->flags,
-                               hbuffer);
-#if RT_CACHE_DEBUG < 2
-                       size += sprintf(buffer+len+size,
-                                "     %-17s %s\n",
-                                entry->mask==DEF_ARP_NETMASK ?
-                                "*" : in_ntoa(entry->mask), entry->dev->name);
-#else
-                       size += sprintf(buffer+len+size,
-                                "     %-17s %s\t%ld\t%1d\n",
-                                entry->mask==DEF_ARP_NETMASK ?
-                                "*" : in_ntoa(entry->mask), entry->dev->name, 
-                                entry->hh ? entry->hh->hh_refcnt : -1,
-                                entry->hh ? entry->hh->hh_uptodate : 0);
-#endif
-       
-                       len += size;
-                       pos += size;
-                 
-                       if (pos <= offset)
-                               len=0;
-                       if (pos >= offset+length)
-                               goto done;
                }
+               arp_unlock();
+               return 1;
        }
-done:
+
+       entry = arp_new_entry(paddr, dev, NULL, skb);
+
+       if (skb != NULL && !entry)
+               dev_kfree_skb(skb, FREE_WRITE);
+
        arp_unlock();
-  
-       *start = buffer+len-(pos-offset);       /* Start of wanted data */
-       len = pos-offset;                       /* Start slop */
-       if (len>length)
-               len = length;                   /* Ending slop */
-       return len;
+       return 1;
 }
 
-
+/*
+ *     Binding hardware header cache entry.
+ *     It is the only really complicated part of arp code.
+ *     We have no locking for hh records, so that
+ *     all possible race conditions should be resolved by
+ *     cli()/sti() pairs.
+ *
+ *     Important note: hhs never disapear from lists, if ARP_LOCKED,
+ *     this fact allows to scan hh lists with enabled interrupts,
+ *     but results in generating duplicate hh entries.
+ *     It is harmless. (and I've never seen such event)
+ *
+ *     Returns 0, if hh has been just created, so that
+ *     caller should fill it.
+ */
 
 int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short htype, u32 paddr)
 {
        struct arp_table *entry;
-       struct hh_cache *hh = *hhp;
+       struct hh_cache *hh;
        int addr_hint;
        unsigned long flags;
 
-       if (hh)
-               return 1;
+       save_flags(flags);
 
        if ((addr_hint = ip_chk_addr(paddr)) != 0)
        {
                unsigned char haddr[MAX_ADDR_LEN];
-               if (hh)
+               if (*hhp)
                        return 1;
-               hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+               hh = arp_alloc_hh(htype);
                if (!hh)
                        return 1;
                arp_set_predefined(addr_hint, haddr, paddr, dev);
-               hh->hh_uptodate = 0;
-               hh->hh_refcnt = 1;
-               hh->hh_arp = NULL;
-               hh->hh_next = NULL;
-               hh->hh_type = htype;
-               *hhp = hh;
                dev->header_cache_update(hh, dev, haddr);
-               return 0;
+               return arp_set_hh(hhp, hh);
        }
 
-       save_flags(flags);
-
        arp_fast_lock();
 
-       entry = arp_lookup(paddr, 0, dev);
-       if (entry == NULL)
-               entry = arpd_lookup(paddr, 0, dev, __LINE__);
+       entry = arp_lookup(paddr, dev);
 
        if (entry)
        {
-               cli();
                for (hh = entry->hh; hh; hh=hh->hh_next)
                        if (hh->hh_type == htype)
                                break;
+
                if (hh)
                {
-                       hh->hh_refcnt++;
-                       *hhp = hh;
-                       restore_flags(flags);
+                       arp_set_hh(hhp, hh);
                        arp_unlock();
                        return 1;
                }
-               restore_flags(flags);
        }
 
-       hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+       hh = arp_alloc_hh(htype);
        if (!hh)
        {
                arp_unlock();
                return 1;
        }
 
-       hh->hh_uptodate = 0;
-       hh->hh_refcnt = 1;
-       hh->hh_arp = NULL;
-       hh->hh_next = NULL;
-       hh->hh_type = htype;
-
        if (entry)
        {
-               dev->header_cache_update(hh, dev, entry->ha);
-               *hhp = hh;
+
                cli();
                hh->hh_arp = (void*)entry;
+               hh->hh_next = entry->hh;
                entry->hh = hh;
-               hh->hh_refcnt++;
+               atomic_inc(&hh->hh_refcnt);
                restore_flags(flags);
+
+               if (entry->flags & ATF_COM)
+                       dev->header_cache_update(hh, dev, entry->ha);
+
+               if (arp_set_hh(hhp, hh))
+               {
+                       arp_unlock();
+                       return 0;
+               }
+
                entry->last_used = jiffies;
-               arpd_update(entry, __LINE__);
                arp_unlock();
                return 0;
        }
 
-
-       /*
-        *      Create a new unresolved entry.
-        */
-       
-       entry = arp_add_entry();
+       entry = arp_new_entry(paddr, dev, hh, NULL);
        if (entry == NULL)
        {
                kfree_s(hh, sizeof(struct hh_cache));
@@ -1713,91+1519,74 @@ int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short ht
                return 1;
        }
 
-       entry->last_updated = entry->last_used = jiffies;
-       entry->flags = 0;
-       entry->ip = paddr;
-       entry->mask = DEF_ARP_NETMASK;
-       memset(entry->ha, 0, dev->addr_len);
-       entry->dev = dev;
-       entry->hh = hh;
-       arpd_update(entry, __LINE__);
-       ATOMIC_INCR(&hh->hh_refcnt);
-       init_timer(&entry->timer);
-       entry->timer.function = arp_expire_request;
-       entry->timer.data = (unsigned long)entry;
-       entry->timer.expires = jiffies + ARP_RES_TIME;
-       skb_queue_head_init(&entry->skb);
-
-       if (arp_lock == 1)
-       {
-               unsigned long hash = HASH(paddr);
-               cli();
-               entry->next = arp_tables[hash];
-               arp_tables[hash] = entry;
-               hh->hh_arp = (void*)entry;
-               entry->retries = ARP_MAX_TRIES;
-               restore_flags(flags);
-
-               add_timer(&entry->timer);
-               arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
-       }
-       else
+       if (!arp_set_hh(hhp, hh))
        {
-#if RT_CACHE_DEBUG >= 1
-               printk("arp_cache_bind: %08x backlogged\n", entry->ip);
-#endif
-               arp_enqueue(&arp_backlog, entry);
-               arp_bh_mask |= ARP_BH_BACKLOG;
+               arp_unlock();
+               return 0;
        }
-       *hhp = hh;
        arp_unlock();
-       return 0;
+       return 1;
 }
 
 static void arp_run_bh()
 {
        unsigned long flags;
        struct arp_table *entry, *entry1;
+       struct device  * dev;
+       unsigned long hash;
        struct hh_cache *hh;
-       __u32 sip;
+       u32 sip;
 
        save_flags(flags);
        cli();
-       if (!arp_lock)
+       arp_fast_lock();
+
+       while (arp_bh_mask)
        {
-               arp_fast_lock();
+               arp_bh_mask  &= ~ARP_BH_BACKLOG;
 
                while ((entry = arp_dequeue(&arp_backlog)) != NULL)
                {
-                       unsigned long hash;
-                       sti();
+                       restore_flags(flags);
+                       if (arp_update(entry->ip, entry->ha, entry->dev, entry, 0))
+                               arp_free_entry(entry);
+                       cli();
+               }
+
+               cli();
+               while ((entry = arp_dequeue(&arp_req_backlog)) != NULL)
+               {
+                       restore_flags(flags);
+
+                       dev = entry->dev;
                        sip = entry->ip;
                        hash = HASH(sip);
 
-                       /* It's possible, that an entry with the same pair 
-                        * (addr,type) was already created. Our entry is older,
-                        * so it should be discarded.
-                        */
-                       for (entry1=arp_tables[hash]; entry1; entry1=entry1->next)
-                               if (entry1->ip==sip && entry1->dev == entry->dev)
+                       for (entry1 = arp_tables[hash]; entry1; entry1 = entry1->next)
+                               if (entry1->ip == sip && entry1->dev == dev)
                                        break;
 
                        if (!entry1)
                        {
-                               struct device  * dev = entry->dev;
                                cli();
                                entry->next = arp_tables[hash];
                                arp_tables[hash] = entry;
-                               for (hh=entry->hh; hh; hh=hh->hh_next)
-                                       hh->hh_arp = (void*)entry;
-                               sti();
-                               del_timer(&entry->timer);
+                               restore_flags(flags);
                                entry->timer.expires = jiffies + ARP_RES_TIME;
-                               add_timer(&entry->timer);
                                entry->retries = ARP_MAX_TRIES;
-                               arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
+                               entry->last_used = jiffies;
+                               if (!(entry->flags & ATF_COM))
+                               {
+                                       add_timer(&entry->timer);
+#ifdef CONFIG_ARPD
+                                       if (!arpd_not_running)
+                                               arpd_lookup(sip, dev);
+                                       else
+#endif
+                                               arp_send(ARPOP_REQUEST, ETH_P_ARP, sip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
+                               }
 #if RT_CACHE_DEBUG >= 1
-                               printk("arp_run_bh: %08x reinstalled\n", sip);
+                               printk(KERN_DEBUG "arp_run_bh: %08x reinstalled\n", sip);
 #endif
                        }
                        else
@@ -1824,59+1613,353 @@ static void arp_run_bh()
                                while ((skb = skb_dequeue(&entry->skb)) != NULL)
                                {
                                        skb_device_lock(skb);
-                                       sti();
+                                       restore_flags(flags);
                                        skb_queue_tail(&entry1->skb, skb);
                                        skb_device_unlock(skb);
                                        cli();
                                }
-                               sti();
+                               restore_flags(flags);
                                
-#if RT_CACHE_DEBUG >= 1
-                               printk("arp_run_bh: entry %08x was born dead\n", entry->ip);
-#endif
                                arp_free_entry(entry);
 
-                               if (entry1->flags & ATF_COM)
-                               {
-                                       arp_update_hhs(entry1);
-                                       arp_send_q(entry1);
-                               }
+                               if (entry1->flags & ATF_COM)
+                               {
+                                       arp_update_hhs(entry1);
+                                       arp_send_q(entry1);
+                               }
+                       }
+                       cli();
+               }
+               cli();
+       }
+       arp_unlock();
+       restore_flags(flags);
+}
+
+
+/*
+ *     Interface to link layer: send routine and receive handler.
+ */
+
+/*
+ *     Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
+ *     message.
+ */
+
+void arp_send(int type, int ptype, u32 dest_ip, 
+             struct device *dev, u32 src_ip, 
+             unsigned char *dest_hw, unsigned char *src_hw,
+             unsigned char *target_hw)
+{
+       struct sk_buff *skb;
+       struct arphdr *arp;
+       unsigned char *arp_ptr;
+
+       /*
+        *      No arp on this interface.
+        */
+       
+       if (dev->flags&IFF_NOARP)
+               return;
+
+       /*
+        *      Allocate a buffer
+        */
+       
+       skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+                               + dev->hard_header_len, GFP_ATOMIC);
+       if (skb == NULL)
+       {
+               printk("ARP: no memory to send an arp packet\n");
+               return;
+       }
+       skb_reserve(skb, dev->hard_header_len);
+       arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
+       skb->arp = 1;
+       skb->dev = dev;
+       skb->free = 1;
+       skb->protocol = htons (ETH_P_IP);
+
+       /*
+        *      Fill the device header for the ARP frame
+        */
+
+       dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len);
+
+       /* Fill out the arp protocol part. */
+       arp->ar_hrd = htons(dev->type);
+#ifdef CONFIG_AX25
+#ifdef CONFIG_NETROM
+       arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP);
+#else
+       arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP);
+#endif
+#else
+       arp->ar_pro = htons(ETH_P_IP);
+#endif
+       arp->ar_hln = dev->addr_len;
+       arp->ar_pln = 4;
+       arp->ar_op = htons(type);
+
+       arp_ptr=(unsigned char *)(arp+1);
+
+       memcpy(arp_ptr, src_hw, dev->addr_len);
+       arp_ptr+=dev->addr_len;
+       memcpy(arp_ptr, &src_ip,4);
+       arp_ptr+=4;
+       if (target_hw != NULL)
+               memcpy(arp_ptr, target_hw, dev->addr_len);
+       else
+               memset(arp_ptr, 0, dev->addr_len);
+       arp_ptr+=dev->addr_len;
+       memcpy(arp_ptr, &dest_ip, 4);
+
+       dev_queue_xmit(skb, dev, 0);
+}
+
+
+/*
+ *     Receive an arp request by the device layer.
+ */
+
+int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+/*
+ *     We shouldn't use this type conversion. Check later.
+ */
+       
+       struct arphdr *arp = (struct arphdr *)skb->h.raw;
+       unsigned char *arp_ptr= (unsigned char *)(arp+1);
+       unsigned char *sha,*tha;
+       u32 sip,tip;
+       
+/*
+ *     The hardware length of the packet should match the hardware length
+ *     of the device.  Similarly, the hardware types should match.  The
+ *     device should be ARP-able.  Also, if pln is not 4, then the lookup
+ *     is not from an IP number.  We can't currently handle this, so toss
+ *     it. 
+ */  
+       if (arp->ar_hln != dev->addr_len    || 
+               dev->type != ntohs(arp->ar_hrd) || 
+               dev->flags & IFF_NOARP          ||
+               arp->ar_pln != 4)
+       {
+               kfree_skb(skb, FREE_READ);
+               return 0;
+               /* Should this be an error/printk?  Seems like something */
+               /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */
+       }
+
+/*
+ *     Another test.
+ *     The logic here is that the protocol being looked up by arp should 
+ *     match the protocol the device speaks.  If it doesn't, there is a
+ *     problem, so toss the packet.
+ */
+/* Again, should this be an error/printk? -- MS */
+
+       switch (dev->type)
+       {
+#ifdef CONFIG_AX25
+               case ARPHRD_AX25:
+                       if(arp->ar_pro != htons(AX25_P_IP))
+                       {
+                               kfree_skb(skb, FREE_READ);
+                               return 0;
+                       }
+                       break;
+#endif
+#ifdef CONFIG_NETROM
+               case ARPHRD_NETROM:
+                       if(arp->ar_pro != htons(AX25_P_IP))
+                       {
+                               kfree_skb(skb, FREE_READ);
+                               return 0;
+                       }
+                       break;
+#endif
+               case ARPHRD_ETHER:
+               case ARPHRD_ARCNET:
+               case ARPHRD_METRICOM:
+                       if(arp->ar_pro != htons(ETH_P_IP))
+                       {
+                               kfree_skb(skb, FREE_READ);
+                               return 0;
+                       }
+                       break;
+
+               case ARPHRD_IEEE802:
+                       if(arp->ar_pro != htons(ETH_P_IP))
+                       {
+                               kfree_skb(skb, FREE_READ);
+                               return 0;
+                       }
+                       break;
+
+               default:
+                       printk("ARP: dev->type mangled!\n");
+                       kfree_skb(skb, FREE_READ);
+                       return 0;
+       }
+
+/*
+ *     Extract fields
+ */
+
+       sha=arp_ptr;
+       arp_ptr += dev->addr_len;
+       memcpy(&sip, arp_ptr, 4);
+       arp_ptr += 4;
+       tha=arp_ptr;
+       arp_ptr += dev->addr_len;
+       memcpy(&tip, arp_ptr, 4);
+  
+/* 
+ *     Check for bad requests for 127.x.x.x and requests for multicast
+ *     addresses.  If this is one such, delete it.
+ */
+       if (LOOPBACK(tip) || MULTICAST(tip))
+       {
+               kfree_skb(skb, FREE_READ);
+               return 0;
+       }
+
+/*
+ *  Process entry.  The idea here is we want to send a reply if it is a
+ *  request for us or if it is a request for someone else that we hold
+ *  a proxy for.  We want to add an entry to our cache if it is a reply
+ *  to us or if it is a request for our address.  
+ *  (The assumption for this last is that if someone is requesting our 
+ *  address, they are probably intending to talk to us, so it saves time 
+ *  if we cache their address.  Their address is also probably not in 
+ *  our cache, since ours is not in their cache.)
+ * 
+ *  Putting this another way, we only care about replies if they are to
+ *  us, in which case we add them to the cache.  For requests, we care
+ *  about those for us and those for our proxies.  We reply to both,
+ *  and in the case of requests for us we add the requester to the arp 
+ *  cache.
+ */
+
+/*
+ *     try to switch to alias device whose addr is tip or closest to sip.
+ */
+
+#ifdef CONFIG_NET_ALIAS
+       if (tip != dev->pa_addr && net_alias_has(skb->dev)) 
+       {
+               /*
+                *      net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
+                */
+               dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+
+               if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
+               {
+                       kfree_skb(skb, FREE_READ);
+                       return 0;
+               }
+       }
+#endif
+
+       if (arp->ar_op == htons(ARPOP_REQUEST))
+       { 
+
+/*
+ * Only reply for the real device address or when it's in our proxy tables
+ */
+               if (tip != dev->pa_addr)
+               {
+                       struct arp_table *proxy_entry;
+
+/*
+ *     To get in here, it is a request for someone else.  We need to
+ *     check if that someone else is one of our proxies.  If it isn't,
+ *     we can toss it.
+ *
+ *     Make "longest match" lookup, a la routing.
+ */
+
+                       arp_fast_lock();
+
+                       for (proxy_entry = arp_proxy_list; proxy_entry;
+                            proxy_entry = proxy_entry->next)
+                       {
+                               if (proxy_entry->dev == dev &&
+                                   !((proxy_entry->ip^tip)&proxy_entry->mask))
+                                       break;
+                       }
+
+                       if (proxy_entry && (proxy_entry->mask || ((dev->pa_addr^tip)&dev->pa_mask)))
+                       {
+                               char ha[MAX_ADDR_LEN];
+                               struct rtable * rt;
+
+                               /* Unlock arp tables to make life for
+                                * ip_rt_route easy. Note, that we are obliged
+                                * to make local copy of hardware address.
+                                */
+
+                               memcpy(ha, proxy_entry->ha, dev->addr_len);
+                               arp_unlock();
+
+                               rt = ip_rt_route(tip, 0);
+                               if (rt  && rt->rt_dev != dev)
+                                       arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha,sha);
+                               ip_rt_put(rt);
+
                        }
-                       cli();
+                       else
+                               arp_unlock();
                }
-               arp_bh_mask  &= ~ARP_BH_BACKLOG;
+               else
+                       arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+
+/*
+ *     Handle gratuitous arp.
+ */
+               arp_fast_lock();
+               arp_update(sip, sha, dev, NULL, 1);
                arp_unlock();
+               kfree_skb(skb, FREE_READ);
+               return 0;
        }
-       restore_flags(flags);
+
+       arp_fast_lock();
+       arp_update(sip, sha, dev, NULL, ip_chk_addr(tip) != IS_MYADDR);
+       arp_unlock();
+       kfree_skb(skb, FREE_READ);
+       return 0;
 }
 
+
+
 /*
- * Test if a hardware address is all zero
+ *     User level interface (ioctl, /proc)
  */
 
-static inline int empty(unsigned char * addr, int len)
-{
-       while (len > 0) {
-               if (*addr)
-                       return 0;
-               len--;
-               addr++;
-       }
-       return 1;
-}
-
 /*
  *     Set (create) an ARP cache entry.
  */
 
 static int arp_req_set(struct arpreq *r, struct device * dev)
 {
-       struct arp_table *entry;
+       struct arp_table *entry, **entryp;
        struct sockaddr_in *si;
-       struct rtable *rt;
-       struct device *dev1;
        unsigned char *ha;
        u32 ip;
+       u32 mask = DEF_ARP_NETMASK;
+       unsigned long flags;
+
+       /*
+        *      Extract netmask (if supplied).
+        */
+
+       if (r->arp_flags&ATF_NETMASK)
+       {
+               si = (struct sockaddr_in *) &r->arp_netmask;
+               mask = si->sin_addr.s_addr;
+       }
 
        /*
         *      Extract destination.
@@ -1885,112+1968,89 @@ static int arp_req_set(struct arpreq *r, struct device * dev)
        si = (struct sockaddr_in *) &r->arp_pa;
        ip = si->sin_addr.s_addr;
 
-       /*
-        *      Is it reachable ?
-        */
 
-       if (ip_chk_addr(ip) == IS_MYADDR)
-               dev1 = dev_get("lo");
-       else {
-               rt = ip_rt_route(ip, 0);
-               if (!rt)
-                       return -ENETUNREACH;
-               dev1 = rt->rt_dev;
-               ip_rt_put(rt);
+       if (r->arp_flags&ATF_PUBL)
+       {
+               if (!mask && ip)
+                       return -EINVAL;
+               if (!dev)
+                       dev = dev_getbytype(r->arp_ha.sa_family);
        }
-
-       /* good guess about the device if it isn't a ATF_PUBL entry */
-       if (!dev) {
-               if (dev1->flags&(IFF_LOOPBACK|IFF_NOARP))
-                       return -ENODEV;
-               dev = dev1;
+       else
+       {
+               if (ip_chk_addr(ip))
+                       return -EINVAL;
+               if (!dev)
+               {
+                       struct rtable * rt;
+                       rt = ip_rt_route(ip, 0);
+                       if (!rt)
+                               return -ENETUNREACH;
+                       dev = rt->rt_dev;
+                       ip_rt_put(rt);
+               }
        }
+       if (!dev || (dev->flags&(IFF_LOOPBACK|IFF_NOARP)))
+               return -ENODEV;
 
-       /* this needs to be checked only for dev=dev1 but it doesn't hurt */    
        if (r->arp_ha.sa_family != dev->type)   
                return -EINVAL;
                
-       if (((r->arp_flags & ATF_PUBL) && dev == dev1) ||
-           (!(r->arp_flags & ATF_PUBL) && dev != dev1))
-               return -EINVAL;
-
+       arp_fast_lock();
 #if RT_CACHE_DEBUG >= 1
-       if (arp_lock)
+       if (ARP_LOCKED())
                printk("arp_req_set: bug\n");
 #endif
-       arp_fast_lock();
-
-       /*
-        *      Is there an existing entry for this address?
-        */
 
-       /*
-        *      Find the entry
-        */
-       
-       entry = arp_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev);
-       if (entry == NULL)
-               entry = arpd_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev, __LINE__);
+       if (!(r->arp_flags & ATF_PUBL))
+               entryp = &arp_tables[HASH(ip)];
+       else
+               entryp = &arp_proxy_list;
 
-       if (entry)
+       while ((entry = *entryp) != NULL)
        {
-               arp_destroy(entry);
-               entry = NULL;
+               if (entry->ip == ip && entry->mask == mask && entry->dev == dev)
+                       break;
+               if ((entry->mask & mask) != mask)
+               {
+                       entry = NULL;
+                       break;
+               }
+               entryp = &entry->next;
        }
 
        /*
-        *      Do we need to create a new entry
+        *      Do we need to create a new entry?
         */
        
        if (entry == NULL)
        {
-               entry = arp_add_entry();
+               entry = arp_alloc_entry();
                if (entry == NULL)
                {
                        arp_unlock();
                        return -ENOMEM;
                }
                entry->ip = ip;
-               entry->hh = NULL;
-               init_timer(&entry->timer);
-               entry->timer.function = arp_expire_request;
-               entry->timer.data = (unsigned long)entry;
+               entry->dev = dev;
+               entry->mask = mask;
+               entry->flags = r->arp_flags;
 
-               if (r->arp_flags & ATF_PUBL)
-               {
-                       cli();
-                       entry->next = arp_proxy_list;
-                       arp_proxy_list = entry;
-                       sti();
-               }
-               else
-               {
-                       unsigned long hash = HASH(ip);
-                       cli();
-                       entry->next = arp_tables[hash];
-                       arp_tables[hash] = entry;
-                       sti();
-               }
-               skb_queue_head_init(&entry->skb);
+               entry->next = (*entryp)->next;
+               *entryp = entry;
        }
-       /*
-        *      We now have a pointer to an ARP entry.  Update it!
-        */
+
        ha = r->arp_ha.sa_data;
-       if ((r->arp_flags & ATF_COM) && empty(ha, dev->addr_len))
+       if (empty(ha, dev->addr_len))
                ha = dev->dev_addr;
+
+       save_flags(flags);
+       cli();
        memcpy(entry->ha, ha, dev->addr_len);
        entry->last_updated = entry->last_used = jiffies;
-       arpd_update(entry, __LINE__);
-       entry->flags = r->arp_flags | ATF_COM;
-       if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK))
-       {
-               si = (struct sockaddr_in *) &r->arp_netmask;
-               entry->mask = si->sin_addr.s_addr;
-       }
-       else
-               entry->mask = DEF_ARP_NETMASK;
-       entry->dev = dev;
+       entry->flags |= ATF_COM;
+       restore_flags(flags);
+       arpd_update(entry);
        arp_update_hhs(entry);
        arp_unlock();
        return 0;
@@ -2006,77+2066,88 @@ static int arp_req_get(struct arpreq *r, struct device *dev)
 {
        struct arp_table *entry;
        struct sockaddr_in *si;
+       u32 mask = DEF_ARP_NETMASK;
+
+       if (r->arp_flags&ATF_NETMASK)
+       {
+               si = (struct sockaddr_in *) &r->arp_netmask;
+               mask = si->sin_addr.s_addr;
+       }
 
        si = (struct sockaddr_in *) &r->arp_pa;
 
+       arp_fast_lock();
 #if RT_CACHE_DEBUG >= 1
-       if (arp_lock)
-               printk("arp_req_set: bug\n");
+       if (ARP_LOCKED())
+               printk("arp_req_set: impossible\n");
 #endif
-       arp_fast_lock();
 
-       entry = arp_lookup(si->sin_addr.s_addr, r->arp_flags|ATF_NETMASK, dev);
-       if (entry == NULL)
-               entry = arpd_lookup(si->sin_addr.s_addr, 
-                                       r->arp_flags|ATF_NETMASK, dev, __LINE__);
+       if (!(r->arp_flags & ATF_PUBL))
+               entry = arp_tables[HASH(si->sin_addr.s_addr)];
+       else
+               entry = arp_proxy_list;
 
-       if (entry == NULL)
+       for ( ; entry ;entry = entry->next)
        {
-               arp_unlock();
-               return -ENXIO;
+               if (entry->ip == si->sin_addr.s_addr 
+                   && (!dev || entry->dev == dev)
+                   && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask))
+               {
+                       memcpy(r->arp_ha.sa_data, entry->ha, entry->dev->addr_len);
+                       r->arp_ha.sa_family = entry->dev->type;
+                       r->arp_flags = entry->flags;
+                       strncpy(r->arp_dev, entry->dev->name, sizeof(r->arp_dev));
+                       arp_unlock();
+                       return 0;
+               }
        }
 
-       /*
-        *      We found it; copy into structure.
-        */
-       
-       memcpy(r->arp_ha.sa_data, &entry->ha, entry->dev->addr_len);
-       r->arp_ha.sa_family = entry->dev->type;
-       r->arp_flags = entry->flags;
-       strncpy(r->arp_dev, entry->dev->name, 16);
        arp_unlock();
-       return 0;
+       return -ENXIO;
 }
 
 static int arp_req_delete(struct arpreq *r, struct device * dev)
 {
-       struct arp_table *entry;
-       struct sockaddr_in *si;
+       struct sockaddr_in      *si;
+       struct arp_table        *entry, **entryp;
+       int     retval = -ENXIO;
+       u32     mask = DEF_ARP_NETMASK;
+
+       if (r->arp_flags&ATF_NETMASK)
+       {
+               si = (struct sockaddr_in *) &r->arp_netmask;
+               mask = si->sin_addr.s_addr;
+       }
 
        si = (struct sockaddr_in *) &r->arp_pa;
+
+       arp_fast_lock();
 #if RT_CACHE_DEBUG >= 1
-       if (arp_lock)
-               printk("arp_req_delete: bug\n");
+       if (ARP_LOCKED())
+               printk("arp_req_delete: impossible\n");
 #endif
-       arp_fast_lock();
 
        if (!(r->arp_flags & ATF_PUBL))
-       {
-               for (entry = arp_tables[HASH(si->sin_addr.s_addr)];
-                    entry != NULL; entry = entry->next)
-                       if (entry->ip == si->sin_addr.s_addr 
-                           && (!dev || entry->dev == dev))
-                       {
-                               arp_destroy(entry);
-                               arp_unlock();
-                               return 0;
-                       }
-       }
+               entryp = &arp_tables[HASH(si->sin_addr.s_addr)];
        else
+               entryp = &arp_proxy_list;
+
+       while ((entry = *entryp) != NULL)
        {
-               for (entry = arp_proxy_list;
-                    entry != NULL; entry = entry->next)
-                       if (entry->ip == si->sin_addr.s_addr 
-                           && (!dev || entry->dev == dev)) 
-                       {
-                               arp_destroy(entry);
-                               arp_unlock();
-                               return 0;
-                       }
+               if (entry->ip == si->sin_addr.s_addr 
+                   && (!dev || entry->dev == dev)
+                   && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask))
+               {
+                       *entryp = entry->next;
+                       arp_free_entry(entry);
+                       retval = 0;
+                       continue;
+               }
+               entryp = &entry->next;
        }
 
        arp_unlock();
-       return -ENXIO;
+       return retval;
 }
 
 /*
@@ -2119,8+2190,11 @@ int arp_ioctl(unsigned int cmd, void *arg)
 
        if (r.arp_pa.sa_family != AF_INET)
                return -EPFNOSUPPORT;
-       if (((struct sockaddr_in *)&r.arp_pa)->sin_addr.s_addr == 0)
-               return -EINVAL;
+
+       if (!(r.arp_flags & ATF_PUBL))
+               r.arp_flags &= ~ATF_NETMASK;
+       if (!(r.arp_flags & ATF_NETMASK))
+               ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=DEF_ARP_NETMASK;
 
        if (r.arp_dev[0])
        {
@@ -2132,14+2206,6 @@ int arp_ioctl(unsigned int cmd, void *arg)
                else if (r.arp_ha.sa_family != dev->type)
                        return -EINVAL;
        }
-       else
-       {
-               if ((r.arp_flags & ATF_PUBL) &&
-                   ((cmd == SIOCSARP) || (cmd == OLD_SIOCSARP))) {
-                       if ((dev = dev_getbytype(r.arp_ha.sa_family)) == NULL)
-                               return -ENODEV;
-               }
-       }                
 
        switch(cmd)
        {
@@ -2199,6+2265,99 @@ int arp_ioctl(unsigned int cmd, void *arg)
        return 0;
 }
 
+/*
+ *     Write the contents of the ARP cache to a PROCfs file.
+ */
+
+#define HBUFFERLEN 30
+
+int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       int len=0;
+       off_t pos=0;
+       int size;
+       struct arp_table *entry;
+       char hbuffer[HBUFFERLEN];
+       int i,j,k;
+       const char hexbuf[] =  "0123456789ABCDEF";
+
+       size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask     Device\n");
+
+       pos+=size;
+       len+=size;
+
+       arp_fast_lock();
+
+       for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
+       {
+               for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
+               {
+/*
+ *     Convert hardware address to XX:XX:XX:XX ... form.
+ */
+#ifdef CONFIG_AX25
+#ifdef CONFIG_NETROM
+                       if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM)
+                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+                       else {
+#else
+                       if(entry->dev->type==ARPHRD_AX25)
+                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+                       else {
+#endif
+#endif
+
+                       for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->dev->addr_len;j++)
+                       {
+                               hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
+                               hbuffer[k++]=hexbuf[  entry->ha[j]&15     ];
+                               hbuffer[k++]=':';
+                       }
+                       hbuffer[--k]=0;
+       
+#ifdef CONFIG_AX25
+                       }
+#endif
+                       size = sprintf(buffer+len,
+                               "%-17s0x%-10x0x%-10x%s",
+                               in_ntoa(entry->ip),
+                               (unsigned int)entry->dev->type,
+                               entry->flags,
+                               hbuffer);
+#if RT_CACHE_DEBUG < 2
+                       size += sprintf(buffer+len+size,
+                                "     %-17s %s\n",
+                                entry->mask==DEF_ARP_NETMASK ?
+                                "*" : in_ntoa(entry->mask), entry->dev->name);
+#else
+                       size += sprintf(buffer+len+size,
+                                "     %-17s %s\t%d\t%1d\n",
+                                entry->mask==DEF_ARP_NETMASK ?
+                                "*" : in_ntoa(entry->mask), entry->dev->name, 
+                                entry->hh ? entry->hh->hh_refcnt : -1,
+                                entry->hh ? entry->hh->hh_uptodate : 0);
+#endif
+       
+                       len += size;
+                       pos += size;
+                 
+                       if (pos <= offset)
+                               len=0;
+                       if (pos >= offset+length)
+                               goto done;
+               }
+       }
+done:
+       arp_unlock();
+  
+       *start = buffer+len-(pos-offset);       /* Start of wanted data */
+       len = pos-offset;                       /* Start slop */
+       if (len>length)
+               len = length;                   /* Ending slop */
+       return len;
+}
+
+
 
 /*
  *     Called once on startup.
@@ -2237,5+2396,8 @@ void arp_init (void)
                arp_get_info
        });
 #endif
-}
 
+#ifdef CONFIG_ARPD
+       netlink_attach(NETLINK_ARPD, arpd_callback);
+#endif
+}
index b761ba9..b10f205 100644 (file)
  *     Additional Authors:
  *             Alan Cox, <gw4pts@gw4pts.ampr.org>
  */
+
+#include <linux/config.h>      /* For CONFIG_IP_CLASSLESS */
  
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -76,7+78,9 @@ unsigned long ip_get_mask(unsigned long addr)
 int ip_chk_addr(unsigned long addr)
 {
        struct device *dev;
+#ifndef CONFIG_IP_CLASSLESS
        unsigned long mask;
+#endif
 
        /* 
         *      Accept both `all ones' and `all zeros' as BROADCAST. 
@@ -90,6+94,7 @@ int ip_chk_addr(unsigned long addr)
            addr == htonl(0x7FFFFFFFL))
                return IS_BROADCAST;
 
+#ifndef  CONFIG_IP_CLASSLESS
        mask = ip_get_mask(addr);
 
        /*
@@ -98,6+103,10 @@ int ip_chk_addr(unsigned long addr)
         
        if ((addr & mask) == htonl(0x7F000000L))
                return IS_MYADDR;
+#else
+       if ((addr & htonl(0x7F000000L)) == htonl(0x7F000000L))
+               return IS_MYADDR;
+#endif
 
        /*
         *      OK, now check the interface addresses. We could
@@ -139,6+148,7 @@ int ip_chk_addr(unsigned long addr)
                                return IS_BROADCAST;
                }
                
+#ifndef CONFIG_IP_CLASSLESS
                /*
                 *      Nope. Check for Network broadcast. 
                 */
@@ -150,6+160,7 @@ int ip_chk_addr(unsigned long addr)
                        if ((addr & ~mask) == ~mask)
                                return IS_BROADCAST;
                }
+#endif
        }
        if(IN_MULTICAST(ntohl(addr)))
                return IS_MULTICAST;
@@ -181,36+192,34 @@ unsigned long ip_my_addr(void)
 
 /*
  *     Find an interface that can handle addresses for a certain address. 
- *
- *     This needs optimising, since it's relatively trivial to collapse
- *     the two loops into one.
  */
-struct device * ip_dev_check(unsigned long addr)
+
+struct device * ip_dev_bynet(unsigned long addr, unsigned long mask)
 {
        struct device *dev;
+       struct device *best_dev = NULL;
+       __u32  best_mask = mask;
 
        for (dev = dev_base; dev; dev = dev->next) 
        {
                if (!(dev->flags & IFF_UP))
                        continue;
-               if (!(dev->flags & IFF_POINTOPOINT))
-                       continue;
-               if (addr != dev->pa_dstaddr)
-                       continue;
-               return dev;
-       }
-       for (dev = dev_base; dev; dev = dev->next) 
-       {
-               if (!(dev->flags & IFF_UP))
-                       continue;
                if (dev->flags & IFF_POINTOPOINT)
+               {
+                       if (addr == dev->pa_dstaddr)
+                               return dev;
                        continue;
+               }
                if (dev->pa_mask & (addr ^ dev->pa_addr))
                        continue;
-               return dev;
+               if (mask == dev->pa_mask)
+                       return dev;
+               if (best_dev && (best_mask & dev->pa_mask) != best_mask)
+                       continue;
+               best_dev = dev;
+               best_mask = dev->pa_mask;
        }
-       return NULL;
+       return best_dev;
 }
 
 /*
index f1dadbc..18383a8 100644 (file)
@@ -215,7+215,7 @@ extern __inline__ int random(void)
 }
 
 /*
- *     Inlined as its only called once.
+ *     Inlined as it's only called once.
  */
 
 static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time)
index 7e08140..e71ab06 100644 (file)
@@ -216,7+216,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
 #ifndef CONFIG_IP_NO_ICMP_REDIRECT
                if (dev == dev2 && 
                        !((iph->saddr^dev->pa_addr)&dev->pa_mask) &&
-                       /* The daddr!=raddr test isn't obvious - what its doing
+                       /* The daddr!=raddr test isn't obvious - what it's doing
                           is avoiding sending a frame the receiver will not 
                           believe anyway.. */
                        iph->daddr != raddr/*ANK*/ && !opt->srr)
@@ -247,7+247,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
 #ifdef CONFIG_IP_MASQUERADE
                /*
                 * If this fragment needs masquerading, make it so...
-                * (Dont masquerade de-masqueraded fragments)
+                * (Don't masquerade de-masqueraded fragments)
                 */
                if (!(is_frag&IPFWD_MASQUERADED) && fw_res==FW_MASQUERADE)
                        ip_fw_masquerade(&skb, dev2);
index 919af64..e5fc277 100644 (file)
@@ -754,7+754,7 @@ void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int i
                        ip_options_fragment(skb);
 
                /*
-                *      Added AC : If we are fragmenting a fragment thats not the
+                *      Added AC : If we are fragmenting a fragment that's not the
                 *                 last fragment then keep MF on each bit
                 */
                if (left > 0 || (is_frag & 1))
index 5b92ded..e1ac232 100644 (file)
@@ -539,7+539,7 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
 
  /*
   *    Check if it's an masqueraded port, look it up,
-  *    and send it on it's way...
+  *    and send it on its way...
   *
   *    Better not have many hosts using the designated portrange
   *    as 'normal' ports, or you'll be spending many time in
@@ -639,7+639,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                  */
                 if (iph->protocol==IPPROTO_UDP)
                {
-                       unsigned long   timeout;
                         recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
                        ip_masq_set_expire(ms, 0);
                        ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
index 1bd4d37..032563b 100644 (file)
@@ -224,7+224,7 @@ int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr,
                 * release route, so that...
                 */
                if (rt)
-                       ATOMIC_INCR(&rt->rt_refcnt);
+                       atomic_inc(&rt->rt_refcnt);
        }
        else
                rt = ip_rt_route(daddr, skb->localroute);
@@ -1059,7+1059,8 @@ void ip_netlink_msg(unsigned long msg, __u32 daddr, __u32 gw, __u32 mask, short
        nrt->rtmsg_flags=flags;
        nrt->rtmsg_metric=metric;
        strcpy(nrt->rtmsg_device,name);
-       netlink_post(NETLINK_ROUTE, skb);
+       if (netlink_post(NETLINK_ROUTE, skb))
+               kfree_skb(skb, FREE_WRITE);
 }      
 
 #endif
@@ -1085,6+1086,7 @@ static int ip_rt_event(struct notifier_block *this, unsigned long event, void *p
                ip_mc_allhost(dev);
 #endif         
                ip_netlink_msg(RTMSG_NEWDEVICE, 0,0,0,0,0,dev->name);
+               ip_rt_update(NETDEV_UP, dev);
        }
        return NOTIFY_DONE;
 }
index 0fcb357..1573667 100644 (file)
@@ -181,7+181,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                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 */
+                       if ((val&7) > 4 && !suser())    /* Only root can set Prec>4 */
                                return -EPERM;
                        sk->ip_tos=val;
                        switch (val & 0x38) {
@@ -297,7+297,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                                {
                                        dev=rt->rt_dev;
                                        route_src = rt->rt_src;
-                                       ATOMIC_DECR(&rt->rt_use);
+                                       atomic_dec(&rt->rt_use);
                                        ip_rt_put(rt);
                                }
                        }
@@ -350,7+350,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                                if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL)
                                {
                                        dev=rt->rt_dev;
-                                       ATOMIC_DECR(&rt->rt_use);
+                                       atomic_dec(&rt->rt_use);
                                        route_src = rt->rt_src;
                                        ip_rt_put(rt);
                                }
index 200e561..7b18ac1 100644 (file)
@@ -74,39+74,15 @@ int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        skb->h.iph=(struct iphdr *)skb->data;
        skb->ip_hdr=(struct iphdr *)skb->data;
        memset(skb->proto_priv, 0, sizeof(struct options));
-       if (skb->ip_hdr->ihl > 5) 
-       {
-               if (ip_options_compile(NULL, skb))
-                       return 0;
-       }
-       
-#ifdef CONFIG_FIREWALL
-       /*
-        *      Check the firewall [well spotted Olaf]
-        */
-        
-       if((err=call_in_firewall(PF_INET, skb->dev, skb->ip_hdr))<FW_ACCEPT)
-       {
-               if(err==FW_REJECT)
-                       icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0 , dev);
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }       
-#endif
 
        /*
         *      If you want to add LZ compressed IP or things like that here,
         *      and in drivers/net/tunnel.c are the places to add.
         */
        
-       /* skb=lzw_uncompress(skb); */
-       
-       /*
-        *      Feed to IP forward.
-        */
-        
-       if(ip_forward(skb, dev, 0, daddr))
-               kfree_skb(skb, FREE_READ);
+       skb->protocol = htons(ETH_P_IP);
+       skb->ip_summed = 0;
+       netif_rx(skb);
        MOD_DEC_USE_COUNT;
        return(0);
 }
index f4f2be1..c051043 100644 (file)
@@ -397,7+397,7 @@ int ipmr_mfc_modify(int action, struct mfcctl *mfc)
                return 0;
        }
        /*
-        *      Unsolicited update - thats ok add anyway.
+        *      Unsolicited update - that's ok, add anyway.
         */
         
        
@@ -420,7+420,7 @@ int ipmr_mfc_modify(int action, struct mfcctl *mfc)
 /*
  *     Socket options and virtual interface manipulation. The whole
  *     virtual interface system is a complete heap, but unfortunately
- *     thats how BSD mrouted happens to think. Maybe one day with a proper
+ *     that's how BSD mrouted happens to think. Maybe one day with a proper
  *     MOSPF/PIM router set up we can clean this up.
  */
  
@@ -487,7+487,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
                                {
                                        if(dev->flags&IFF_MULTICAST)
                                        {
-                                               /* Most ethernet cards dont know
+                                               /* Most ethernet cards don't know
                                                   how to do this yet.. */
                                                dev->flags|=IFF_ALLMULTI;
                                                dev_mc_upload(dev);
index 9bec91e..de9844c 100644 (file)
@@ -5,7+5,7 @@
  *
  *             PACKET - implements raw packet sockets.
  *
- *             Doesn't belong in IP but its currently too hooked into ip
+ *             Doesn't belong in IP but it's currently too hooked into ip
  *             to separate.
  *
  * Version:    @(#)packet.c    1.0.6   05/25/93
@@ -176,7+176,7 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len,
 
        /*
         *      If the write buffer is full, then tough. At this level the user gets to
-        *      deal with the problem - do your own algorithmic backoffs. Thats far
+        *      deal with the problem - do your own algorithmic backoffs. That's far
         *      more flexible.
         */
         
index 13e61b2..5b9fc3c 100644 (file)
@@ -68,11+68,15 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
        unsigned short destp, srcp;
        int len=0;
        off_t pos=0;
-       off_t begin=0;
+       off_t begin;
+       char tmpbuf[129];
   
        s_array = pro->sock_array;
-       len += sprintf(buffer, "sl  local_address rem_address   st tx_queue "
-           "rx_queue tr tm->when uid inode\n");
+       if (offset < 128) 
+               len += sprintf(buffer, "%-127s\n",
+                              "  sl  local_address rem_address   st tx_queue "
+                              "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+       pos = 128;
 /*
  *     This was very pretty but didn't work when a socket is destroyed
  *     at the wrong moment (eg a syn recv socket getting a reset), or
@@ -85,6+89,12 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                sp = s_array[i];
                while(sp != NULL) 
                {
+                       pos += 128;
+                       if (pos < offset)
+                       {
+                               sp = sp->next;
+                               continue;
+                       }
                        dest  = sp->daddr;
                        src   = sp->saddr;
                        destp = sp->dummy_th.dest;
@@ -109,8+119,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                            timer_active=timer_active2;
                            timer_expires=sp->timer.expires;
                        }
-                       len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X"
-                           " %02X %08X:%08X %02X:%08lX %08X %d %d %ld\n",
+                       sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
+                               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
                                i, src, srcp, dest, destp, sp->state, 
                                format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc, 
                                format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc,
@@ -121,32+131,28 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                                SOCK_INODE(sp->socket)->i_ino : 0);
                        if (timer_active1) add_timer(&sp->retransmit_timer);
                        if (timer_active2) add_timer(&sp->timer);
+                       len += sprintf(buffer+len, "%-127s\n", tmpbuf);
                        /*
                         * All sockets with (port mod SOCK_ARRAY_SIZE) = i
                         * are kept in sock_array[i], so we must follow the
                         * 'next' link to get them all.
                         */
-                       sp = sp->next;
-                       pos=begin+len;
-                       if(pos<offset)
-                       {
-                               len=0;
-                               begin=pos;
-                       }
-                       if(pos>offset+length)
+                       if(len >= length)
                                break;
+                       sp = sp->next;
                }
                sti();  /* We only turn interrupts back on for a moment,
                           but because the interrupt queues anything built
                           up before this will clear before we jump back
                           and cli(), so it's not as bad as it looks */
-               if(pos>offset+length)
+               if(len>= length)
                        break;
        }
-       *start=buffer+(offset-begin);
-       len-=(offset-begin);
+       begin = len - (pos - offset);
+       *start = buffer + begin;
+       len -= begin;
        if(len>length)
-               len=length;
+               len = length;
        return len;
 } 
 
index 1f467fe..191e00f 100644 (file)
@@ -198,7+198,7 @@ static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int of
                if(!iph->saddr)
                        iph->saddr=saddr;
                iph->check=0;
-               iph->tot_len=htons(fraglen);    /* This is right as you cant frag
+               iph->tot_len=htons(fraglen);    /* This is right as you can't frag
                                           RAW packets */
                /*
                 *      Deliberate breach of modularity to keep 
index 9f32196..633cd2c 100644 (file)
@@ -321,42+321,6 @@ static __inline__ struct device * get_gw_dev(__u32 gw)
 }
 
 /*
- *     Used by 'rt_add()' when we can't get the netmask any other way..
- *
- *     If the lower byte or two are zero, we guess the mask based on the
- *     number of zero 8-bit net numbers, otherwise we use the "default"
- *     masks judging by the destination address and our device netmask.
- */
-static __u32 unsigned long default_mask(__u32 dst)
-{
-       dst = ntohl(dst);
-       if (IN_CLASSA(dst))
-               return htonl(IN_CLASSA_NET);
-       if (IN_CLASSB(dst))
-               return htonl(IN_CLASSB_NET);
-       return htonl(IN_CLASSC_NET);
-}
-
-
-/*
- *     If no mask is specified then generate a default entry.
- */
-
-static __u32 guess_mask(__u32 dst, struct device * dev)
-{
-       __u32 mask;
-
-       if (!dst)
-               return 0;
-       mask = default_mask(dst);
-       if ((dst ^ dev->pa_addr) & mask)
-               return mask;
-       return dev->pa_mask;
-}
-
-
-/*
  *     Check if a mask is acceptable.
  */
  
@@ -527,50+491,6 @@ static __inline__ void fib_add_1(short flags, __u32 dst, __u32 mask,
        struct fib_info * fi;
        int logmask;
 
-       if (flags & RTF_HOST) 
-               mask = 0xffffffff;
-       /*
-        * If mask is not specified, try to guess it.
-        */
-       else if (!mask)
-       {
-               if (!((dst ^ dev->pa_addr) & dev->pa_mask)) 
-               {
-                       mask = dev->pa_mask;
-                       flags &= ~RTF_GATEWAY;
-                       if (flags & RTF_DYNAMIC) 
-                       {
-                               printk("Dynamic route to my own net rejected\n");
-                               return;
-                       }
-               } 
-               else
-                       mask = guess_mask(dst, dev);
-               dst &= mask;
-       }
-       
-       /*
-        *      A gateway must be reachable and not a local address
-        */
-        
-       if (gw == dev->pa_addr)
-               flags &= ~RTF_GATEWAY;
-               
-       if (flags & RTF_GATEWAY) 
-       {
-               /*
-                *      Don't try to add a gateway we can't reach.. 
-                *      Tunnel devices are exempt from this rule.
-                */
-                
-               if ((dev != get_gw_dev(gw)) && dev->type!=ARPHRD_TUNNEL)
-                       return;
-                       
-               flags |= RTF_GATEWAY;
-       } 
-       else
-               gw = 0;
-               
        /*
         *      Allocate an entry and fill it in.
         */
@@ -632,7+552,7 @@ static __inline__ void fib_add_1(short flags, __u32 dst, __u32 mask,
        if (fz->fz_nent >= RTZ_HASHING_LIMIT && !fz->fz_hash_table && logmask<32)
        {
                struct fib_node ** ht;
-#if RT_CACHE_DEBUG
+#if RT_CACHE_DEBUG >= 2
                printk("fib_add_1: hashing for zone %d started\n", logmask);
 #endif
                ht = kmalloc(RTZ_HASH_DIVISOR*sizeof(struct rtable*), GFP_KERNEL);
@@ -747,7+667,12 @@ static int rt_flush_list(struct fib_node ** fp, struct device *dev)
        struct fib_node *f;
 
        while ((f = *fp) != NULL) {
-               if (f->fib_info->fib_dev != dev) {
+/*
+ *     "Magic" device route is allowed to point to loopback,
+ *     discard it too.
+ */
+               if (f->fib_info->fib_dev != dev &&
+                   (dev != &loopback_dev || f->fib_dst != dev->pa_addr)) {
                        fp = &f->fib_next;
                        continue;
                }
@@ -797,7+722,7 @@ static __inline__ void fib_flush_1(struct device *dev)
  *
  *     We preserve the old format but pad the buffers out. This means that
  *     we can spin over the other entries as we read them. Remember the
- *     gated BGP4 code could need to read 60,000+ routes on occasion (thats
+ *     gated BGP4 code could need to read 60,000+ routes on occasion (that's
  *     about 7Mb of data). To do that ok we will need to also cache the
  *     last route we got to (reads will generally be following on from
  *     one another without gaps).
@@ -961,12+886,9 @@ static void rt_free(struct rtable * rt)
        {
                struct hh_cache * hh = rt->rt_hh;
                rt->rt_hh = NULL;
-               if (hh && !--hh->hh_refcnt)
-               {
-                       restore_flags(flags);
-                       kfree_s(hh, sizeof(struct hh_cache));
-               }
                restore_flags(flags);
+               if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+                       kfree_s(hh, sizeof(struct hh_cache));
                kfree_s(rt, sizeof(struct rt_table));
                return;
        }
@@ -1000,12+922,9 @@ static __inline__ void rt_kick_free_queue(void)
 #endif
                        *rtp = rt->rt_next;
                        rt->rt_hh = NULL;
-                       if (hh && !--hh->hh_refcnt)
-                       {
-                               sti();
-                               kfree_s(hh, sizeof(struct hh_cache));
-                       }
                        sti();
+                       if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+                               kfree_s(hh, sizeof(struct hh_cache));
                        kfree_s(rt, sizeof(struct rt_table));
 #if RT_CACHE_DEBUG >= 2
                        printk("rt_kick_free_queue: %08x is free\n", daddr);
@@ -1017,7+936,8 @@ static __inline__ void rt_kick_free_queue(void)
        }
 }
 
-void ip_rt_run_bh() {
+void ip_rt_run_bh()
+{
        unsigned long flags;
        save_flags(flags);
        cli();
@@ -1409,7+1329,7 @@ static void rt_cache_add(unsigned hash, struct rtable * rth)
                        else
                        {
                                if (rtg->rt_hh)
-                                       ATOMIC_INCR(&rtg->rt_hh->hh_refcnt);
+                                       atomic_inc(&rtg->rt_hh->hh_refcnt);
                                rth->rt_hh = rtg->rt_hh;
                                ip_rt_put(rtg);
                        }
@@ -1570,7+1490,7 @@ struct rtable * ip_rt_slow_route (__u32 daddr, int local)
        {
                rt_free(rth);
 #if RT_CACHE_DEBUG >= 1
-               printk("rt_cache: route to %08x was born dead\n", daddr);
+               printk(KERN_DEBUG "rt_cache: route to %08x was born dead\n", daddr);
 #endif
        }
 
@@ -1581,7+1501,7 @@ struct rtable * ip_rt_slow_route (__u32 daddr, int local)
 void ip_rt_put(struct rtable * rt)
 {
        if (rt)
-               ATOMIC_DECR(&rt->rt_refcnt);
+               atomic_dec(&rt->rt_refcnt);
 }
 
 struct rtable * ip_rt_route(__u32 daddr, int local)
@@ -1595,8+1515,8 @@ struct rtable * ip_rt_route(__u32 daddr, int local)
                if (rth->rt_dst == daddr)
                {
                        rth->rt_lastuse = jiffies;
-                       ATOMIC_INCR(&rth->rt_use);
-                       ATOMIC_INCR(&rth->rt_refcnt);
+                       atomic_inc(&rth->rt_use);
+                       atomic_inc(&rth->rt_refcnt);
                        ip_rt_unlock();
                        return rth;
                }
@@ -1671,42+1591,49 @@ int ip_rt_new(struct rtentry *r)
                }
        }
 
-       /*
-        *      Ignore faulty masks
-        */
-        
-       if (bad_mask(mask, daddr))
-               mask=0;
-
-       /*
-        *      Set the mask to nothing for host routes.
-        */
-        
-       if (flags & RTF_HOST)
+       if (flags & RTF_HOST) 
                mask = 0xffffffff;
        else if (mask && r->rt_genmask.sa_family != AF_INET)
                return -EAFNOSUPPORT;
 
-       /*
-        *      You can only gateway IP via IP..
-        */
-        
        if (flags & RTF_GATEWAY) 
        {
                if (r->rt_gateway.sa_family != AF_INET)
                        return -EAFNOSUPPORT;
+
+               /*
+                *      Don't try to add a gateway we can't reach.. 
+                *      Tunnel devices are exempt from this rule.
+                */
+
                if (!dev)
                        dev = get_gw_dev(gw);
+               else if (dev != get_gw_dev(gw) && dev->type != ARPHRD_TUNNEL)
+                       return -EINVAL;
+               if (!dev)
+                       return -ENETUNREACH;
        } 
-       else if (!dev)
-               dev = ip_dev_check(daddr);
+       else
+       {
+               gw = 0;
+               if (!dev)
+                       dev = ip_dev_bynet(daddr, mask);
+               if (!dev)
+                       return -ENETUNREACH;
+               if (!mask)
+               {
+                       if (((daddr ^ dev->pa_addr) & dev->pa_mask) == 0)
+                               mask = dev->pa_mask;
+               }
+       }
 
-       /*
-        *      Unknown device.
-        */
-        
-       if (dev == NULL)
-               return -ENETUNREACH;
+#ifndef CONFIG_IP_CLASSLESS
+       if (!mask)
+               mask = ip_get_mask(daddr);
+#endif
+       
+       if (bad_mask(mask, daddr))
+               return -EINVAL;
 
        /*
         *      Add the route
@@ -1783,3+1710,10 @@ void ip_rt_advice(struct rtable **rp, int advice)
        return;
 }
 
+void ip_rt_update(int event, struct device *dev)
+{
+       if (event == NETDEV_UP)
+               rt_add(RTF_HOST|RTF_UP, dev->pa_addr, ~0, 0, dev, 0, 0, 0, 0);
+       else if (event == NETDEV_DOWN)
+               rt_del(dev->pa_addr, ~0, dev, 0, RTF_HOST|RTF_UP, 0);
+}
index f572aca..7fba124 100644 (file)
  *                                     ack if stat is TCP_CLOSED.
  *             Alan Cox        :       Look up device on a retransmit - routes may
  *                                     change. Doesn't yet cope with MSS shrink right
- *                                     but its a start!
+ *                                     but it's a start!
  *             Marc Tamsky     :       Closing in closing fixes.
  *             Mike Shaver     :       RFC1122 verifications.
  *             Alan Cox        :       rcv_saddr errors.
@@ -1962,7+1962,7 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
        /*
         *      SKIP devices set their MTU to 65535. This is so they can take packets
         *      unfragmented to security process then fragment. They could lie to the
-        *      TCP layer about a suitable MTU, but its easier to let skip sort it out
+        *      TCP layer about a suitable MTU, but it's easier to let skip sort it out
         *      simply because the final package we want unfragmented is going to be
         *
         *      [IPHDR][IPSP][Security data][Modified TCP data][Security data]
index 17e81a2..37b2f8d 100644 (file)
 #include <net/tcp.h>
 
 /*
- *     Policy code extracted so its now separate
+ *     Policy code extracted so it's now separate
  */
 
 /*
@@ -344,7+344,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
         *      flurry of syns from eating up all our memory.
         *
         *      BSD does some funnies here and allows 3/2 times the
-        *      set backlog as a fudge factor. Thats just too gross.
+        *      set backlog as a fudge factor. That's just too gross.
         */
 
        if (sk->ack_backlog >= sk->max_ack_backlog) 
@@ -502,7+502,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        /*
         *      SKIP devices set their MTU to 65535. This is so they can take packets
         *      unfragmented to security process then fragment. They could lie to the
-        *      TCP layer about a suitable MTU, but its easier to let skip sort it out
+        *      TCP layer about a suitable MTU, but it's easier to let skip sort it out
         *      simply because the final package we want unfragmented is going to be
         *
         *      [IPHDR][IPSP][Security data][Modified TCP data][Security data]
@@ -607,7+607,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         */
 
        if(sk->zapped)
-               return(1);      /* Dead, cant ack any more so why bother */
+               return(1);      /* Dead, can't ack any more so why bother */
 
        /*
         *      We have dropped back to keepalive timeouts. Thus we have
@@ -1736,7+1736,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        
                /* 
                 *      Retransmitted SYN for our socket. This is uninteresting. If sk->state==TCP_LISTEN
-                *      then its a new connection
+                *      then it's a new connection
                 */
                 
                if (sk->state == TCP_SYN_RECV && th->syn && skb->seq+1 == sk->acked_seq)
@@ -1759,7+1759,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                                /* We got an ack, but it's not a good ack */
                                if(!tcp_ack(sk,th,skb->ack_seq,len))
                                {
-                                       /* Reset the ack - its an ack from a 
+                                       /* Reset the ack - it's an ack from a 
                                           different connection  [ th->rst is checked in tcp_send_reset()] */
                                        tcp_statistics.TcpAttemptFails++;
                                        tcp_send_reset(daddr, saddr, th,
index 760c225..63517cd 100644 (file)
 #include <linux/interrupt.h>
 
 /*
+ * RFC 1122 says:
+ *
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
+ *  RECV.NEXT + RCV.WIN fixed until:
+ *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+ *
+ * Experiments against BSD and Solaris machines show that following
+ * these rules results in the BSD and Solaris machines making very
+ * bad guesses about how much data they can have in flight.
+ *
+ * Instead we follow the BSD lead and offer a window that gives
+ * the size of the current free space, truncated to a multiple
+ * of 1024 bytes. If the window is smaller than
+ *     min(sk->mss, MAX_WINDOW/2)
+ * then we advertise the window as having size 0, unless this
+ * would shrink the window we offered last time.
+ * This results in as much as double the throughput as the original
+ * implementation.
+ *
+ * We do BSD style SWS avoidance -- note that RFC1122 only says we
+ * must do silly window avoidance, it does not require that we use
+ * the suggested algorithm.
+ *
+ * The "rcvbuf" and "rmem_alloc" values are shifted by 1, because
+ * they also contain buffer handling overhead etc, so the window
+ * we actually use is essentially based on only half those values.
+ */
+int tcp_new_window(struct sock * sk)
+{
+       unsigned long window;
+       unsigned long minwin, maxwin;
+
+       /* Get minimum and maximum window values.. */
+       minwin = sk->mss;
+       if (!minwin)
+               minwin = sk->mtu;
+       maxwin = sk->window_clamp;
+       if (!maxwin)
+               maxwin = MAX_WINDOW;
+       if (minwin > maxwin/2)
+               minwin = maxwin/2;
+
+       /* Get current rcvbuf size.. */
+       window = sk->rcvbuf/2;
+       if (window < minwin) {
+               sk->rcvbuf = minwin*2;
+               window = minwin;
+       }
+
+       /* Check rcvbuf against used and minimum window */
+       window -= sk->rmem_alloc/2;
+       if ((long)(window - minwin) < 0)                /* SWS avoidance */
+               window = 0;
+
+       if (window > 1023)
+               window &= ~1023;
+       if (window > maxwin)
+               window = maxwin;
+       return window;
+}
+
+/*
  *     Get rid of any delayed acks, we sent one already..
  */
 static __inline__ void clear_delayed_acks(struct sock * sk)
index bb02473..d4967b0 100644 (file)
  *     Revision 0.34:  Module support. <Jim Freeman>
  *     Revision 0.35:  Checksum support. <Neil Turton>, hooked in by <Alan Cox>
  *
+ *     Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
+ *     pair. Also, now usage count is managed this way
+ *     -Count one if the auto_interface mode is on
+ *      -Count one per configured interface
+ *
+ *     Jacques Gelinas (jacques@solucorp.qc.ca)
+ *
+ *
  *     Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
  *     Neither Greg Page nor Caldera, Inc. admit liability nor provide 
  *     warranty for any of this software. This material is provided 
@@ -105,7+113,14 @@ static ipx_interface       *ipx_internal_net = NULL;
 static int
 ipxcfg_set_auto_create(char val)
 {
-       ipxcfg_auto_create_interfaces = val;
+       if (ipxcfg_auto_create_interfaces != val){
+               if (val){
+                       MOD_INC_USE_COUNT;
+               }else{
+                       MOD_DEC_USE_COUNT;
+               }
+               ipxcfg_auto_create_interfaces = val;
+       }
        return 0;
 }
                
@@ -336,6+351,7 @@ ipxitf_down(ipx_interface *intrfc)
        /* sockets still dangling
         * - must be closed from user space
         */
+       MOD_DEC_USE_COUNT;
        return;
 }
 
@@ -803,6+819,7 @@ ipxitf_insert(ipx_interface *intrfc)
 
        if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL))
                ipx_primary_net = intrfc;
+       MOD_INC_USE_COUNT;
        return;
 }
 
@@ -1015,7+1032,7 @@ ipxitf_auto_create(struct device *dev, unsigned short dlink_type)
 }
 
 static int 
-ipxitf_ioctl(unsigned int cmd, void *arg)
+ipxitf_ioctl_real(unsigned int cmd, void *arg)
 {
        int err;
        switch(cmd)
@@ -1080,6+1097,15 @@ ipxitf_ioctl(unsigned int cmd, void *arg)
        }
 }
 
+static int 
+ipxitf_ioctl(unsigned int cmd, void *arg)
+{
+       int ret;
+       MOD_INC_USE_COUNT;
+       ret = ipxitf_ioctl_real (cmd,arg);
+       MOD_DEC_USE_COUNT;
+       return ret;
+}
 /*******************************************************************************************************************\
 *                                                                                                                  *
 *                                      Routing tables for the IPX socket layer                                     *
@@ -1312,7+1338,7 @@ static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struc
         *      Apply checksum. Not allowed on 802.3 links.
         */
         
-       if(sk->no_check || intrfc->if_dlink_type!=IPX_FRAME_8023)
+       if(sk->no_check || intrfc->if_dlink_type==IPX_FRAME_8023)
                ipx->ipx_checksum=0xFFFF;
        else
                ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(ipx_packet));
index b6ca49b..ab13513 100644 (file)
@@ -235,7+235,7 @@ static void nr_destroy_timer(unsigned long data)
  *     Once it is removed from the queue no interrupt or bottom half will
  *     touch it and we are (fairly 8-) ) safe.
  */
-void nr_destroy_socket(struct sock *sk)        /* Not static as its used by the timer */
+void nr_destroy_socket(struct sock *sk)        /* Not static as it's used by the timer */
 {
        struct sk_buff *skb;
        unsigned long flags;
@@ -954,7+954,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
        unsigned short frametype, window, timeout;
        
 
-       skb->sk = NULL;         /* Initially we don't know who its for */
+       skb->sk = NULL;         /* Initially we don't know who it's for */
 
        /*
         *      skb->data points to the netrom frame start
@@ -980,7+980,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev)
 #endif
 
        /*
-        * Find an existing socket connection, based on circuit ID, if its
+        * Find an existing socket connection, based on circuit ID, if it's
         * a Connect Request base it on their circuit ID.
         */
        if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
index f5e9efb..653f9f6 100644 (file)
@@ -395,7+395,7 @@ static int sock_write(struct inode *inode, struct file *file, const char *ubuf,
 
 /*
  *     With an ioctl arg may well be a user mode pointer, but we don't know what to do
- *     with it - thats up to the protocol still.
+ *     with it - that's up to the protocol still.
  */
 
 int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
index eec7b17..4ed43a0 100644 (file)
  *             Marty Leisner   :       Fixes to fd passing
  *             Nick Nevin      :       recvmsg bugfix.
  *             Alan Cox        :       Started proper garbage collector
+ *             Heiko EiBfeldt  :       Missing verify_area check
  *
  * Known differences from reference BSD that was tested:
  *
@@ -352,7+353,7 @@ static int unix_release(struct socket *sock, struct socket *peer)
        if(skpair!=NULL)
                skpair->protinfo.af_unix.locks--;       /* It may now die */
        sk->protinfo.af_unix.other=NULL;                /* No pair */
-       unix_destroy_socket(sk);                        /* Try and flush out this socket. Throw our buffers at least */
+       unix_destroy_socket(sk);                        /* Try to flush out this socket. Throw out buffers at least */
        
        /*
         *      FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
@@ -1222,6+1223,8 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        if((skb=skb_peek(&sk->receive_queue))!=NULL)
                                amount=skb->len;
                        err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
+                       if(err)
+                               return err;
                        put_fs_long(amount,(unsigned long *)arg);
                        return 0;
                }
index cfcf67f..4bc4b95 100644 (file)
@@ -1110,7+1110,7 @@ $DIALOG   --backtitle "$backtitle" \
 #
 # Check kernel version of previous menuconfig build.
 # If it's different then we should tell the sound driver
-# to rebuild it's Config.in file.
+# to rebuild its Config.in file.
 #
 rebuildsound=TRUE
 if [ -e .menuconfig ]
index d21170b..9cc10fa 100644 (file)
@@ -449,7+449,7 @@ void fix_conditionals(struct kconfig * scfg)
        {
          /*
           * Now search the condition list for a known configuration variable
-          * that has conditions of it's own.
+          * that has conditions of its own.
           */
          if(cnd->op != op_kvariable) continue;
          if(cnd->variable.cfg->cond == NULL) continue;
index 94181a1..2a00021 100644 (file)
@@ -662,7+662,7 @@ int main(int argc, char * argv[])
    * Input file is now parsed.  Next we need to go through and attach
    * the correct conditions to each of the actual menu items and kill
    * the if/else/endif tokens from the list.  We also flag the menu items
-   * that have other things that depend upon it's setting.
+   * that have other things that depend upon its setting.
    */
   fix_conditionals(config);
 
close