diff -u +recursive +new-file 0.99pl15/linux/CHANGES linux/CHANGES
--- 0.99pl15/linux/CHANGES	Wed Dec  1 14:44:15 1993
+++ linux/CHANGES	Mon Mar 14 00:25:31 1994
@@ -1,3 +1,13 @@
+CHANGES since 0.99 patchlevel 15:
+
+ - removed all the bugs, of course.
+ - networking fixes.
+ - more changes than I really wanted..
+
+CHANGES since 0.99 patchlevel 14:
+
+ - too many to count, really.  Besides, I've lost my notes. 
+
 CHANGES since 0.99 patchlevel 13:
 
  - new kernel source layout: drivers separated
diff -u +recursive +new-file 0.99pl15/linux/CREDITS linux/CREDITS
--- 0.99pl15/linux/CREDITS
+++ linux/CREDITS	Sun Mar 13 23:59:52 1994
@@ -0,0 +1,605 @@
+	This is at least a partial credits-file of people that have
+	contributed to the linux project.  It is sorted by name, and
+	formatted in a format that allows for easy grepping and
+	beautification by scripts.  The fields are: name (N), email (E),
+	description (D) and snail-mail address (S).  Thanks,
+
+			Linus
+----------
+
+N: Krishna Balasubramanian
+E: balasub@cis.ohio-state.edu
+D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
+
+N: Arindam Banerji
+E: axb@cse.nd.edu
+D: Contributed ESDI driver routines needed to port LINUX to the PS/2 MCA.
+S: Department of Computer Science & Eng.
+S: University of Notre Dame
+S: Notre Dame, Indiana
+S: USA
+
+N: Peter Bauer
+E: 100136.3530@compuserve.com
+D: Driver for depca-ethernet-board
+S: 69259 Wilhemsfeld
+S: Rainweg 15
+S: Germany
+
+N: Fred Baumgarten
+E: dc6iq@insu1.etec.uni-karlsruhe.de
+D: NET-2 & netstat(8)
+S: Kandelstrasse 27
+S: 76297 Stutensee
+S: Germany
+
+N: Donald Becker
+E: becker@super.org
+D: General low-level networking hacker
+D: Most of the ethercard drivers
+D: Original author of the NFS server
+S: 17100 Science Drive
+S: Bowie, Maryland 20715
+S: USA
+
+N: Stephen R. van den Berg (AKA BuGless)
+E: berg@pool.informatik.rwth-aachen.de
+D: General kernel, gcc, and libc hacker
+D: Specialisation: tweaking, ensuring portability, tweaking, cleaning,
+D: tweaking and occasionally debugging :-)
+S: Bouwensstraat 22
+S: 6369 BG  Simpelveld
+S: The Netherlands
+
+N: Hennus Bergman
+E: hennus@sky.nl.mugnet.org  [My uucp-fed Linux box at home]
+E: csg279@wing.rug.nl        [Alternate address]
+D: Author and maintainer of the QIC-02 tape driver
+S: The Netherlands
+
+N: Ross Biro
+E: bir7@leland.Stanford.Edu
+D: Original author of the Linux networking code
+
+N: Bill Bogstad
+E: bogstad@cs.jhu.edu
+D: Wrote /proc/self patch
+S: Johns Hopkins University
+S: Computer Science Department
+S: Baltimore, Maryland 21218
+S: USA
+
+N: John Boyd
+E: boyd@cis.ohio-state.edu
+D: Co-author of wd7000 SCSI driver
+S: 101 Curl Drive #591
+S: Columbus, Ohio 43210 
+S: USA
+
+N: Andries Brouwer
+E: aeb@cwi.nl
+D: International character handling for keyboard and console
+S: Bessemerstraat 21
+S: Amsterdam
+S: The Netherlands
+
+N: Remy Card
+E: Remy.Card@masi.ibp.fr
+D: Extended file system designer and developer
+D: Second extended file system designer and developer
+S: Institut Blaise Pascal
+S: 4 Place Jussieu, 75252 Paris Cedex 05
+S: France
+
+N: Ed Carp
+E: ecarp@netcom.com
+D: uucp, elm, pine, pico port
+D: cron, at(1) developer
+S: 48287 Sawleaf
+S: Fremont, California  94539
+S: USA
+
+N: Raymond Chen
+E: raymondc@microsoft.com
+D: Author of Configure script
+S: 14509 NE 39th St, #1096
+S: Bellevue WA 98007
+S: USA
+
+N: Alan Cox
+E: iiitac@pyr.swan.ac.uk
+E: gw4pts@gw4pts.ampr.org
+E: GW4PTS@GB7SWN (packet radio)
+D: NET2Debugged author
+D: Network layer debugging
+D: AX.25 & IPX alpha releases
+S: <No>
+
+N: Laurence Culhane
+E: loz@holmes.demon.co.uk
+D: Wrote the initial alpha SLIP code
+S: 81 Hood Street
+S: Northampton
+S: NN1 3QT
+S: England
+
+N: Wayne Davison
+E: davison@borland.com
+D: Second extended file system co-designer
+
+N: Thomas Dunbar
+E: tdunbar@vtaix.cc.vt.edu
+D: TeX & METAFONT hacking/maintainence
+S: Dean, Graduate School
+S: Virginia Tech
+S: Blacksburg, Virginia 24061
+S: USA
+
+N: Torsten Duwe
+E: Torsten.Duwe@informatik.uni-erlangen.de
+D: Part-time kernel hacker
+D: The Linux Support Team Erlangen
+S: Grevenbroicher Str. 17
+S: 47807 Krefeld
+S: Germany
+
+N: Drew Eckhardt
+E: drew@cs.Colorado.EDU
+D: SCSI code
+D: Assorted snippets elsewhere
+D: Boot sector "..." printing
+S: 538 West Laurell Court
+S: Louisville, Colorado 80027
+S: USA
+
+N: Bjorn Ekwall
+E: bj0rn@blox.se
+D: Driver for the D-Link parallel port Ethernet adapter
+S: Myrstuguv. 83
+S: S-143 32  VARBY
+S: Sweden
+
+N: Doug Evans
+E: dje@cygnus.com
+D: Wrote Xenix FS (part of standard kernel since 0.99.15)
+
+N: Rik Faith
+E: faith@cs.unc.edu
+D: Future Domain TMC-16x0 SCSI driver
+
+N: Juergen Fischer
+E: fischer@server.et-inf.fho-emden.de
+D: Author of Adaptec AHA-152x scsi driver
+S: Schulstrasse 18
+S: 26506 Norden
+S: Germany
+
+N: Jeremy Fitzhardinge
+E: jeremy@sw.oz.au
+D: Improved mmap and munmap handling
+D: General mm minor tidyups
+S: 99 Albermarle Street
+S: Newtown 2042
+S: Australia
+
+N: Ralf Flaxa
+E: rfflaxa@immd4.informatik.uni-erlangen.de
+D: The Linux Support Team Erlangen
+
+N: Nigel Gamble
+E: nigel%gamble.uucp@gate.net
+D: Interrupt-driven printer driver
+S: 301 Norwood Terrace, Apartment N226
+S: Boca Raton, Florida 33431-6588
+S: USA
+
+N: Philip Gladstone
+E: philipg@onsett.com
+D: Kernel / timekeeping stuff
+
+N: Bruno Haible
+E: haible@ma2s2.mathematik.uni-karlsruhe.de
+D: Unified SysV FS based on Xenix FS (part of standard kernel since 0.99.15)
+S: Augartenstrasse 40
+S: D - 76137 Karlsruhe
+S: Germany
+
+N: Andrew Haylett
+E: ajh@gec-mrc.co.uk
+D: Selection mechanism
+S: GEC-Marconi Research Centre
+S: West Hanningfield Road
+S: Great Baddow, Essex CM2 8HN
+S: UK
+
+N: Dirk Hohndel
+E: hohndel@informatik.uni-wuerzburg.de
+D: XFree86
+S: Universit"at W"urzburg, LS Informatik I
+S: Am Hubland, 97218 W"urzburg
+S: Germany
+
+N: Nick Holloway
+E: alfie@dcs.warwick.ac.uk
+D: Small patches for kernel, libc
+D: Makedev
+S: Department of Computer Science
+S: University of Warwick
+S: Coventry
+S: CV4 7AL
+S: UK
+
+N: Ron Holt
+E: ron@novell.com
+D: Kernel development
+D: Contributed to kernel Wabi/Wine support
+S: Novell, Inc.
+S: 1700 South 122 East, Mailstop CP-1
+S: Provo, Utah 84606
+S: USA
+
+N: Rob W. W. Hooft
+E: hooft@EMBL-Heidelberg.DE
+D: Shared libs for graphics-tools and for the f2c compiler
+D: Some kernel programming on the floppy and sounddrivers in early days
+D: Some other hacks to get different kinds of programs to work for linux
+S: Panoramastrasse 18
+S: D-69126 Heidelberg
+S: Germany
+
+N: Michael K. Johnson
+E: johnsonm@sunsite.unc.edu
+D: The Linux Documentation Project
+D: Kernel Hackers' Guide
+D: Procps
+D: Proc filesystem
+D: Maintain tsx-11.mit.edu
+D: LP driver
+S: 201 Howell Street, Apartment 1C
+S: Chapel Hill, North Carolina 27514-4818
+S: USA
+
+N: Fred N. van Kempen
+E: waltje@uwalt.nl.mugnet.org
+D: NET-2
+D: Drivers
+D: Kernel cleanups
+S: Hoefbladhof 27
+S: 2215 DV  Voorhout
+S: The Netherlands
+
+N: Olaf Kirch
+E: okir@monad.swb.de
+D: Author of the Linux Network Administrators' Guide
+S: Kattreinstr 38
+S: D-64295
+S: Germany
+
+N: Ian Kluft
+E: ikluft@thunder.sbay.org
+D: Smail binary packages for Slackware and Debian
+S: 2200 Monroe Street #1509
+S: Santa Clara, California 95050-3452
+S: USA
+
+N: Rudolf Koenig
+E: rfkoenig@immd4.informatik.uni-erlangen.de
+D: The Linux Support Team Erlangen
+
+N: Bas Laarhoven
+E: bas@vimec.nl
+D: Loadable modules and ftape driver
+S: Mr. v. Boemellaan 39
+S: NL-5237 KA  's-Hertogenbosch
+S: The Netherlands
+
+N: Warner Losh
+E: imp@boulder.parcplace.com
+D: Provided OI/OB for Linux, general hacker
+S: 4909 Pearl East Circle Suite 200
+S: Boulder, Colorado 80303
+S: USA
+
+N: H.J. Lu
+E: hjl@nynexst.com
+D: GCC + libraries hacker
+
+N: Tuomas J. Lukka
+E: Tuomas.Lukka@Helsinki.FI
+D: Original dual-monitor patches
+D: Console-mouse-tracking patches
+S: Puistokaari 1 E 18
+S: 00200 Helsinki
+S: Finland
+
+N: Kai M"akisara
+E: Kai.Makisara@vtt.fi
+D: SCSI Tape Driver
+
+N: James B. MacLean
+E: jmaclean@fox.nstn.ns.ca
+D: Coordinator of DOSEMU releases
+D: Program in DOSEMU
+S: PO BOX 220, HFX. CENTRAL
+S: Halifax, Nova Scotia
+S: Canada B3J 3C8
+
+N: Pat Mackinlay
+E: pat@it.com.au
+D: 8 bit XT hard disk driver
+D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
+S: 25 McMillan Street
+S: Victoria Park, 6100
+S: Western Australia
+
+N: John A. Martin
+E: jmartin@csc.com
+E: jam@acm.org
+E: j.a.martin@ieee.org
+D: FSSTND contributor
+D: Credit file compilator
+S: Computer Sciences Corporation
+S: 1100 West Street
+S: Laurel, Maryland 20707-3587
+S: USA
+
+N: Bradley McLean
+E: brad@bradpc.gaylord.com
+D: Device driver hacker
+D: General kernel debugger
+S: 249 Nichols Avenue
+S: Syracuse, New York 13206
+S: USA
+
+N: Craig Metz
+E: cmetz@tjhsst.edu
+D: Some of PAS 16 mixer & PCM support
+S: 12305 Country Ridge Lane
+S: Fairfax, Virginia 22033
+S: USA
+
+N: William (Bill) Metzenthen
+E: billm@vaxc.cc.monash.edu.au
+E: billm@jacobi.maths.monash.edu.au
+D: Author of the FPU emulator.
+D: Minor kernel hacker for other lost causes (Hercules mono, etc).
+S: 22 Parker Street
+S: Ormond
+S: Victoria 3163
+S: Australia
+
+N: Rick Miller
+E: rick@discus.mil.wi.us
+D: Linux Device Registrar (Major/minor numbers), "au-play", "bwBASIC"
+S: S78 W16203 Woods Road
+S: Muskego, Wisconsin 53150
+S: USA
+
+N: Corey Minyard
+E: minyard@wf-rch.cirr.com
+D: Sony CDU31A CDROM Driver
+S: 1805 Marquette
+S: Richardson, Texas 75081
+S: USA
+
+N: Eberhard Moenkeberg
+E: emoenke@gwdg.de
+D: CDROM driver "sbpcd" (Matsushita/Panasonic/Soundblaster)
+S: Reinholdstrasse 14
+S: D-37083 Goettingen
+S: Germany
+
+N: Ian A. Murdock
+E: imurdock@shell.portal.com
+D: Creator of Debian distribution
+S: 30 White Tail Lane
+S: Lafayette, Indiana 47906
+S: USA
+
+N: Johan Myreen
+E: jem@vipunen.hut.fi
+D: PS/2 mouse driver writer etc.
+S: Dragonvagen 1 A 13
+S: FIN-00330 Helsingfors
+S: Finland
+
+N: Stefan Probst
+E: snprobst@immd4.informatik.uni-erlangen.de
+D: The Linux Support Team Erlangen
+
+N: Daniel Quinlan
+E: quinlan@bucknell.edu
+D: FSSTND Coordinator
+S: Box C3529
+S: Bucknell University
+S: Lewisburg, Pennsylvania 17837
+S: USA
+
+N: Florian La Roche
+E: rzsfl@rz.uni-sb.de
+E: flla@stud.uni-sb.de
+D: Net programs and kernel net hacker
+S: Gaildorfer Str. 27
+S: 7000 Stuttgart 50
+S: Germany
+
+N: Robert Sanders
+E: gt8134b@prism.gatech.edu
+D: Dosemu
+
+N: Peter De Schrijver
+E: stud11@cc4.kuleuven.ac.be
+D: Mitsumi CD-ROM driver patches March version
+S: Molenbaan 29
+S: B2240 Zandhoven
+S: Belgium
+
+N: Darren Senn
+E: sinster@scintilla.santa-clara.ca.us
+D: Whatever I notice needs doing (so far: itimers, /proc)
+S: 620 Park View Drive #206
+S: Santa Clara, California 95054
+S: USA
+
+N: Chris Smith
+E: csmith@convex.com
+D: HPFS filesystem
+S: Richardson, Texas
+S: USA
+
+N: Drew Sullivan
+E: drew@lethe.north.net
+D: iBCS2 developer
+S: 22 Irvington Cres.
+S: Willowdale, Ontario
+S: Canada, M2N 2Z1
+
+N: Tommy Thorn
+E: Tommy.Thorn@daimi.aau.dk
+D: Device driver hacker (aha1542 & plip)
+S: Aarhus University
+S: Computer Science Department
+S: Ny Munkegade 116
+S: DK-8000 Aarhus C
+S: Denmark
+
+N: Jon Tombs
+E: jon@gtex02.us.es
+D: NFS mmap()
+D: XF86_S3
+D: Kernel modules
+S: C/ Teodosio 43
+S: Portal 6 1-A
+S: Sevilla 41002
+S: Spain
+
+N: Linus Torvalds
+E: Linus.Torvalds@Helsinki.FI
+D: General kernel hacker
+S: Kalevankatu 55 B 37
+S: 00180 Helsinki
+S: Finland
+
+N: Theodore Ts'o
+E: tytso@mit.edu
+D: Random Linux hacker
+D: Maintainer of tsx-11.mit.edu ftp archive
+D: Maintainer of c.o.l.* Usenet<->mail gateway
+D: Author of serial driver
+D: Author of the new e2fsck
+D: Author of job control and system call restart code
+D: Author of ramdisk device driver
+D: Author of loopback device driver
+S: MIT Room E40-343
+S: 1 Amherst Street
+S: Cambridge, Massachusetts 02139
+S: USA
+
+N: Simmule Turner
+E: simmy@digex.com
+D: Added swapping to filesystem
+S: 8504 16th Street #406
+S: Silver Spring, Maryland 20910
+S: USA
+
+N: Stephen Tweedie
+E: sct@dcs.ed.ac.uk
+D: Second extended file system developer
+D: General filesystem hacker
+S: Dept. of Computer Science
+S: University of Edinburgh
+S: JCMB, The King's Buildings
+S: Mayfield Road
+S: Edinburgh EH9 3JZ
+S: Scotland, UK
+
+N: Thomas Uhl
+E: uhl@sun1.rz.fh-heilbronn.de
+D: Application programmer
+D: Linux promoter
+D: Author of a German book on Linux
+S: Obere Heerbergstrasse 17
+S: 97078 Wuerzburg
+S: Germany
+
+N: Juergen Weigert
+E: jnweiger@immd4.informatik.uni-erlangen.de
+D: The Linux Support Team Erlangen
+
+N: Matt Welsh
+E: mdw@sunsite.unc.edu
+D: Linux Documentation Project coordinator
+D: Author, Linux Installation and Getting Started
+D: HOWTO coordinator and writer
+D: Maintainer of sunsite.unc.edu Linux doc archives
+D: Moderator, comp.os.linux.announce
+S: 205 Gray Street NE
+S: Wilson, North Caroilina 27893 
+S: USA
+
+
+N: Marco van Wieringen
+E: mvw@mercury.mcs.nl.mugnet.org
+D: Author of acct and quota
+S: Breeburgsingel 12
+S: 2135 CN Hoofddorp
+S: The Netherlands
+
+N: Stephen D. Williams
+E: sdw@lig.net
+E: sdw@meaddata.com
+D: Consultant, entrepreneur, developer
+S: 2464 Rosina Drive
+S: Dayton, Ohio 45342-6430
+S: USA
+
+N: G\"unter Windau
+E: gunter@mbfys.kun.nl
+D: Some bug fixes in the polling printer driver (lp.c)
+S: University of Nijmegen
+S: Geert-Grooteplein Noord 21
+S: 6525 EZ  Nijmegen
+S: The Netherlands
+
+N: Lars Wirzenius
+E: lars.wirzenius@helsinki.fi
+D: Linux System Administrator's Guide
+D: Co-moderator, comp.os.linux.announce
+D: Original sprintf in kernel
+D: Personal information about Linus
+D: Original kernel README
+D: Linux News (electronic magazine)
+D: Meta-FAQ, originator
+D: INFO-SHEET, former maintainer
+S: Ohratie 16 C 198
+S: sf-01370 Vantaa
+S: Finland
+
+N: Roger E. Wolff
+E: wolff@dutecai.et.tudelft.nl
+D: Written kmalloc/kfree
+S: Oosterstraat 23 
+S: 2611 TT  Delft
+S: The Netherlands
+
+N: Frank Xia
+E: qx@math.columbia.edu
+D: Xiafs filesystem
+S: 542 West 112th Street, 5N
+S: New York, New York 10025
+S: USA
+
+N: Eric Youngdale
+E: eric@tantalus.nrl.navy.mil
+D: General kernel hacker
+D: SCSI iso9660 and ELF
+S: 17 Canterbury Square #101
+S: Alexandria, Virginia 22304
+S: USA
+
+N: Orest Zborowski
+E: orestz@microsoft.com
+D: XFree86 and kernel development
+S: 1507 145th Place SE #B5
+S: Bellevue, Washington 98007
+S: USA
diff -u +recursive +new-file 0.99pl15/linux/Configure linux/Configure
--- 0.99pl15/linux/Configure	Wed Dec  1 14:44:15 1993
+++ linux/Configure	Mon Feb 21 20:38:30 1994
@@ -158,8 +158,9 @@
 	eval "$2=$ans"
 }
 
-CONFIG=.config~
+CONFIG=.tmpconfig
 CONFIG_H=include/linux/autoconf.h
+trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2
 
 #
 # Make sure we start out with a clean slate.
diff -u +recursive +new-file 0.99pl15/linux/Makefile linux/Makefile
--- 0.99pl15/linux/Makefile	Thu Feb  3 14:16:43 1994
+++ linux/Makefile	Mon Mar 14 00:38:57 1994
@@ -1,5 +1,5 @@
-VERSION = 0.99
-PATCHLEVEL = 15
+VERSION = 1
+PATCHLEVEL = 0
 ALPHA =
 
 all:	Version zImage
@@ -116,10 +116,10 @@
 
 config:
 	$(CONFIG_SHELL) Configure $(OPTS) < config.in
-	@if grep -s '^CONFIG_SOUND' .config~ ; then \
+	@if grep -s '^CONFIG_SOUND' .tmpconfig ; then \
 		$(MAKE) -C drivers/sound config; \
 		else : ; fi
-	mv .config~ .config
+	mv .tmpconfig .config
 
 linuxsubdirs: dummy
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
@@ -149,7 +149,7 @@
 	$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
 
 tools/system:	boot/head.o init/main.o tools/version.o linuxsubdirs
-	$(LD) $(LDFLAGS) -T 1000 boot/head.o init/main.o tools/version.o \
+	$(LD) $(LDFLAGS) -Ttext 1000 boot/head.o init/main.o tools/version.o \
 		$(ARCHIVES) \
 		$(FILESYSTEMS) \
 		$(DRIVERS) \
@@ -188,11 +188,13 @@
 
 zlilo: $(CONFIGURE) zImage
 	if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi
+	if [ -f /zSystem.map ]; then mv /zSystem.map /zSystem.old; fi
 	cat zImage > /vmlinuz
+	cp zSystem.map /
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 tools/zSystem:	boot/head.o init/main.o tools/version.o linuxsubdirs
-	$(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \
+	$(LD) $(LDFLAGS) -Ttext 100000 boot/head.o init/main.o tools/version.o \
 		$(ARCHIVES) \
 		$(FILESYSTEMS) \
 		$(DRIVERS) \
@@ -229,7 +231,7 @@
 	rm -f zImage zSystem.map tools/zSystem tools/system
 	rm -f Image System.map boot/bootsect boot/setup
 	rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback
-	rm -f drivers/sound/configure
+	rm -f .tmp* drivers/sound/configure
 	rm -f init/*.o tools/build boot/*.o tools/*.o
 
 mrproper: clean
@@ -246,11 +248,11 @@
 
 depend dep:
 	touch tools/version.h
-	for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~
-	for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~
+	for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .tmpdepend
+	for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .tmpdepend
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
 	rm -f tools/version.h
-	mv .depend~ .depend
+	mv .tmpdepend .depend
 
 ifdef CONFIGURATION
 ..$(CONFIGURATION):
diff -u +recursive +new-file 0.99pl15/linux/README linux/README
--- 0.99pl15/linux/README	Wed Dec 15 10:03:34 1993
+++ linux/README	Mon Mar 14 00:11:20 1994
@@ -1,30 +1,44 @@
 
-	Linux kernel release 0.99 patchlevel 14
+	Linux kernel release 1.0
 
-These are the release notes for linux version 0.99.14.  Read them
-carefully, as they tell you what's new, explain how to install the
+These are the release notes for linux version 1.0.  Read them carefully,
+as they tell you what this is all about, explain how to install the
 kernel, and what to do if something goes wrong. 
 
+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. 
+
+  It has all the features you would expect in a modern fully-fledged
+  Unix, including true multitasking, virtual memory, shared libraries,
+  demand loading, shared copy-on-write executables, proper memory
+  management and TCP/IP networking. 
+
+  It is distributed under the GNU General Public License - see the
+  accompanying COPYING file for more details. 
+
 INSTALLING the kernel:
 
- - if you install by patching, you need a *clean* 0.99.13 source tree,
+ - If you install the full sources, do a
+
+		cd /usr/src
+		tar xvf linux-1.0.tar
+
+   to get it all put in place.
+
+ - if you install by patching, you need a *clean* 0.99.15 source tree,
    which presumably exists in /usr/src/linux.  If so, to get the kernel
    patched, just do a
 
 		cd /usr/src
-		patch -p0 < linux-0.99.patch14
+		patch -p0 < linux-1.0.patch
 
    and you should be ok.  You may want to remove the backup files (xxx~
    or xxx.orig), and make sure that there are no failed patches (xxx# or
    xxx.rej).
 
- - If you install the full sources, do a
-
-		cd /usr/src
-		tar xvf linux-0.99.14.tar
-
-   to get it all put in place.
-
  - make sure your /usr/include/linux and /usr/include/asm directories
    are just symlinks to the kernel sources:
 
@@ -48,6 +62,9 @@
    /bin/sh (in that order), so hopefully one of those is correct. 
 
 	NOTES on "make config":
+	- having unnecessary drivers will make the kernel bigger, and can
+	  under some circumstances lead to problems: probing for a
+	  nonexistent controller card may confuse your other controllers
 	- compiling the kernel with "-m486" for a number of 486-specific
 	  will result in a kernel that still works on a 386: it may be
 	  slightly larger and possibly slower by an insignificant amount,
@@ -74,10 +91,10 @@
 
 COMPILING the kernel:
 
- - make sure you have gcc-2.4.5 or newer available with g++.  It seems
-   older gcc versions can have problems compiling linux 0.99.10 and
-   newer versions.  If you upgrade, remember to get the new binutils
-   package too (for as/ld/nm and company)
+ - make sure you have gcc-2.4.5 or newer available.  It seems older gcc
+   versions can have problems compiling newer versions of linux.  If you
+   upgrade your compiler, remember to get the new binutils package too
+   (for as/ld/nm and company)
 
  - do a "make zImage" to create a compressed kernel image.  If you want
    to make a bootdisk (without root filesystem or lilo), insert a floppy
@@ -94,12 +111,13 @@
    For some, this is on a floppy disk, in which case you can "cp
    /usr/src/linux/zImage /dev/fd0" to make a bootable floppy. 
 
-   If you boot Linux from the hard drive, chances are you use LILO uses
-   the kernel image as specified in the file /etc/lilo/config.  The
-   kernel image file is usually /vmlinux, or /Image, or /etc/Image.  To
-   use the new kernel, copy the new image over the old one (save a
-   backup of the original!).  Then, you MUST REINSTALL LILO!! If you
-   don't, you won't be able to boot the new kernel image. 
+   If you boot Linux from the hard drive, chances are you use LILO which
+   uses the kernel image as specified in the file /etc/lilo/config.  The
+   kernel image file is usually /vmlinuz, or /zImage, or /etc/zImage. 
+   To use the new kernel, copy the new image over the old one (save a
+   backup of the original!).  Then, you MUST RERUN LILO to update the
+   loading map!! If you don't, you won't be able to boot the new kernel
+   image. 
 
    Reinstalling LILO is usually a matter of running /etc/lilo/install. 
    You may wish to edit /etc/lilo/config to specify an entry for your
diff -u +recursive +new-file 0.99pl15/linux/config.in linux/config.in
--- 0.99pl15/linux/config.in	Thu Feb  3 13:27:36 1994
+++ linux/config.in	Sun Mar 13 02:17:37 1994
@@ -76,7 +76,7 @@
 bool 'AT1700 support' CONFIG_AT1700 n
 #bool 'Zenith Z-Note support' CONFIG_ZNET n
 #bool 'EtherExpress support' CONFIG_EEXPRESS n
-#bool 'DEPCA support' CONFIG_DEPCA n
+bool 'DEPCA support' CONFIG_DEPCA n
 #bool 'NI52** support' CONFIG_NI52 n
 #bool 'NI65** support' CONFIG_NI65 n
 #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
@@ -106,7 +106,7 @@
 *
 #bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
 #bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
-bool 'Parallel printer support' CONFIG_PRINTER y
+bool 'Parallel printer support' CONFIG_PRINTER n
 bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
 bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y
 if [ "$CONFIG_PSMOUSE" = "y" ]
@@ -114,7 +114,7 @@
 fi
 bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
 bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y
+bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
 bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n
 bool 'QIC-117 tape support' CONFIG_FTAPE n
 if [ "$CONFIG_FTAPE" = "y" ]
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/README linux/drivers/FPU-emu/README
--- 0.99pl15/linux/drivers/FPU-emu/README	Tue Jan 11 11:10:47 1994
+++ linux/drivers/FPU-emu/README	Mon Feb 14 13:10:44 1994
@@ -47,7 +47,7 @@
 
 
 --Bill Metzenthen
-  Jan 1994
+  Feb 1994
 
 
 ----------------------- Internals of wm-FPU-emu -----------------------
@@ -92,22 +92,13 @@
 ----------------------- Limitations of wm-FPU-emu -----------------------
 
 There are a number of differences between the current wm-FPU-emu
-(version beta 1.5) and the 80486 FPU (apart from bugs). Some of the
+(version beta 1.10) and the 80486 FPU (apart from bugs). Some of the
 more important differences are listed below:
 
-Segment overrides don't do anything yet.
+The Roundup flag does not have much meaning for the transcendental
+functions and its 80486 value with these functions is likely to differ
+from its emulator value.
 
-All internal computations are performed at 64 bit or higher precision
-and the results rounded etc as required by the PC bits of the FPU
-control word.  Under the crt0 version for Linux current at June 1993,
-the FPU PC bits specify 64 bits precision.
-
-The precision flag (PE of the FPU status word) and the Roundup flag
-(C1 of the status word) are now implemented. Does anyone write code
-which uses these features? The Roundup flag does not have much meaning
-for the transcendental functions and its 80486 value with these
-functions is likely to differ from its emulator value.
-
 In a few rare cases the Underflow flag obtained with the emulator will
 be different from that obtained with an 80486. This occurs when the
 following conditions apply simultaneously:
@@ -139,6 +130,19 @@
 result of any arithmetic operation. An 80486 can keep one of these
 numbers in an FPU register with its identity as a PseudoDenormal, but
 the emulator will not; they are always converted to a valid number.
+
+Self modifying code can cause the emulator to fail. An example of such
+code is:
+          movl %esp,[%ebx]
+	  fld1
+The FPU instruction may be (usually will be) loaded into the pre-fetch
+queue of the cpu before the mov instruction is executed. If the
+destination of the 'movl' overlaps the FPU instruction then the bytes
+in the prefetch queue and memory will be inconsistent when the FPU
+instruction is executed. The emulator will be invoked but will not be
+able to find the instruction which caused the device-not-present
+exception. For this case, the emulator cannot emulate the behaviour of
+an 80486DX.
 
 ----------------------- Performance of wm-FPU-emu -----------------------
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/control_w.h linux/drivers/FPU-emu/control_w.h
--- 0.99pl15/linux/drivers/FPU-emu/control_w.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/control_w.h	Wed Feb 16 13:07:55 1994
@@ -35,9 +35,10 @@
 
 /* p 15-5: Precision control bits affect only the following:
    ADD, SUB(R), MUL, DIV(R), and SQRT */
-#define PR_24_BITS      _Const_(0x000)
-#define PR_53_BITS      _Const_(0x200)
-#define PR_64_BITS      _Const_(0x300)
+#define PR_24_BITS        _Const_(0x000)
+#define PR_53_BITS        _Const_(0x200)
+#define PR_64_BITS        _Const_(0x300)
+#define PR_RESERVED_BITS  _Const_(0x100)
 /* FULL_PRECISION simulates all exceptions masked */
 #define FULL_PRECISION  (PR_64_BITS | RC_RND | 0x3f)
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/errors.c linux/drivers/FPU-emu/errors.c
--- 0.99pl15/linux/drivers/FPU-emu/errors.c	Thu Feb  3 12:11:37 1994
+++ linux/drivers/FPU-emu/errors.c	Fri Feb 25 14:42:45 1994
@@ -84,16 +84,32 @@
 
   RE_ENTRANT_CHECK_OFF;
   /* No need to verify_area(), we have previously fetched these bytes. */
-  printk("At %p: ", (void *) address);
-  while ( 1 )
+  printk("At %p:", (void *) address);
+#define MAX_PRINTED_BYTES 20
+  for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
     {
       byte1 = get_fs_byte((unsigned char *) address);
-      if ( (byte1 & 0xf8) == 0xd8 ) break;
-      printk("[%02x]", byte1);
+      if ( (byte1 & 0xf8) == 0xd8 )
+	{
+	  printk(" %02x", byte1);
+	  break;
+	}
+      printk(" [%02x]", byte1);
       address++;
     }
-  printk("%02x ", byte1);
-  FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+  if ( i == MAX_PRINTED_BYTES )
+    printk(" [more..]\n");
+  else
+    {
+      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
+
+      if (FPU_modrm >= 0300)
+	printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+      else
+	printk(" /%d, mod=%d rm=%d\n",
+	       (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+    }
+
   partial_status = status_word();
 
 #ifdef DEBUGGING
@@ -112,12 +128,6 @@
 if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
 #endif DEBUGGING
 
-  if (FPU_modrm >= 0300)
-    printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
-  else
-    printk("/%d, mod=%d rm=%d\n",
-	   (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
-
   printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
 	 partial_status & 0x8000 ? 1 : 0,   /* busy */
 	 (partial_status & 0x3800) >> 11,   /* stack top pointer */
@@ -234,8 +244,9 @@
 	      0x126  in fpu_entry.c
 	      0x127  in poly_2xm1.c
 	      0x128  in fpu_entry.c
+	      0x130  in get_address.c
        0x2nn  in an *.S file:
-              0x201  in reg_u_add.S, reg_round.S
+              0x201  in reg_u_add.S
               0x202  in reg_u_div.S
               0x203  in reg_u_div.S
               0x204  in reg_u_div.S
@@ -250,11 +261,15 @@
 	      0x213  in wm_sqrt.S
 	      0x214  in wm_sqrt.S
 	      0x215  in wm_sqrt.S
-	      0x216  in reg_round.S
-	      0x217  in reg_round.S
-	      0x218  in reg_round.S
 	      0x220  in reg_norm.S
 	      0x221  in reg_norm.S
+	      0x230  in reg_round.S
+	      0x231  in reg_round.S
+	      0x232  in reg_round.S
+	      0x233  in reg_round.S
+	      0x234  in reg_round.S
+	      0x235  in reg_round.S
+	      0x236  in reg_round.S
  */
 
 void exception(int n)
@@ -307,11 +322,11 @@
 #endif PRINT_MESSAGES
 	}
       else
-	printk("FP emulator: Unknown Exception: 0x%04x!\n", n);
+	printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
       
       if ( n == EX_INTERNAL )
 	{
-	  printk("FP emulator: Internal error type 0x%04x\n", int_type);
+	  printk("FPU emulator: Internal error type 0x%04x\n", int_type);
 	  emu_printall();
 	}
 #ifdef PRINT_MESSAGES
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_aux.c linux/drivers/FPU-emu/fpu_aux.c
--- 0.99pl15/linux/drivers/FPU-emu/fpu_aux.c	Thu Feb  3 12:11:37 1994
+++ linux/drivers/FPU-emu/fpu_aux.c	Mon Feb  7 09:35:20 1994
@@ -17,6 +17,9 @@
 #include "control_w.h"
 
 
+static void fnop(void)
+{
+}
 
 void fclex(void)
 {
@@ -47,9 +50,16 @@
   FPU_entry_eip = ip_offset = 0;
 }
 
+/*
+ * These are nops on the i387..
+ */
+#define feni fnop
+#define fdisi fnop
+#define fsetpm fnop
+
 static FUNC const finit_table[] = {
-  Un_impl, Un_impl, fclex, finit,
-  Un_impl, FPU_illegal, FPU_illegal, FPU_illegal
+  feni, fdisi, fclex, finit,
+  fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
 };
 
 void finit_()
@@ -74,11 +84,6 @@
   (fstsw_table[FPU_rm])();
 }
 
-
-
-static void fnop(void)
-{
-}
 
 static FUNC const fp_nop_table[] = {
   fnop, FPU_illegal, FPU_illegal, FPU_illegal,
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_emu.h linux/drivers/FPU-emu/fpu_emu.h
--- 0.99pl15/linux/drivers/FPU-emu/fpu_emu.h	Thu Feb  3 12:19:58 1994
+++ linux/drivers/FPU-emu/fpu_emu.h	Wed Feb 16 13:07:55 1994
@@ -81,6 +81,12 @@
 #define PREFIX_REPE 0xf3
 #define PREFIX_REPNE 0xf2
 #define PREFIX_LOCK 0xf0
+#define PREFIX_CS_ 1
+#define PREFIX_DS_ 2
+#define PREFIX_ES_ 3
+#define PREFIX_FS_ 4
+#define PREFIX_GS_ 5
+#define PREFIX_SS_ 6
 
 /* These are to defeat the default action, giving the instruction
    no net effect: */
@@ -94,7 +100,11 @@
 
 typedef void (*FUNC)(void);
 typedef struct fpu_reg FPU_REG;
-typedef struct { unsigned char address_size, segment; } overrides;
+typedef struct { unsigned char address_size, operand_size, segment; }
+        overrides;
+/* This structure is 32 bits: */
+typedef struct { overrides override;
+		 unsigned char vm86; } fpu_addr_modes;
 
 #define	st(x)	( regs[((top+x) &7 )] )
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_entry.c linux/drivers/FPU-emu/fpu_entry.c
--- 0.99pl15/linux/drivers/FPU-emu/fpu_entry.c	Thu Feb  3 12:27:17 1994
+++ linux/drivers/FPU-emu/fpu_entry.c	Mon Feb 21 20:36:51 1994
@@ -137,13 +137,15 @@
 char emulating=0;
 #endif PARANOID
 
-static int valid_prefix(unsigned char *byte, overrides *override);
+static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+			overrides *override);
 
 
 asmlinkage void math_emulate(long arg)
 {
   unsigned char  FPU_modrm, byte1;
-  overrides override;
+  unsigned short code;
+  fpu_addr_modes addr_modes;
   int unmasked;
 
 #ifdef PARANOID
@@ -170,35 +172,40 @@
 
   SETUP_DATA_AREA(arg);
 
-  FPU_ORIG_EIP = FPU_EIP;
+  addr_modes.vm86 = (FPU_EFLAGS & 0x00020000) != 0;
 
-  /* We cannot handle emulation in v86-mode */
-  if (FPU_EFLAGS & 0x00020000)
-    {
-      math_abort(FPU_info,SIGILL);
-    }
+  if ( addr_modes.vm86 )
+    FPU_EIP += FPU_CS << 4;
 
-  /* user code space? */
-  if (FPU_CS == KERNEL_CS)
-    {
-      printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
-      panic("Math emulation needed in kernel");
-    }
+  FPU_ORIG_EIP = FPU_EIP;
 
-  /* We cannot handle multiple segments yet */
-  if (FPU_CS != USER_CS || FPU_DS != USER_DS)
+  if ( !addr_modes.vm86 )
     {
-      math_abort(FPU_info,SIGILL);
+      /* user code space? */
+      if (FPU_CS == KERNEL_CS)
+	{
+	  printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
+	  panic("Math emulation needed in kernel");
+	}
+
+      /* We cannot handle multiple segments yet */
+      if (FPU_CS != USER_CS || FPU_DS != USER_DS)
+	{
+	  math_abort(FPU_info,SIGILL);
+	}
     }
 
   FPU_lookahead = 1;
   if (current->flags & PF_PTRACED)
-  	FPU_lookahead = 0;
+    FPU_lookahead = 0;
 
-  if ( !valid_prefix(&byte1, &override) )
+  if ( !valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+		     &addr_modes.override) )
     {
       RE_ENTRANT_CHECK_OFF;
-      printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1);
+      printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
+	     "FPU emulator: self-modifying code! (emulation impossible)\n",
+	     byte1);
       RE_ENTRANT_CHECK_ON;
       EXCEPTION(EX_INTERNAL|0x126);
       math_abort(FPU_info,SIGILL);
@@ -244,7 +251,7 @@
 	 but a real 80486 uses the following instructions:
 	 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
        */
-      unsigned short code = (FPU_modrm << 8) | byte1;
+      code = (FPU_modrm << 8) | byte1;
       if ( ! ( (((code & 0xf803) == 0xe003) ||    /* fnclex, fninit, fnstsw */
 		(((code & 0x3003) == 0x3001) &&   /* fnsave, fnstcw, fnstenv,
 						     fnstsw */
@@ -289,7 +296,11 @@
   if ( FPU_modrm < 0300 )
     {
       /* All of these instructions use the mod/rm byte to get a data address */
-      get_address(FPU_modrm, override);
+      if ( addr_modes.vm86
+	  ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
+	get_address_16(FPU_modrm, &FPU_EIP, addr_modes);
+      else
+	get_address(FPU_modrm, &FPU_EIP, addr_modes);
       if ( !(byte1 & 1) )
 	{
 	  unsigned short status1 = partial_status;
@@ -303,16 +314,16 @@
 	      switch ( (byte1 >> 1) & 3 )
 		{
 		case 0:
-		  unmasked = reg_load_single(override);
+		  unmasked = reg_load_single();
 		  break;
 		case 1:
-		  reg_load_int32(override);
+		  reg_load_int32();
 		  break;
 		case 2:
-		  unmasked = reg_load_double(override);
+		  unmasked = reg_load_double();
 		  break;
 		case 3:
-		  reg_load_int16(override);
+		  reg_load_int16();
 		  break;
 		}
 	      
@@ -440,7 +451,8 @@
 	}
       else
 	{
-	  load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override);
+	  load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
+			   addr_modes);
 	}
 
     reg_mem_instr_done:
@@ -527,10 +539,14 @@
   if (FPU_lookahead && !need_resched)
     {
       FPU_ORIG_EIP = FPU_EIP;
-      if ( valid_prefix(&byte1, &override) )
+      if ( valid_prefix(&byte1, (unsigned char **)&FPU_EIP,
+			&addr_modes.override) )
 	goto do_another_FPU_instruction;
     }
 
+  if ( addr_modes.vm86 )
+    FPU_EIP -= FPU_CS << 4;
+
   RE_ENTRANT_CHECK_OFF;
 }
 
@@ -539,16 +555,17 @@
    all prefix bytes, further changes are needed in the emulator code
    which accesses user address space. Access to separate segments is
    important for msdos emulation. */
-static int valid_prefix(unsigned char *Byte, overrides *override)
+static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
+			overrides *override)
 {
   unsigned char byte;
-  unsigned long ip = FPU_EIP;
+  unsigned char *ip = *fpu_eip;
 
-  *override = (overrides) { 0, PREFIX_DS };       /* defaults */
+  *override = (overrides) { 0, 0, PREFIX_DS_ };       /* defaults */
 
   RE_ENTRANT_CHECK_OFF;
   FPU_code_verify_area(1);
-  byte = get_fs_byte((unsigned char *) FPU_EIP);
+  byte = get_fs_byte(ip);
   RE_ENTRANT_CHECK_ON;
 
   while ( 1 )
@@ -558,35 +575,43 @@
 	case ADDR_SIZE_PREFIX:
 	  override->address_size = ADDR_SIZE_PREFIX;
 	  goto do_next_byte;
+
+	case OP_SIZE_PREFIX:
+	  override->operand_size = OP_SIZE_PREFIX;
+	  goto do_next_byte;
+
 	case PREFIX_CS:
-	  override->segment = PREFIX_CS;
+	  override->segment = PREFIX_CS_;
 	  goto do_next_byte;
 	case PREFIX_ES:
-	  override->segment = PREFIX_ES;
+	  override->segment = PREFIX_ES_;
 	  goto do_next_byte;
 	case PREFIX_SS:
-	  override->segment = PREFIX_SS;
+	  override->segment = PREFIX_SS_;
 	  goto do_next_byte;
 	case PREFIX_FS:
-	  override->segment = PREFIX_FS;
+	  override->segment = PREFIX_FS_;
 	  goto do_next_byte;
 	case PREFIX_GS:
-	  override->segment = PREFIX_GS;
+	  override->segment = PREFIX_GS_;
 	  goto do_next_byte;
 
 	case PREFIX_DS:   /* Redundant unless preceded by another override. */
-	  override->segment = PREFIX_DS;
+	  override->segment = PREFIX_DS_;
 
+/* lock is not a valid prefix for FPU instructions,
+   let the cpu handle it to generate a SIGILL. */
+/*	case PREFIX_LOCK: */
+
 	  /* rep.. prefixes have no meaning for FPU instructions */
-	case PREFIX_LOCK:
 	case PREFIX_REPE:
 	case PREFIX_REPNE:
-	case OP_SIZE_PREFIX:  /* Used often by gcc, but has no effect. */
+
 	do_next_byte:
-	  FPU_EIP++;
+	  ip++;
 	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(1);
-	  byte = get_fs_byte((unsigned char *) (FPU_EIP));
+	  byte = get_fs_byte(ip);
 	  RE_ENTRANT_CHECK_ON;
 	  break;
 	case FWAIT_OPCODE:
@@ -596,11 +621,14 @@
 	  if ( (byte & 0xf8) == 0xd8 )
 	    {
 	      *Byte = byte;
+	      *fpu_eip = ip;
 	      return 1;
 	    }
 	  else
 	    {
-	      FPU_EIP = ip;
+	      /* Not a valid sequence of prefix bytes followed by
+		 an FPU instruction. */
+	      *Byte = byte;  /* Needed for error message. */
 	      return 0;
 	    }
 	}
@@ -608,7 +636,7 @@
 }
 
 
-void __math_abort(struct info * info, unsigned int signal)
+void math_abort(struct info * info, unsigned int signal)
 {
 	FPU_EIP = FPU_ORIG_EIP;
 	current->tss.trap_no = 16;
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_proto.h linux/drivers/FPU-emu/fpu_proto.h
--- 0.99pl15/linux/drivers/FPU-emu/fpu_proto.h	Thu Feb  3 12:11:38 1994
+++ linux/drivers/FPU-emu/fpu_proto.h	Wed Feb 16 13:07:56 1994
@@ -52,7 +52,7 @@
 
 /* fpu_entry.c */
 asmlinkage void math_emulate(long arg);
-extern void __math_abort(struct info *info, unsigned int signal);
+extern void math_abort(struct info *info, unsigned int signal);
 
 /* fpu_etc.c */
 extern void fp_etc(void);
@@ -63,10 +63,13 @@
 extern void trig_b(void);
 
 /* get_address.c */
-extern void get_address(unsigned char FPU_modrm, overrides override);
+extern void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+			fpu_addr_modes);
+extern void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+			   fpu_addr_modes);
 
 /* load_store.c */
-extern void load_store_instr(char type, overrides override);
+extern void load_store_instr(char type, fpu_addr_modes addr_modes);
 
 /* poly_2xm1.c */
 extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result);
@@ -105,26 +108,26 @@
 extern void fconst(void);
 
 /* reg_ld_str.c */
-extern int reg_load_extended(overrides override);
-extern int reg_load_double(overrides override);
-extern int reg_load_single(overrides override);
-extern void reg_load_int64(overrides override);
-extern void reg_load_int32(overrides override);
-extern void reg_load_int16(overrides override);
-extern void reg_load_bcd(overrides override);
-extern int reg_store_extended(overrides override);
-extern int reg_store_double(overrides override);
-extern int reg_store_single(overrides override);
-extern int reg_store_int64(overrides override);
-extern int reg_store_int32(overrides override);
-extern int reg_store_int16(overrides override);
-extern int reg_store_bcd(overrides override);
+extern int reg_load_extended(void);
+extern int reg_load_double(void);
+extern int reg_load_single(void);
+extern void reg_load_int64(void);
+extern void reg_load_int32(void);
+extern void reg_load_int16(void);
+extern void reg_load_bcd(void);
+extern int reg_store_extended(void);
+extern int reg_store_double(void);
+extern int reg_store_single(void);
+extern int reg_store_int64(void);
+extern int reg_store_int32(void);
+extern int reg_store_int16(void);
+extern int reg_store_bcd(void);
 extern int round_to_int(FPU_REG *r);
-extern char *fldenv(void);
-extern void frstor(void);
+extern char *fldenv(fpu_addr_modes addr_modes);
+extern void frstor(fpu_addr_modes addr_modes);
 extern unsigned short tag_word(void);
-extern char *fstenv(void);
-extern void fsave(void);
+extern char *fstenv(fpu_addr_modes addr_modes);
+extern void fsave(fpu_addr_modes addr_modes);
 
 /* reg_mul.c */
 extern int reg_mul(FPU_REG const *a, FPU_REG const *b,
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/fpu_system.h linux/drivers/FPU-emu/fpu_system.h
--- 0.99pl15/linux/drivers/FPU-emu/fpu_system.h	Tue Jan 25 11:03:59 1994
+++ linux/drivers/FPU-emu/fpu_system.h	Wed Feb 16 13:07:56 1994
@@ -23,6 +23,7 @@
 #define FPU_info		(I387.soft.info)
 
 #define FPU_CS			(*(unsigned short *) &(FPU_info->___cs))
+#define FPU_SS			(*(unsigned short *) &(FPU_info->___ss))
 #define FPU_DS			(*(unsigned short *) &(FPU_info->___ds))
 #define FPU_EAX			(FPU_info->___eax)
 #define FPU_EFLAGS		(FPU_info->___eflags)
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/get_address.c linux/drivers/FPU-emu/get_address.c
--- 0.99pl15/linux/drivers/FPU-emu/get_address.c	Thu Feb  3 12:11:39 1994
+++ linux/drivers/FPU-emu/get_address.c	Wed Feb 16 13:07:56 1994
@@ -39,9 +39,21 @@
 
 #define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info))
 
+static int reg_offset_vm86[] = {
+	offsetof(struct info,___cs),
+	offsetof(struct info,___vm86_ds),
+	offsetof(struct info,___vm86_es),
+	offsetof(struct info,___vm86_fs),
+	offsetof(struct info,___vm86_gs),
+	offsetof(struct info,___ss)
+      };
 
+#define VM86_REG_(x) (*(unsigned short *) \
+		      (reg_offset_vm86[((unsigned)x)]+(char *) FPU_info))
+
+
 /* Decode the SIB byte. This function assumes mod != 0 */
-static void *sib(int mod)
+static void *sib(int mod, unsigned long *fpu_eip)
 {
   unsigned char ss,index,base;
   long offset;
@@ -48,9 +60,9 @@
 
   RE_ENTRANT_CHECK_OFF;
   FPU_code_verify_area(1);
-  base = get_fs_byte((char *) FPU_EIP);   /* The SIB byte */
+  base = get_fs_byte((char *) (*fpu_eip));   /* The SIB byte */
   RE_ENTRANT_CHECK_ON;
-  FPU_EIP++;
+  (*fpu_eip)++;
   ss = base >> 6;
   index = (base >> 3) & 7;
   base &= 7;
@@ -77,9 +89,9 @@
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      offset += (signed char) get_fs_byte((char *) FPU_EIP);
+      offset += (signed char) get_fs_byte((char *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
-      FPU_EIP++;
+      (*fpu_eip)++;
     }
   else if (mod == 2 || base == 5) /* The second condition also has mod==0 */
     {
@@ -86,9 +98,9 @@
       /* 32 bit displacment */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(4);
-      offset += (signed) get_fs_long((unsigned long *) FPU_EIP);
+      offset += (signed) get_fs_long((unsigned long *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
-      FPU_EIP += 4;
+      (*fpu_eip) += 4;
     }
 
   return (void *) offset;
@@ -95,6 +107,20 @@
 }
 
 
+static unsigned long vm86_segment(unsigned char segment)
+{ 
+  segment--;
+#ifdef PARANOID
+  if ( segment > PREFIX_SS_ )
+    {
+      EXCEPTION(EX_INTERNAL|0x130);
+      math_abort(FPU_info,SIGSEGV);
+    }
+#endif PARANOID
+  return (unsigned long)VM86_REG_(segment) << 4;
+}
+
+
 /*
        MOD R/M byte:  MOD == 3 has a special use for the FPU
                       SIB byte used iff R/M = 100b
@@ -112,7 +138,8 @@
 
 */
 
-void get_address(unsigned char FPU_modrm, overrides override)
+void get_address(unsigned char FPU_modrm, unsigned long *fpu_eip,
+		 fpu_addr_modes addr_modes)
 {
   unsigned char mod;
   long *cpu_reg_ptr;
@@ -123,11 +150,20 @@
   FPU_data_selector = FPU_DS;
 #endif PECULIAR_486
 
+  /* Memory accessed via the cs selector is write protected
+     in 32 bit protected mode. */
+#define FPU_WRITE_BIT 0x10
+  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+      && (addr_modes.override.segment == PREFIX_CS_) )
+    {
+      math_abort(FPU_info,SIGSEGV);
+    }
+
   mod = (FPU_modrm >> 6) & 3;
 
   if (FPU_rm == 4 && mod != 3)
     {
-      FPU_data_address = sib(mod);
+      FPU_data_address = sib(mod, fpu_eip);
       return;
     }
 
@@ -137,20 +173,11 @@
     case 0:
       if (FPU_rm == 5)
 	{
-	  /* Special case: disp16 or disp32 */
+	  /* Special case: disp32 */
 	  RE_ENTRANT_CHECK_OFF;
-	  if ( override.address_size == ADDR_SIZE_PREFIX )
-	    {
-	      FPU_code_verify_area(2);
-	      offset = get_fs_word((unsigned short *) FPU_EIP);
-	      FPU_EIP += 2;
-	    }
-	  else
-	    {
-	      FPU_code_verify_area(4);
-	      offset = get_fs_long((unsigned long *) FPU_EIP);
-	      FPU_EIP += 4;
-	    }
+	  FPU_code_verify_area(4);
+	  offset = get_fs_long((unsigned long *) (*fpu_eip));
+	  (*fpu_eip) += 4;
 	  RE_ENTRANT_CHECK_ON;
 	  FPU_data_address = (void *) offset;
 	  return;
@@ -165,33 +192,125 @@
       /* 8 bit signed displacement */
       RE_ENTRANT_CHECK_OFF;
       FPU_code_verify_area(1);
-      offset = (signed char) get_fs_byte((char *) FPU_EIP);
+      offset = (signed char) get_fs_byte((char *) (*fpu_eip));
       RE_ENTRANT_CHECK_ON;
-      FPU_EIP++;
+      (*fpu_eip)++;
       break;
     case 2:
-      /* 16 or 32 bit displacement */
+      /* 32 bit displacement */
       RE_ENTRANT_CHECK_OFF;
-      if ( override.address_size == ADDR_SIZE_PREFIX )
+      FPU_code_verify_area(4);
+      offset = (signed) get_fs_long((unsigned long *) (*fpu_eip));
+      (*fpu_eip) += 4;
+      RE_ENTRANT_CHECK_ON;
+      break;
+    case 3:
+      /* Not legal for the FPU */
+      EXCEPTION(EX_Invalid);
+    }
+
+  if ( addr_modes.vm86 )
+    {
+      offset += vm86_segment(addr_modes.override.segment);
+    }
+
+  FPU_data_address = offset + (char *)*cpu_reg_ptr;
+}
+
+
+void get_address_16(unsigned char FPU_modrm, unsigned long *fpu_eip,
+		      fpu_addr_modes addr_modes)
+{
+  unsigned char mod;
+  int offset = 0;     /* Default used for mod == 0 */
+
+#ifndef PECULIAR_486
+  /* This is a reasonable place to do this */
+  FPU_data_selector = FPU_DS;
+#endif PECULIAR_486
+
+  /* Memory accessed via the cs selector is write protected
+     in 32 bit protected mode. */
+#define FPU_WRITE_BIT 0x10
+  if ( !addr_modes.vm86 && (FPU_modrm & FPU_WRITE_BIT)
+      && (addr_modes.override.segment == PREFIX_CS_) )
+    {
+      math_abort(FPU_info,SIGSEGV);
+    }
+
+  mod = (FPU_modrm >> 6) & 3;
+
+  switch (mod)
+    {
+    case 0:
+      if (FPU_rm == 6)
 	{
+	  /* Special case: disp16 */
+	  RE_ENTRANT_CHECK_OFF;
 	  FPU_code_verify_area(2);
-	  offset = (signed) get_fs_word((unsigned short *) FPU_EIP);
-	  FPU_EIP += 2;
-	}
-      else
-	{
-	  FPU_code_verify_area(4);
-	  offset = (signed) get_fs_long((unsigned long *) FPU_EIP);
-	  FPU_EIP += 4;
+	  offset = (unsigned short)get_fs_word((unsigned short *) (*fpu_eip));
+	  (*fpu_eip) += 2;
+	  RE_ENTRANT_CHECK_ON;
+	  goto add_segment;
 	}
+      break;
+    case 1:
+      /* 8 bit signed displacement */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_code_verify_area(1);
+      offset = (signed char) get_fs_byte((signed char *) (*fpu_eip));
+      RE_ENTRANT_CHECK_ON;
+      (*fpu_eip)++;
+      break;
+    case 2:
+      /* 16 bit displacement */
+      RE_ENTRANT_CHECK_OFF;
+      FPU_code_verify_area(2);
+      offset = (unsigned) get_fs_word((unsigned short *) (*fpu_eip));
+      (*fpu_eip) += 2;
       RE_ENTRANT_CHECK_ON;
       break;
     case 3:
       /* Not legal for the FPU */
       EXCEPTION(EX_Invalid);
+      break;
+    }
+  switch ( FPU_rm )
+    {
+    case 0:
+      offset += FPU_info->___ebx + FPU_info->___esi;
+      break;
+    case 1:
+      offset += FPU_info->___ebx + FPU_info->___edi;
+      break;
+    case 2:
+      offset += FPU_info->___ebp + FPU_info->___esi;
+      break;
+    case 3:
+      offset += FPU_info->___ebp + FPU_info->___edi;
+      break;
+    case 4:
+      offset += FPU_info->___esi;
+      break;
+    case 5:
+      offset += FPU_info->___edi;
+      break;
+    case 6:
+      offset += FPU_info->___ebp;
+      break;
+    case 7:
+      offset += FPU_info->___ebx;
+      break;
     }
 
-  FPU_data_address = offset + (char *)*cpu_reg_ptr;
-  if ( override.address_size == ADDR_SIZE_PREFIX )
-    FPU_data_address = (void *)((long)FPU_data_address & 0xffff);
+ add_segment:
+  offset &= 0xffff;
+
+  if ( addr_modes.vm86 )
+    {
+      offset += vm86_segment(addr_modes.override.segment);
+    }
+
+  FPU_data_address = (void *)offset ;
 }
+
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/load_store.c linux/drivers/FPU-emu/load_store.c
--- 0.99pl15/linux/drivers/FPU-emu/load_store.c	Thu Feb  3 12:11:39 1994
+++ linux/drivers/FPU-emu/load_store.c	Mon Feb 14 13:10:46 1994
@@ -46,7 +46,7 @@
   _NONE_, _REG0_, _NONE_, _REG0_
   };
 
-void load_store_instr(char type, overrides override)
+void load_store_instr(char type, fpu_addr_modes addr_modes)
 {
   FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't
 			change if the emulator is re-entered. */
@@ -85,7 +85,7 @@
   {
   case 000:       /* fld m32real */
     clear_C1();
-    reg_load_single(override);
+    reg_load_single();
     if ( (FPU_loaded_data.tag == TW_NaN) &&
 	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
       {
@@ -96,12 +96,12 @@
     break;
   case 001:      /* fild m32int */
     clear_C1();
-    reg_load_int32(override);
+    reg_load_int32();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 002:      /* fld m64real */
     clear_C1();
-    reg_load_double(override);
+    reg_load_double();
     if ( (FPU_loaded_data.tag == TW_NaN) &&
 	real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) )
       {
@@ -112,58 +112,58 @@
     break;
   case 003:      /* fild m16int */
     clear_C1();
-    reg_load_int16(override);
+    reg_load_int16();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 010:      /* fst m32real */
     clear_C1();
-    reg_store_single(override);
+    reg_store_single();
     break;
   case 011:      /* fist m32int */
     clear_C1();
-    reg_store_int32(override);
+    reg_store_int32();
     break;
   case 012:     /* fst m64real */
     clear_C1();
-    reg_store_double(override);
+    reg_store_double();
     break;
   case 013:     /* fist m16int */
     clear_C1();
-    reg_store_int16(override);
+    reg_store_int16();
     break;
   case 014:     /* fstp m32real */
     clear_C1();
-    if ( reg_store_single(override) )
+    if ( reg_store_single() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 015:     /* fistp m32int */
     clear_C1();
-    if ( reg_store_int32(override) )
+    if ( reg_store_int32() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 016:     /* fstp m64real */
     clear_C1();
-    if ( reg_store_double(override) )
+    if ( reg_store_double() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 017:     /* fistp m16int */
     clear_C1();
-    if ( reg_store_int16(override) )
+    if ( reg_store_int16() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
   case 020:     /* fldenv  m14/28byte */
-    fldenv();
+    fldenv(addr_modes);
     break;
   case 022:     /* frstor m94/108byte */
-    frstor();
+    frstor(addr_modes);
     break;
   case 023:     /* fbld m80dec */
     clear_C1();
-    reg_load_bcd(override);
+    reg_load_bcd();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 024:     /* fldcw */
@@ -183,25 +183,25 @@
     break;
   case 025:      /* fld m80real */
     clear_C1();
-    reg_load_extended(override);
+    reg_load_extended();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 027:      /* fild m64int */
     clear_C1();
-    reg_load_int64(override);
+    reg_load_int64();
     reg_move(&FPU_loaded_data, pop_ptr);
     break;
   case 030:     /* fstenv  m14/28byte */
-    fstenv();
+    fstenv(addr_modes);
     NO_NET_DATA_EFFECT;
     break;
   case 032:      /* fsave */
-    fsave();
+    fsave(addr_modes);
     NO_NET_DATA_EFFECT;
     break;
   case 033:      /* fbstp m80dec */
     clear_C1();
-    if ( reg_store_bcd(override) )
+    if ( reg_store_bcd() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
@@ -215,7 +215,7 @@
     break;
   case 035:      /* fstp m80real */
     clear_C1();
-    if ( reg_store_extended(override) )
+    if ( reg_store_extended() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
@@ -229,7 +229,7 @@
     break;
   case 037:      /* fistp m64int */
     clear_C1();
-    if ( reg_store_int64(override) )
+    if ( reg_store_int64() )
       pop_0();  /* pop only if the number was actually stored
 		 (see the 80486 manual p16-28) */
     break;
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_ld_str.c linux/drivers/FPU-emu/reg_ld_str.c
--- 0.99pl15/linux/drivers/FPU-emu/reg_ld_str.c	Thu Feb  3 12:11:41 1994
+++ linux/drivers/FPU-emu/reg_ld_str.c	Wed Feb 16 13:07:56 1994
@@ -44,7 +44,7 @@
 
 
 /* Get a long double from user memory */
-int reg_load_extended(overrides override)
+int reg_load_extended(void)
 {
   long double *s = (long double *)FPU_data_address;
   unsigned long sigl, sigh, exp;
@@ -145,7 +145,7 @@
 
 
 /* Get a double from user memory */
-int reg_load_double(overrides override)
+int reg_load_double(void)
 {
   double *dfloat = (double *)FPU_data_address;
   int exp;
@@ -223,7 +223,7 @@
 
 
 /* Get a float from user memory */
-int reg_load_single(overrides override)
+int reg_load_single(void)
 {
   float *single = (float *)FPU_data_address;
   unsigned m32;
@@ -292,7 +292,7 @@
 
 
 /* Get a long long from user memory */
-void reg_load_int64(overrides override)
+void reg_load_int64(void)
 {
   long long *_s = (long long *)FPU_data_address;
   int e;
@@ -324,7 +324,7 @@
 
 
 /* Get a long from user memory */
-void reg_load_int32(overrides override)
+void reg_load_int32(void)
 {
   long *_s = (long *)FPU_data_address;
   long s;
@@ -356,7 +356,7 @@
 
 
 /* Get a short from user memory */
-void reg_load_int16(overrides override)
+void reg_load_int16(void)
 {
   short *_s = (short *)FPU_data_address;
   int s, e;
@@ -389,7 +389,7 @@
 
 
 /* Get a packed bcd array from user memory */
-void reg_load_bcd(overrides override)
+void reg_load_bcd(void)
 {
   char *s = (char *)FPU_data_address;
   int pos;
@@ -436,7 +436,7 @@
 /*===========================================================================*/
 
 /* Put a long double into user memory */
-int reg_store_extended(overrides override)
+int reg_store_extended(void)
 {
   /*
     The only exception raised by an attempt to store to an
@@ -475,7 +475,7 @@
 
 
 /* Put a double into user memory */
-int reg_store_double(overrides override)
+int reg_store_double(void)
 {
   double *dfloat = (double *)FPU_data_address;
   unsigned long l[2];
@@ -670,7 +670,7 @@
 
 
 /* Put a float into user memory */
-int reg_store_single(overrides override)
+int reg_store_single(void)
 {
   float *single = (float *)FPU_data_address;
   long templ;
@@ -859,7 +859,7 @@
 
 
 /* Put a long long into user memory */
-int reg_store_int64(overrides override)
+int reg_store_int64(void)
 {
   long long *d = (long long *)FPU_data_address;
   FPU_REG t;
@@ -918,7 +918,7 @@
 
 
 /* Put a long into user memory */
-int reg_store_int32(overrides override)
+int reg_store_int32(void)
 {
   long *d = (long *)FPU_data_address;
   FPU_REG t;
@@ -972,7 +972,7 @@
 
 
 /* Put a short into user memory */
-int reg_store_int16(overrides override)
+int reg_store_int16(void)
 {
   short *d = (short *)FPU_data_address;
   FPU_REG t;
@@ -1026,7 +1026,7 @@
 
 
 /* Put a packed bcd array into user memory */
-int reg_store_bcd(overrides override)
+int reg_store_bcd(void)
 {
   char *d = (char *)FPU_data_address;
   FPU_REG t;
@@ -1163,7 +1163,7 @@
 
 /*===========================================================================*/
 
-char *fldenv(void)
+char *fldenv(fpu_addr_modes addr_modes)
 {
   char *s = (char *)FPU_data_address;
   unsigned short tag_word = 0;
@@ -1170,17 +1170,45 @@
   unsigned char tag;
   int i;
 
-  RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_READ, s, 0x1c);
-  control_word = get_fs_word((unsigned short *) s);
-  partial_status = get_fs_word((unsigned short *) (s+4));
-  tag_word = get_fs_word((unsigned short *) (s+8));
-  ip_offset = get_fs_long((unsigned long *) (s+0x0c));
-  cs_selector = get_fs_long((unsigned long *) (s+0x10));
-  data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
-  operand_selector = get_fs_long((unsigned long *) (s+0x18));
-  RE_ENTRANT_CHECK_ON;
+  if ( addr_modes.vm86
+      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+    {
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_READ, s, 0x0e);
+      control_word = get_fs_word((unsigned short *) s);
+      partial_status = get_fs_word((unsigned short *) (s+2));
+      tag_word = get_fs_word((unsigned short *) (s+4));
+      ip_offset = get_fs_word((unsigned short *) (s+6));
+      cs_selector = get_fs_word((unsigned short *) (s+8));
+      data_operand_offset = get_fs_word((unsigned short *) (s+0x0a));
+      operand_selector = get_fs_word((unsigned short *) (s+0x0c));
+      RE_ENTRANT_CHECK_ON;
+      s += 0x0e;
+      if ( addr_modes.vm86 )
+	{
+	  ip_offset += (cs_selector & 0xf000) << 4;
+	  data_operand_offset += (operand_selector & 0xf000) << 4;
+	}
+    }
+  else
+    {
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_READ, s, 0x1c);
+      control_word = get_fs_word((unsigned short *) s);
+      partial_status = get_fs_word((unsigned short *) (s+4));
+      tag_word = get_fs_word((unsigned short *) (s+8));
+      ip_offset = get_fs_long((unsigned long *) (s+0x0c));
+      cs_selector = get_fs_long((unsigned long *) (s+0x10));
+      data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
+      operand_selector = get_fs_long((unsigned long *) (s+0x18));
+      RE_ENTRANT_CHECK_ON;
+      s += 0x1c;
+    }
 
+#ifdef PECULIAR_486
+  control_word &= ~0xe080;
+#endif PECULIAR_486
+
   top = (partial_status >> SW_Top_Shift) & 7;
 
   if ( partial_status & ~control_word & CW_Exceptions )
@@ -1226,21 +1254,21 @@
   NO_NET_DATA_EFFECT;
   NO_NET_INSTR_EFFECT;
 
-  return s + 0x1c;
+  return s;
 }
 
 
-void frstor(void)
+void frstor(fpu_addr_modes addr_modes)
 {
   int i, stnr;
   unsigned char tag;
-  char *s = fldenv();
+  char *s = fldenv(addr_modes);
 
   for ( i = 0; i < 8; i++ )
     {
       /* Load each register. */
       FPU_data_address = (void *)(s+i*10);
-      reg_load_extended((overrides){0,0});
+      reg_load_extended();
       stnr = (i+top) & 7;
       tag = regs[stnr].tag;   /* Derived from the loaded tag word. */
       reg_move(&FPU_loaded_data, &regs[stnr]);
@@ -1285,46 +1313,79 @@
 }
 
 
-char *fstenv(void)
+char *fstenv(fpu_addr_modes addr_modes)
 {
   char *d = (char *)FPU_data_address;
 
-  RE_ENTRANT_CHECK_OFF;
-  FPU_verify_area(VERIFY_WRITE,d,28);
+  if ( addr_modes.vm86
+      || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
+    {
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,d,14);
+#ifdef PECULIAR_486
+      put_fs_long(control_word & ~0xe080, (unsigned short *) d);
+#else
+      put_fs_word(control_word, (unsigned short *) d);
+#endif PECULIAR_486
+      put_fs_word(status_word(), (unsigned short *) (d+2));
+      put_fs_word(tag_word(), (unsigned short *) (d+4));
+      put_fs_word(ip_offset, (unsigned short *) (d+6));
+      put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a));
+      if ( addr_modes.vm86 )
+	{
+	  put_fs_word((ip_offset & 0xf0000) >> 4,
+		      (unsigned short *) (d+8));
+	  put_fs_word((data_operand_offset & 0xf0000) >> 4,
+		      (unsigned short *) (d+0x0c));
+	}
+      else
+	{
+	  put_fs_word(cs_selector, (unsigned short *) (d+8));
+	  put_fs_word(operand_selector, (unsigned short *) (d+0x0c));
+	}
+      RE_ENTRANT_CHECK_ON;
+      d += 0x0e;
+    }
+  else
+    {
+      RE_ENTRANT_CHECK_OFF;
+      FPU_verify_area(VERIFY_WRITE,d,28);
 #ifdef PECULIAR_486
-  /* An 80486 sets all the reserved bits to 1. */
-  put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
-  put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
-  put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
+      /* An 80486 sets all the reserved bits to 1. */
+      put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
+      put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
+      put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
 #else
-  put_fs_word(control_word, (unsigned short *) d);
-  put_fs_word(status_word(), (unsigned short *) (d+4));
-  put_fs_word(tag_word(), (unsigned short *) (d+8));
+      put_fs_word(control_word, (unsigned short *) d);
+      put_fs_word(status_word(), (unsigned short *) (d+4));
+      put_fs_word(tag_word(), (unsigned short *) (d+8));
 #endif PECULIAR_486
-  put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
-  put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
-  put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
+      put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
+      put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
+      put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
 #ifdef PECULIAR_486
-  /* An 80486 sets all the reserved bits to 1. */
-  put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
+      /* An 80486 sets all the reserved bits to 1. */
+      put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
 #else
-  put_fs_long(operand_selector, (unsigned long *) (d+0x18));
+      put_fs_long(operand_selector, (unsigned long *) (d+0x18));
 #endif PECULIAR_486
-  RE_ENTRANT_CHECK_ON;
+      RE_ENTRANT_CHECK_ON;
+      d += 0x1c;
+    }
   
   control_word |= CW_Exceptions;
   partial_status &= ~(SW_Summary | SW_Backward);
 
-  return d + 0x1c;
+  return d;
 }
 
 
-void fsave(void)
+void fsave(fpu_addr_modes addr_modes)
 {
   char *d;
   int i;
 
-  d = fstenv();
+  d = fstenv(addr_modes);
   RE_ENTRANT_CHECK_OFF;
   FPU_verify_area(VERIFY_WRITE,d,80);
   RE_ENTRANT_CHECK_ON;
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_mul.c linux/drivers/FPU-emu/reg_mul.c
--- 0.99pl15/linux/drivers/FPU-emu/reg_mul.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/reg_mul.c	Fri Feb 25 14:42:46 1994
@@ -51,11 +51,10 @@
 	 one valid and the other zero.
 	 The result is therefore zero. */
       reg_move(&CONST_Z, dest);
-#ifdef PECULIAR_486
       /* The 80486 book says that the answer is +0, but a real
-	 80486 appears to behave this way... */
+	 80486 behaves this way.
+	 IEEE-754 apparently says it should be this way. */
       dest->sign = sign;
-#endif PECULIAR_486
       return 0;
     }
   else
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/reg_round.S linux/drivers/FPU-emu/reg_round.S
--- 0.99pl15/linux/drivers/FPU-emu/reg_round.S	Wed Dec  1 14:44:16 1993
+++ linux/drivers/FPU-emu/reg_round.S	Wed Feb 16 13:07:57 1994
@@ -156,9 +156,19 @@
 	cmpl	PR_24_BITS,%ecx
 	je	LRound_To_24
 
+#ifdef PECULIAR_486
+/* With the precision control bits set to 01 "(reserved)", a real 80486
+   behaves as if the precision control bits were set to 11 "64 bits" */
+	cmpl	PR_RESERVED_BITS,%ecx
+	je	LRound_To_64
+#ifdef PARANOID
+	jmp	L_bugged_denorm_486
+#endif PARANOID
+#else
 #ifdef PARANOID
-	jmp	L_bugged	/* There is no bug, just a bad control word */
+	jmp	L_bugged_denorm	/* There is no bug, just a bad control word */
 #endif PARANOID
+#endif PECULIAR_486
 
 
 /* Round etc to 24 bit precision */
@@ -178,7 +188,7 @@
 	je	LDown_24
 
 #ifdef PARANOID
-	jmp	L_bugged
+	jmp	L_bugged_round24
 #endif PARANOID
 
 LUp_24:
@@ -258,7 +268,7 @@
 	je	LDown_53
 
 #ifdef PARANOID
-	jmp	L_bugged
+	jmp	L_bugged_round53
 #endif PARANOID
 
 LUp_53:
@@ -332,7 +342,7 @@
 	je	LDown_64
 
 #ifdef PARANOID
-	jmp	L_bugged
+	jmp	L_bugged_round64
 #endif PARANOID
 
 LUp_64:
@@ -643,21 +653,46 @@
 
 
 #ifdef PARANOID
-/* If we ever get here then we have problems! */
-L_bugged:
-	pushl	EX_INTERNAL|0x201
+#ifdef PECULIAR_486
+L_bugged_denorm_486:
+	pushl	EX_INTERNAL|0x236
+	call	EXCEPTION
+	popl	%ebx
+	jmp	L_exception_exit
+#else
+L_bugged_denorm:
+	pushl	EX_INTERNAL|0x230
+	call	EXCEPTION
+	popl	%ebx
+	jmp	L_exception_exit
+#endif PECULIAR_486
+
+L_bugged_round24:
+	pushl	EX_INTERNAL|0x231
+	call	EXCEPTION
+	popl	%ebx
+	jmp	L_exception_exit
+
+L_bugged_round53:
+	pushl	EX_INTERNAL|0x232
+	call	EXCEPTION
+	popl	%ebx
+	jmp	L_exception_exit
+
+L_bugged_round64:
+	pushl	EX_INTERNAL|0x233
 	call	EXCEPTION
 	popl	%ebx
 	jmp	L_exception_exit
 
 L_norm_bugged:
-	pushl	EX_INTERNAL|0x216
+	pushl	EX_INTERNAL|0x234
 	call	EXCEPTION
 	popl	%ebx
 	jmp	L_exception_exit
 
 L_entry_bugged:
-	pushl	EX_INTERNAL|0x217
+	pushl	EX_INTERNAL|0x235
 	call	EXCEPTION
 	popl	%ebx
 L_exception_exit:
diff -u +recursive +new-file 0.99pl15/linux/drivers/FPU-emu/version.h linux/drivers/FPU-emu/version.h
--- 0.99pl15/linux/drivers/FPU-emu/version.h	Thu Feb  3 12:11:41 1994
+++ linux/drivers/FPU-emu/version.h	Mon Feb 14 13:10:47 1994
@@ -9,5 +9,5 @@
  |                                                                           |
  +---------------------------------------------------------------------------*/
 
-#define FPU_VERSION "wm-FPU-emu version Beta 1.9"
+#define FPU_VERSION "wm-FPU-emu version Beta 1.10"
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- 0.99pl15/linux/drivers/block/Makefile	Sat Jan 29 14:55:06 1994
+++ linux/drivers/block/Makefile	Sun Mar  6 16:08:21 1994
@@ -37,9 +37,6 @@
 ifdef CONFIG_SBPCD
 OBJS := $(OBJS) sbpcd.o
 SRCS := $(SRCS) sbpcd.c
-ifdef PATCHLEVEL
-CFLAGS := $(CFLAGS) -DPATCHLEVEL=$(PATCHLEVEL) 
-endif
 endif #CONFIG_SBPCD
 
 ifdef CONFIG_BLK_DEV_HD
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- 0.99pl15/linux/drivers/block/README.sbpcd	Sun Jan 30 19:37:12 1994
+++ linux/drivers/block/README.sbpcd	Sun Mar  6 16:08:21 1994
@@ -1,4 +1,4 @@
-This is release 1.2 of the SoundBlaster Pro (Matsushita, Kotobuki,
+This is release 1.3 of the SoundBlaster Pro (Matsushita, Kotobuki,
 Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of IDE-style
@@ -6,10 +6,10 @@
 like CR-562 and CR-563, too), and it will work with the soundcard
 interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with
 the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...).
-The interface type has to get configured, because the behavior 
-is different.
+The interface type has to get configured in /usr/include/linux/sbpcd.h, 
+because the behavior is different.
 
-The driver respects different drive firmware releases - my drive
+The driver respects different drive firmware releases - my old drive
 is a 2.11, but it should work with "old" drives <2.01 ... >3.00
 and with "new" drives (which count the releases around 0.75 or
 1.00).
@@ -23,9 +23,6 @@
 to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
 they must not be in consecutive order.
 
-If this driver doesn't work with your equipment, mail me a
-description, please.
-
 The driver supports reading of data from the CD and playing of
 audio tracks. The audio part should run with WorkMan, xcdplayer,
 with the "non-X11" products CDplayer and WorkBone - tell me if
@@ -32,11 +29,8 @@
 it is not compatible with other software.
 
 MultiSession is supported, "ManySession" (see below) alternatively.
-Photo CDs should work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm
-is a package to convert photo CD image files.
-
-I did not have a chance to play with XA or mixed mode CDs yet.
-Send one over, if you would like sbpcd to support that.
+Photo CDs work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is a package 
+to convert photo CD image files.
 
 The transfer rate will reach 150 kB/sec with standard drives and
 the full 300 kB/sec with double-speed drives.
@@ -127,7 +121,7 @@
 drop me a mail and some food for the soul. :-)
 Those "many-session" CDs can get made by CDROM writers like
 Philips CDD 521.
-With this feature enabled, it is impossible to read true
+If you enable this feature, it is impossible to read true
 multisession CDs.
 
 
@@ -193,10 +187,6 @@
 
 Currently, the detection of disk change or removal does not
 work as good as it should.
-
-Further, I do not know if this driver can live together with a
-SCSI CD-ROM driver and/or device, but I hope so. 
-
 
 
 Bug reports, comments, wishes, donations (technical information
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- 0.99pl15/linux/drivers/block/floppy.c	Mon Dec 27 07:23:53 1993
+++ linux/drivers/block/floppy.c	Tue Mar  1 08:27:32 1994
@@ -301,7 +301,7 @@
 
 static void floppy_select(unsigned int nr)
 {
-	static struct timer_list select = { NULL, 0, 0, select_callback };
+	static struct timer_list select = { NULL, NULL, 0, 0, select_callback };
 
 	if (current_drive == (current_DOR & 3)) {
 		floppy_ready();
@@ -324,10 +324,10 @@
 }
 
 static struct timer_list motor_on_timer[4] = {
-	{ NULL, 0, 0, motor_on_callback },
-	{ NULL, 0, 1, motor_on_callback },
-	{ NULL, 0, 2, motor_on_callback },
-	{ NULL, 0, 3, motor_on_callback }
+	{ NULL, NULL, 0, 0, motor_on_callback },
+	{ NULL, NULL, 0, 1, motor_on_callback },
+	{ NULL, NULL, 0, 2, motor_on_callback },
+	{ NULL, NULL, 0, 3, motor_on_callback }
 };
 
 static void motor_off_callback(unsigned long nr)
@@ -341,10 +341,10 @@
 }
 
 static struct timer_list motor_off_timer[4] = {
-	{ NULL, 0, 0, motor_off_callback },
-	{ NULL, 0, 1, motor_off_callback },
-	{ NULL, 0, 2, motor_off_callback },
-	{ NULL, 0, 3, motor_off_callback }
+	{ NULL, NULL, 0, 0, motor_off_callback },
+	{ NULL, NULL, 0, 1, motor_off_callback },
+	{ NULL, NULL, 0, 2, motor_off_callback },
+	{ NULL, NULL, 0, 3, motor_off_callback }
 };
 
 static void floppy_on(unsigned int nr)
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- 0.99pl15/linux/drivers/block/mcd.c	Thu Dec  2 17:25:41 1993
+++ linux/drivers/block/mcd.c	Sun Mar  6 16:12:04 1994
@@ -852,7 +852,10 @@
 			       mcd_port);
 			return mem_start;
 		}	
-					
+
+	if (result[0] == result[1] && result[1] == result[2])
+		return mem_start;
+
 	printk("mcd: Mitsumi version : %02X %c %x\n",
 	       result[0],result[1],result[2]);
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- 0.99pl15/linux/drivers/block/sbpcd.c	Sun Jan 30 19:37:11 1994
+++ linux/drivers/block/sbpcd.c	Sun Mar  6 16:08:22 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 1.2.
+ *  NOTE:     This is release 1.3.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
@@ -13,8 +13,8 @@
  *
  *  VERSION HISTORY
  *
- *  0.1  initial release, April/May 93, after mcd.c
- *  
+ *  0.1  initial release, April/May 93, after mcd.c (Martin Harriss)
+ *
  *  0.2  the "repeat:"-loop in do_sbpcd_request did not check for
  *       end-of-request_queue (resulting in kernel panic).
  *       Flow control seems stable, but throughput is not better.  
@@ -60,7 +60,8 @@
  *  1.2  Found the "workman with double-speed drive" bug: use the driver's
  *       audio_state, not what the drive is reporting with ReadSubQ.
  *
- *
+ *  1.3  Minor cleanups.
+ *       Refinements regarding Workman.
  *
  *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
  *     elaborated speed-up experiments (and the fabulous results!), for
@@ -92,17 +93,10 @@
  *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
-#ifndef PATCHLEVEL
-#define PATCHLEVEL 9
-#endif
 
 #include <linux/config.h>
 #include <linux/errno.h>
 
-#if SBPCD_USE_IRQ
-#include <linux/signal.h>
-#endif SBPCD_USE_IRQ
-
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
@@ -111,13 +105,12 @@
 #include <linux/ioport.h>
 #include <linux/sbpcd.h>
 
-#if PATCHLEVEL>13
+#if SBPCD_USE_IRQ
+#include <linux/signal.h>
+#endif SBPCD_USE_IRQ
+
 #include <linux/ddi.h>
 #include <linux/major.h> 
-#else
-#define DDIOCSDBG 0x9000
-#define MATSUSHITA_CDROM_MAJOR 25  
-#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -127,14 +120,10 @@
 #define MAJOR_NR MATSUSHITA_CDROM_MAJOR
 #include "blk.h"
 
-#define VERSION "1.2"
+#define VERSION "1.3 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
-#ifndef CONFIG_SBPCD
-#error "SBPCD: \"make config\" again. Enable Matsushita/Panasonic CDROM support"
-#endif
-
 #ifndef CONFIG_ISO9660_FS
 #error "SBPCD: \"make config\" again. File system iso9660 is necessary."
 #endif
@@ -145,7 +134,7 @@
 #define MANY_SESSION 0
 #define CDMKE
 #undef  FUTURE
-#define WORKMAN 0 /* some testing stuff to make it better */
+#define WORKMAN 1 /* some testing stuff to make it better */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -154,17 +143,16 @@
  * inspired by Adam J. Richter from Yggdrasil
  *
  * still not good enough - can cause a hang.
- *   example: a NE 2000 ehernet card at 300 will cause a hang probing 310.
+ *   example: a NE 2000 ethernet card at 300 will cause a hang probing 310.
  * if that happens, reboot and use the LILO (kernel) command line.
- * the conflicting possible ethernet card addresses get probed last - to
- * minimize the hang possibilities. 
+ * The possibly conflicting ethernet card addresses get NOT probed 
+ * by default - to minimize the hang possibilities. 
  *
  * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error,
  * the 0x2xx-addresses must get checked before 0x6xx.
  *
- * what are other cards' default and range ???
- * what about ESCOM PowerSound???
- * what about HighScreen???
+ * send mail to emoenke@gwdg.de if your interface card is not FULLY
+ * represented here.
  */
 static int autoprobe[] = 
 {
@@ -181,11 +169,14 @@
   0x650, 0, /* "sound card #9" */
   0x670, 0, /* "sound card #9" */
   0x690, 0, /* "sound card #9" */
+#if 0
+/* some "hazardous" locations (ethernet cards) */
   0x330, 0, /* Lasermate, CI-101P */
   0x350, 0, /* Lasermate, CI-101P */
   0x370, 0, /* Lasermate, CI-101P */
   0x290, 1, /* Soundblaster 16 */
   0x310, 0, /* Lasermate, CI-101P */
+#endif
 };
 
 #define NUM_AUTOPROBE  (sizeof(autoprobe) / sizeof(int))
@@ -221,6 +212,8 @@
  * (1<<DBG_DID)  drive ID test
  * (1<<DBG_RES)  drive reset info
  * (1<<DBG_SPI)  SpinUp test info
+ * (1<<DBG_IOS)  ioctl trace: "subchannel"
+ * (1<<DBG_IO2)  ioctl trace: general
  * (1<<DBG_000)  unnecessary information
  */
 #if 1
@@ -228,6 +221,7 @@
 #else
 static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_TOC) |
+                          (1<<DBG_IOC) |
                           (1<<DBG_IOX);
 #endif
 static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
@@ -1992,9 +1986,17 @@
 {
   int i, st;
 
-  DPRINTF((DBG_IOC,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
+  DPRINTF((DBG_IO2,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
 				MINOR(inode->i_rdev), cmd, arg));
   if (!inode) return (-EINVAL);
+  i=MINOR(inode->i_rdev);
+  if ( (i<0) || (i>=NR_SBPCD) )
+    {
+      printk("SBPCD: ioctl: bad device: %d\n", i);
+      return (-ENODEV);             /* no such drive */
+    }
+  switch_drive(i);
+
   st=GetStatus();
   if (st<0) return (-EIO);
   
@@ -2004,16 +2006,7 @@
       if (i<0) return (-EIO);	/* error reading TOC */
     }
   
-  i=MINOR(inode->i_rdev);
-  if ( (i<0) || (i>=NR_SBPCD) )
-    {
-      DPRINTF((DBG_INF,"SBPCD: ioctl: bad device: %d\n", i));
-      return (-ENODEV);             /* no such drive */
-    }
-  switch_drive(i);
-
-
-  DPRINTF((DBG_IOC,"SBPCD: ioctl: device %d, request %04X\n",i,cmd));
+  DPRINTF((DBG_IO2,"SBPCD: ioctl: device %d, request %04X\n",i,cmd));
   switch (cmd) 		/* Sun-compatible */
     {
     case DDIOCSDBG:		/* DDI Debug */
@@ -2194,7 +2187,7 @@
       return (0);
 
     case CDROMSUBCHNL:   /* Get subchannel info */
-      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSUBCHNL entered.\n"));
+      DPRINTF((DBG_IOS,"SBPCD: ioctl: CDROMSUBCHNL entered.\n"));
       if ((st_spinning)||(!subq_valid)) { i=xx_ReadSubQ();
 					  if (i<0) return (-EIO);
 					}
@@ -2235,7 +2228,7 @@
 	  SC.cdsc_reladdr.msf.frame=DS[d].SubQ_run_trk&0x00FF;
 	}
       memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl));
-      DPRINTF((DBG_IOC,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
+      DPRINTF((DBG_IOS,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n",
 	       SC.cdsc_format,SC.cdsc_audiostatus,
 	       SC.cdsc_adr,SC.cdsc_ctrl,
 	       SC.cdsc_trk,SC.cdsc_ind,
@@ -2251,7 +2244,7 @@
       return (-EINVAL);
       
     default:
-      DPRINTF((DBG_IOX,"SBPCD: ioctl: unknown function request %04X\n", cmd));
+      DPRINTF((DBG_IOC,"SBPCD: ioctl: unknown function request %04X\n", cmd));
       return (-EINVAL);
     } /* end switch(cmd) */
 }
@@ -2353,7 +2346,7 @@
   dev = MINOR(CURRENT->dev);
   if ( (dev<0) || (dev>=NR_SBPCD) )
     {
-      DPRINTF((DBG_INF,"SBPCD: do_request: bad device: %d\n", dev));
+      printk("SBPCD: do_request: bad device: %d\n", dev);
       return;
     }
   switch_drive(dev);
@@ -2364,7 +2357,7 @@
 
   if (CURRENT->cmd != READ)
     {
-      DPRINTF((DBG_INF,"SBPCD: bad cmd %d\n", CURRENT->cmd));
+      printk("SBPCD: bad cmd %d\n", CURRENT->cmd);
       end_request(0);
       goto request_loop;
     }
@@ -2556,8 +2549,8 @@
       if (j&s_not_data_ready)
 	{
 	  if ((DS[d].ored_ctl_adr&0x40)==0)
-	    DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n"));
-	  else DPRINTF((DBG_INF,"SBPCD: sbp_data: DATA_READY timeout.\n"));
+	    printk("SBPCD: CD contains no data tracks.\n");
+	  else printk("SBPCD: sbp_data: DATA_READY timeout.\n");
 	  error_flag++;
 	  break;
 	}
@@ -2665,7 +2658,7 @@
   i = MINOR(ip->i_rdev);
   if ( (i<0) || (i>=NR_SBPCD) )
     {
-      DPRINTF((DBG_INF,"SBPCD: open: bad device: %d\n", i));
+      printk("SBPCD: open: bad device: %d\n", i);
       return (-ENODEV);             /* no such drive */
     }
   switch_drive(i);
@@ -2683,7 +2676,7 @@
   DPRINTF((DBG_STA,"SBPCD: sbpcd_open: status %02X\n", DS[d].status_byte));
   if (!st_door_closed||!st_caddy_in)
     {
-      DPRINTF((DBG_INF,"SBPCD: sbpcd_open: no disk in drive\n"));
+      printk("SBPCD: sbpcd_open: no disk in drive\n");
       return (-EIO);
     }
 
@@ -2716,7 +2709,7 @@
   i = MINOR(ip->i_rdev);
   if ( (i<0) || (i>=NR_SBPCD) ) 
     {
-      DPRINTF((DBG_INF,"SBPCD: release: bad device: %d\n", i));
+      printk("SBPCD: release: bad device: %d\n", i);
       return;
     }
   switch_drive(i);
@@ -2840,19 +2833,25 @@
       DPRINTF((DBG_INI,"SBPCD: check_drives done.\n"));
       sti(); /* to avoid possible "printk" bug */
       if (i>=0) break; /* drive found */
-      printk ("\n");
+      DPRINTF((DBG_INF,"\n"));
       sti(); /* to avoid possible "printk" bug */
     } /* end of cycling through the set of possible I/O port addresses */
 
   if (ndrives==0)
     {
-      DPRINTF((DBG_INF,"SBPCD: No drive found.\n"));
+      printk("SBPCD: No drive found.\n");
       sti();
       return (mem_start);
     }
 
-  DPRINTF((DBG_INF,"SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n",
-	   ndrives, type, CDo_command));
+  if (port_index>0)
+    {
+      printk("SBPCD: You should configure sbpcd.h for your hardware.\n");
+      sti();
+    }
+
+  printk("SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n",
+	   ndrives, type, CDo_command);
   sti(); /* to avoid possible "printk" bug */
   check_datarate();
   DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n"));
@@ -2908,8 +2907,8 @@
   
   if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0)
     {
-      DPRINTF((DBG_INF,"SBPCD: Can't get MAJOR %d for Matsushita CDROM\n",
-	       MATSUSHITA_CDROM_MAJOR));
+      printk("SBPCD: Can't get MAJOR %d for Matsushita CDROM\n",
+	       MATSUSHITA_CDROM_MAJOR);
       sti(); /* to avoid possible "printk" bug */
       return (mem_start);
     }
@@ -2921,8 +2920,7 @@
 #if SBPCD_USE_IRQ
   if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction))
     {
-      DPRINTF((DBG_INF,"SBPCD: Can't get IRQ%d for sbpcd driver\n",
-	       SBPCD_INTR_NR));
+      printk("SBPCD: Can't get IRQ%d for sbpcd driver\n", SBPCD_INTR_NR);
       sti(); /* to avoid possible "printk" bug */
     }
 #endif SBPCD_USE_IRQ
@@ -2954,7 +2952,7 @@
 
   if (MAJOR(full_dev) != MATSUSHITA_CDROM_MAJOR) 
     {
-      DPRINTF((DBG_INF,"SBPCD: media_check: invalid device.\n"));
+      printk("SBPCD: media_check: invalid device.\n");
       return (-1);
     }
   
diff -u +recursive +new-file 0.99pl15/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- 0.99pl15/linux/drivers/block/xd.c	Wed Dec  1 14:44:15 1993
+++ linux/drivers/block/xd.c	Sat Feb 12 18:27:33 1994
@@ -60,6 +60,7 @@
 	{ 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
 	{ 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
 	{ 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
+	{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
 };
 static u_char *xd_bases[] =
 {
@@ -578,6 +579,34 @@
 	}
 	else
 		printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
+}
+
+/* Omti support courtesy Dirk Melchers */
+static void xd_omti_init_controller (u_char *address)
+{
+	switch ((u_long) address) {
+		case 0xC8000:	xd_iobase = 0x320; break;
+		case 0xD0000:	xd_iobase = 0x324; break;
+		case 0xD8000:	xd_iobase = 0x328; break;
+		case 0xE0000:	xd_iobase = 0x32C; break;
+		default:	printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
+				xd_iobase = 0x320; break;
+	}
+	
+	xd_irq = 5;			/* the IRQ and DMA channel are fixed on the Omti controllers */
+	xd_dma = 3;
+	xd_maxsectors = 0x40;
+
+	outb(0,XD_RESET);		/* reset the controller */
+}
+
+static void xd_omti_init_drive (u_char drive)
+{
+	/* gets infos from drive */
+	xd_override_init_drive(drive);
+
+	/* set other parameters, Hardcoded, not that nice :-) */
+	xd_info[drive].control = 2;
 }
 
 /* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/console.c linux/drivers/char/console.c
--- 0.99pl15/linux/drivers/char/console.c	Thu Feb  3 13:34:54 1994
+++ linux/drivers/char/console.c	Wed Feb 23 08:52:24 1994
@@ -382,12 +382,18 @@
 	__set_origin(__real_origin);
 }
 
-static inline void hide_cursor(int currcons)
+/*
+ * Put the cursor just beyond the end of the display adaptor memory.
+ */
+static inline void hide_cursor(void)
 {
+  /* This is inefficient, we could just put the cursor at 0xffff,
+     but perhaps the delays due to the inefficiency are useful for
+     some hardware... */
 	outb_p(14, video_port_reg);
-	outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
 	outb_p(15, video_port_reg);
-	outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
 }
 
 static inline void set_cursor(int currcons)
@@ -405,7 +411,7 @@
 		outb_p(15, video_port_reg);
 		outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 	} else
-		hide_cursor(currcons);
+		hide_cursor();
 	restore_flags(flags);
 }
 
@@ -1546,7 +1552,7 @@
 		return;
 	timer_table[BLANK_TIMER].fn = unblank_screen;
 	get_scrmem(fg_console);
-	hide_cursor(fg_console);
+	hide_cursor();
 	console_blanked = 1;
 	memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
 }
@@ -1800,12 +1806,11 @@
 	if (! *bp)
 		return 0;
 	unblank_screen();
-	while (*bp)
-	{
+	while (*bp) {
 		put_tty_queue(*bp, &tty->read_q);
 		bp++;
+		TTY_READ_FLUSH(tty);
 	}
-	TTY_READ_FLUSH(tty);
 	return 0;
 }
 
@@ -1823,6 +1828,14 @@
 
 /*
  * PIO_FONT support.
+ *
+ * The font loading code goes back to the codepage package by
+ * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
+ * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
+ * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
+ *
+ * Change for certain monochrome monitors by Yury Shevchuck
+ * (sizif@botik.yaroslavl.su).
  */
 
 #define colourmap ((char *)0xa0000)
@@ -1838,14 +1851,17 @@
 #ifdef CAN_LOAD_EGA_FONTS
 	int i;
 	char *charmap;
+	int beg;
 
 	/* no use to "load" CGA... */
 
-	if (video_type == VIDEO_TYPE_EGAC)
+	if (video_type == VIDEO_TYPE_EGAC) {
 		charmap = colourmap;
-	else if (video_type == VIDEO_TYPE_EGAM)
+		beg = 0x0e;
+	} else if (video_type == VIDEO_TYPE_EGAM) {
 		charmap = blackwmap;
-	else
+		beg = 0x0a;
+	} else
 		return -EINVAL;
 
 	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
@@ -1892,7 +1908,7 @@
 	outb_p( 0x05, gr_port_reg );
 	outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
 	outb_p( 0x06, gr_port_reg );
-	outb_p( 0x0e, gr_port_val );    /* map starts at b800:0000 */
+	outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
 	sti();
 
 	return 0;
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- 0.99pl15/linux/drivers/char/keyboard.c	Tue Feb  1 13:04:29 1994
+++ linux/drivers/char/keyboard.c	Thu Mar  3 08:05:22 1994
@@ -29,12 +29,19 @@
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+
 #ifndef KBD_DEFMODE
 #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
 #endif
 
 #ifndef KBD_DEFLEDS
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock
+ * is on. This seems a good reason to start with NumLock off.
+ */
+#define KBD_DEFLEDS 0
 #endif
 
 #ifndef KBD_DEFLOCK
@@ -205,6 +212,17 @@
 	} else if (scancode == 0xfe) {
 		resend = 1;
 		goto end_kbd_intr;
+	} else if (scancode == 0) {
+#ifdef KBD_REPORT_ERR
+	        printk("keyboard buffer overflow\n");
+#endif
+		goto end_kbd_intr;
+	} else if (scancode == 0xff) {
+#ifdef KBD_REPORT_ERR
+	        printk("keyboard error\n");
+#endif
+	        prev_scancode = 0;
+	        goto end_kbd_intr;
 	}
 	tty = TTY_TABLE(0);
  	kbd = kbd_table + fg_console;
@@ -263,13 +281,17 @@
 	      if (e0_keys[scancode])
 		scancode = e0_keys[scancode];
 	      else if (!raw_mode) {
+#ifdef KBD_REPORT_UNKN
 		  printk("keyboard: unknown scancode e0 %02x\n", scancode);
+#endif
 		  goto end_kbd_intr;
 	      }
 	  }
 	} else if (scancode >= E0_BASE && !raw_mode) {
+#ifdef KBD_REPORT_UNKN
 	  printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
 		 scancode, E0_BASE - 1);
+#endif
 	  goto end_kbd_intr;
  	}
   
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- 0.99pl15/linux/drivers/char/psaux.c	Tue Jan 11 11:08:20 1994
+++ linux/drivers/char/psaux.c	Thu Feb 17 09:15:19 1994
@@ -442,7 +442,6 @@
         int qp_found = 0;
 
 #ifdef CONFIG_82C710_MOUSE
-	printk("Probing 82C710 mouse port device.\n");
         if ((qp_found = probe_qp())) {
 	        printk("82C710 type pointing device detected -- driver installed.\n");
 /*		printk("82C710 address = %x (should be 0x310)\n", qp_data); */
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- 0.99pl15/linux/drivers/char/pty.c	Wed Feb  2 13:54:21 1994
+++ linux/drivers/char/pty.c	Wed Feb  9 08:57:58 1994
@@ -55,14 +55,11 @@
 {
 	unsigned long count, n;
 	struct tty_queue *fq, *tq;
-	int skip_readq;
 
 	if (from->stopped || EMPTY(&from->write_q))
 		return;
 	fq = &from->write_q;
-	/* Bypass the read_q if this is a pty master. */
-	skip_readq = IS_A_PTY_MASTER(to->line) && to->disc == N_TTY;
-	tq = skip_readq ? &to->secondary : &to->read_q;
+	tq = &to->read_q;
 	count = MIN(CHARS(fq), LEFT(tq));
 	while (count) {
 		n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head),
@@ -72,10 +69,7 @@
 		fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1);
 		tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1);
 	}
-	if (skip_readq)
-		wake_up_interruptible(&to->secondary.proc_list);
-	else
-		TTY_READ_FLUSH(to);
+	TTY_READ_FLUSH(to);
 	if (LEFT(fq) > WAKEUP_CHARS)
 		wake_up_interruptible(&fq->proc_list);
 	if (from->write_data_cnt) {
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- 0.99pl15/linux/drivers/char/serial.c	Wed Jan 26 11:17:55 1994
+++ linux/drivers/char/serial.c	Sun Mar 13 22:20:21 1994
@@ -258,7 +258,13 @@
 	struct async_struct *info;
 	
 	info = rs_table + DEV_TO_SL(tty->line);
-	
+
+	if (info->flags & ASYNC_CLOSING) {
+		tty->stopped = 0;
+		tty->hw_stopped = 0;
+		return;
+	}
+
 	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
 #ifdef ISR_HACK
 	serial_out(info, UART_IER, info->IER);
@@ -431,7 +437,7 @@
 			rs_sched_event(info, RS_EVENT_HANGUP);
 		}
 	}
-	if (C_CRTSCTS(info->tty)) {
+	if (C_CRTSCTS(info->tty) && !(info->flags & ASYNC_CLOSING)) {
 		if (info->tty->hw_stopped) {
 			if (status & UART_MSR_CTS) {
 #ifdef SERIAL_DEBUG_INTR
@@ -456,7 +462,7 @@
 
 static inline void figure_RS_timer(void)
 {
-	int	timeout = 6000;	/* 60 seconds; really big :-) */
+	int	timeout = jiffies + 60*HZ; /* 60 seconds; really big :-) */
 	int	i, mask;
 	
 	if (!IRQ_active)
@@ -467,7 +473,7 @@
 		if (IRQ_timer[i] < timeout)
 			timeout = IRQ_timer[i];
 	}
-	timer_table[RS_TIMER].expires = jiffies + timeout;
+	timer_table[RS_TIMER].expires = timeout;
 	timer_active |= 1 << RS_TIMER;
 }
 
@@ -1029,9 +1035,11 @@
 	if (!tty || tty->stopped || tty->hw_stopped)
 		return;
 	info = rs_table + DEV_TO_SL(tty->line);
-	if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED))
-		return;
 	cli();
+	if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED)) {
+		sti();
+		return;
+	}
 	restart_port(info);
 	info->IER = (UART_IER_MSI | UART_IER_RLSI |
 		     UART_IER_THRI | UART_IER_RDI);
@@ -1520,11 +1528,7 @@
 	tty->hw_stopped = 0;
 	if (info->flags & ASYNC_INITIALIZED) {
 		rs_start(tty);
-		/*
-		 * XXX There should be a timeout added to
-		 * wait_until_sent, eventually.  TYT 1/19/94
-		 */
-		wait_until_sent(tty);
+		wait_until_sent(tty, 6000); /* 60 seconds timeout */
 	} else
 		flush_output(tty);
 	flush_input(tty);
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- 0.99pl15/linux/drivers/char/tpqic02.c	Wed Dec  1 14:44:15 1993
+++ linux/drivers/char/tpqic02.c	Mon Feb 14 22:13:26 1994
@@ -1816,7 +1816,7 @@
 	int stat;
 
 	if (TP_DIAGS(current_tape_dev))
-		printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n",
+		printk(TPQIC_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%x, flags=%x\n",
 			MINOR(dev), buf, count, filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* Only allow mod 512 bytes at a time. */
@@ -1833,7 +1833,7 @@
 	/* Make sure buffer is safe to write into. */
 	error = verify_area(VERIFY_WRITE, buf, count);
 	if (error) {
-		printk(TPQIC_NAME ": read: verify_area(WRITE, %lx, %x) failed\n", buf, count);
+		printk(TPQIC_NAME ": read: verify_area(WRITE, %p, %x) failed\n", buf, count);
 		return error;
 	}
 
@@ -1985,7 +1985,7 @@
 	unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
 
 	if (TP_DIAGS(current_tape_dev))
-		printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n",
+		printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%x, flags=%x\n",
 			MINOR(dev), buf, count, filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* only allow mod 512 bytes at a time */
@@ -2010,7 +2010,7 @@
 	/* Make sure buffer is safe to read from. */
 	error = verify_area(VERIFY_READ, buf, count);
 	if (error) {
-		printk(TPQIC_NAME ": write: verify_area(READ, %lx, %x) failed\n", buf, count);
+		printk(TPQIC_NAME ": write: verify_area(READ, %p, %x) failed\n", buf, count);
 		return error;
 	}
 
@@ -2107,7 +2107,7 @@
 		}
 	}
 	tpqputs("write request for <0 bytes");
-	printk(TPQIC_NAME ": status_bytes_wr %x, buf %x, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count);
+	printk(TPQIC_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count);
 	return -EINVAL;
 } /* tape_qic02_write */
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- 0.99pl15/linux/drivers/char/tty_io.c	Tue Feb  1 13:04:30 1994
+++ linux/drivers/char/tty_io.c	Tue Mar  1 19:00:15 1994
@@ -259,8 +259,10 @@
 	flush_input(tty);
 	flush_output(tty);
 	wake_up_interruptible(&tty->secondary.proc_list);
-	if (tty->session > 0)
+	if (tty->session > 0) {
 		kill_sl(tty->session,SIGHUP,1);
+		kill_sl(tty->session,SIGCONT,1);
+	}
 	tty->session = 0;
 	tty->pgrp = -1;
  	for_each_task(p) {
@@ -297,7 +299,7 @@
  * it wants to dissassociate itself from its controlling tty.
  *
  * It performs the following functions:
- * 	(1)  Sends a SIGHUP to the foreground process group
+ * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
  * 	(2)  Clears the tty from being controlling the session
  * 	(3)  Clears the controlling tty for all processes in the
  * 		session group.
@@ -310,8 +312,10 @@
 	if (current->tty >= 0) {
 		tty = tty_table[current->tty];
 		if (tty) {
-			if (tty->pgrp > 0)
+			if (tty->pgrp > 0) {
 				kill_pg(tty->pgrp, SIGHUP, priv);
+				kill_pg(tty->pgrp, SIGCONT, priv);
+			}
 			tty->session = 0;
 			tty->pgrp = -1;
 		} else
@@ -926,10 +930,7 @@
 static inline int input_available_p(struct tty_struct *tty)
 {
 	/* Avoid calling TTY_READ_FLUSH unnecessarily. */
-	if (L_ICANON(tty)) {
-		if (tty->canon_data || FULL(&tty->read_q))
-			return 1;
-	} else if (!EMPTY(&tty->secondary))
+	if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
 		return 1;
 
 	/* Shuffle any pending data down the queues. */
@@ -937,10 +938,7 @@
 	if (tty->link)
 		TTY_WRITE_FLUSH(tty->link);
 
-	if (L_ICANON(tty)) {
-		if (tty->canon_data || FULL(&tty->read_q))
-			return 1;
-	} else if (!EMPTY(&tty->secondary))
+	if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
 		return 1;
 	return 0;
 }
@@ -954,6 +952,24 @@
 	int minimum, time;
 	int retval = 0;
 
+	/* Job control check -- must be done at start and after
+	   every sleep (POSIX.1 7.1.1.4). */
+	/* NOTE: not yet done after every sleep pending a thorough
+	   check of the logic of this change. -- jlc */
+	/* don't stop on /dev/console */
+	if (file->f_inode->i_rdev != CONSOLE_DEV &&
+	    current->tty == tty->line) {
+		if (tty->pgrp <= 0)
+			printk("read_chan: tty->pgrp <= 0!\n");
+		else if (current->pgrp != tty->pgrp) {
+			if (is_ignored(SIGTTIN) ||
+			    is_orphaned_pgrp(current->pgrp))
+				return -EIO;
+			kill_pg(current->pgrp, SIGTTIN, 1);
+			return -ERESTARTSYS;
+		}
+	}
+
 	if (L_ICANON(tty)) {
 		minimum = time = 0;
 		current->timeout = (unsigned long) -1;
@@ -974,24 +990,6 @@
 
 	add_wait_queue(&tty->secondary.proc_list, &wait);
 	while (1) {
-		/* Job control check -- must be done at start and after
-		   every sleep (POSIX.1 7.1.1.4). */
-		/* don't stop on /dev/console */
-		if (file->f_inode->i_rdev != CONSOLE_DEV &&
-		    current->tty == tty->line) {
-			if (tty->pgrp <= 0)
-				printk("read_chan: tty->pgrp <= 0!\n");
-			else if (current->pgrp != tty->pgrp) {
-				if (is_ignored(SIGTTIN) ||
-				    is_orphaned_pgrp(current->pgrp)) {
-					retval = -EIO;
-					break;
-				}
-				kill_pg(current->pgrp, SIGTTIN, 1);
-				retval = -ERESTARTSYS;
-				break;
-			}
-		}
 		/* First test for status change. */
 		if (tty->packet && tty->link->ctrl_status) {
 			if (b != buf)
@@ -1032,7 +1030,7 @@
 			nr--;
 		}
 
-		while (nr > 0) {
+		while (1) {
 			int eol;
 
 			cli();
@@ -1043,6 +1041,24 @@
 			eol = clear_bit(tty->secondary.tail,
 					&tty->secondary_flags);
 			c = tty->secondary.buf[tty->secondary.tail];
+			if (!nr) {
+				/* Gobble up an immediately following EOF if
+				   there is no more room in buf (this can
+				   happen if the user "pushes" some characters
+				   using ^D).  This prevents the next read()
+				   from falsely returning EOF. */
+				if (eol) {
+					if (c == __DISABLED_CHAR) {
+						tty->canon_data--;
+						INC(tty->secondary.tail);
+					} else {
+						set_bit(tty->secondary.tail,
+							&tty->secondary_flags);
+					}
+				}
+				sti();
+				break;
+			}
 			INC(tty->secondary.tail);
 			sti();
 			if (eol) {
@@ -1063,10 +1079,9 @@
 		/* If there is enough space in the secondary queue now, let the
 		   low-level driver know. */
 		if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
-		    && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
+		    && clear_bit(TTY_SQ_THROTTLED, &tty->flags))
 			tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
 
-		/* XXX packet mode's status byte is mistakenly counted */
 		if (b - buf >= minimum || !nr)
 			break;
 		if (time)
@@ -1117,6 +1132,10 @@
 			break;
 		if (EMPTY(&tty->write_q) && !need_resched)
 			continue;
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			break;
+		}
 		schedule();
 	}
 	current->state = TASK_RUNNING;
@@ -1590,7 +1609,7 @@
 			select_wait(&tty->secondary.proc_list, wait);
 			return 0;
 		case SEL_OUT:
-			if (!FULL(&tty->write_q))
+			if (LEFT(&tty->write_q) > WAKEUP_CHARS)
 				return 1;
 			select_wait(&tty->write_q.proc_list, wait);
 			return 0;
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- 0.99pl15/linux/drivers/char/tty_ioctl.c	Mon Jan 31 12:37:14 1994
+++ linux/drivers/char/tty_ioctl.c	Tue Mar  1 19:00:15 1994
@@ -82,7 +82,7 @@
 	}
 }
 
-void wait_until_sent(struct tty_struct * tty)
+void wait_until_sent(struct tty_struct * tty, int timeout)
 {
 	struct wait_queue wait = { current, NULL };
 
@@ -91,7 +91,11 @@
 		return;
 	add_wait_queue(&tty->write_q.proc_list, &wait);
 	current->counter = 0;	/* make us low-priority */
-	while (1) {
+	if (timeout)
+		current->timeout = timeout + jiffies;
+	else
+		current->timeout = (unsigned) -1;
+	do {
 		current->state = TASK_INTERRUPTIBLE;
 		if (current->signal & ~current->blocked)
 			break;
@@ -99,7 +103,7 @@
 		if (EMPTY(&tty->write_q))
 			break;
 		schedule();
-	}
+	} while (current->timeout);
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&tty->write_q.proc_list, &wait);
 }
@@ -297,7 +301,7 @@
 		return 0;	/* We are already in the desired discipline */
 
 	/* Shutdown the current discipline. */
-	wait_until_sent(tty);
+	wait_until_sent(tty, 0);
 	flush_input(tty);
 	if (ldiscs[tty->disc].close)
 		ldiscs[tty->disc].close(tty);
@@ -379,7 +383,7 @@
 			if (cmd == TCSETSF || cmd == TCSETSW) {
 				if (cmd == TCSETSF)
 					flush_input(termios_tty);
-				wait_until_sent(termios_tty);
+				wait_until_sent(termios_tty, 0);
 			}
 			return set_termios(termios_tty, (struct termios *) arg,
 					   termios_dev);
@@ -394,7 +398,7 @@
 			if (cmd == TCSETAF || cmd == TCSETAW) {
 				if (cmd == TCSETAF)
 					flush_input(termios_tty);
-				wait_until_sent(termios_tty);
+				wait_until_sent(termios_tty, 0);
 			}
 			return set_termio(termios_tty, (struct termio *) arg,
 					  termios_dev);
@@ -483,6 +487,8 @@
 					     sizeof (pid_t));
 			if (retval)
 				return retval;
+			if (current->tty != termios_dev)
+				return -ENOTTY;
 			put_fs_long(termios_tty->pgrp, (pid_t *) arg);
 			return 0;
 		case TIOCSPGRP:
@@ -522,7 +528,10 @@
 			return 0;
 		case TIOCSTI:
 			if ((current->tty != dev) && !suser())
-				return -EACCES;
+				return -EPERM;
+			retval = verify_area(VERIFY_READ, (void *) arg, 1);
+			if (retval)
+				return retval;
 			put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
 			TTY_READ_FLUSH(tty);
 			return 0;
@@ -550,6 +559,9 @@
 					return set_selection(arg);
 				case 3:
 					return paste_selection(tty);
+				case 4:
+					unblank_screen();
+					return 0;
 #endif /* CONFIG_SELECTION */
 				default: 
 					return -EINVAL;
@@ -570,7 +582,7 @@
 			else if (IS_A_PTY_SLAVE(dev))
 				redirect = tty;
 			else
-				return -EINVAL;
+				return -ENOTTY;
 			return 0;
 		case FIONBIO:
 			arg = get_fs_long((unsigned long *) arg);
@@ -580,8 +592,8 @@
 				file->f_flags &= ~O_NONBLOCK;
 			return 0;
 		case TIOCNOTTY:
-			if (MINOR(file->f_rdev) != current->tty)
-				return -EINVAL;
+			if (current->tty != dev)
+				return -ENOTTY;
 			if (current->leader)
 				disassociate_ctty(0);
 			current->tty = -1;
@@ -619,7 +631,7 @@
 			return 0;
 		case TIOCPKT:
 			if (!IS_A_PTY_MASTER(dev))
-				return -EINVAL;
+				return -ENOTTY;
 			retval = verify_area(VERIFY_READ, (void *) arg,
 					     sizeof (unsigned long));
 			if (retval)
@@ -627,7 +639,7 @@
 			if (get_fs_long(arg)) {
 				if (!tty->packet) {
 					tty->packet = 1;
-					tty->ctrl_status = 0;
+					tty->link->ctrl_status = 0;
 				}
 			} else
 				tty->packet = 0;
@@ -636,7 +648,7 @@
 			retval = check_change(tty, dev);
 			if (retval)
 				return retval;
-			wait_until_sent(tty);
+			wait_until_sent(tty, 0);
 			if (!tty->ioctl)
 				return 0;
 			tty->ioctl(tty, file, cmd, arg);
diff -u +recursive +new-file 0.99pl15/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- 0.99pl15/linux/drivers/char/vt.c	Tue Feb  1 13:04:30 1994
+++ linux/drivers/char/vt.c	Fri Feb 11 13:06:42 1994
@@ -86,7 +86,7 @@
 void
 kd_mksound(unsigned int count, unsigned int ticks)
 {
-	static struct timer_list sound_timer = { NULL, 0, 0, kd_nosound };
+	static struct timer_list sound_timer = { NULL, NULL, 0, 0, kd_nosound };
 
 	cli();
 	del_timer(&sound_timer);
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- 0.99pl15/linux/drivers/net/3c501.c	Wed Feb  2 17:30:01 1994
+++ linux/drivers/net/3c501.c	Sun Mar  6 16:12:04 1994
@@ -17,7 +17,7 @@
 */
 
 static char *version =
-    "3c501.c:v13.13 1993 Donald Becker (becker@super.org).\n";
+    "3c501.c: 3/3/94 Donald Becker (becker@super.org).\n";
 
 /*
   Braindamage remaining:
@@ -301,9 +301,6 @@
 
     if (skb->len <= 0)
 	return 0;
-
-    if (el_debug > 2)
-	printk("%s: el_start_xmit(%d)...", dev->name, skb->len);
 
     /* Avoid timer-based retransmission conflicts. */
     if (set_bit(0, (void*)&dev->tbusy) != 0)
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- 0.99pl15/linux/drivers/net/3c503.c	Wed Dec  1 14:44:15 1993
+++ linux/drivers/net/3c503.c	Sun Mar  6 16:12:04 1994
@@ -16,7 +16,7 @@
 */
 
 static char *version =
-    "3c503.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
+    "3c503.c:v0.99.15k 3/3/93 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -200,9 +200,6 @@
 	dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
 	dev->rmem_start = TX_PAGES*256 + dev->mem_start;
     }
-    if (ei_debug > 2)
-	printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n",
-	       dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end);
 
     /* Finish setting the board's parameters. */
     ei_status.name = "3C503";
@@ -228,7 +225,7 @@
     dev->stop = &el2_close;
 
     if (dev->mem_start)
-	printk("\n%s: %s with shared memory at %#6x-%#6x,\n",
+	printk("\n%s: %s with shared memory at %#6lx-%#6lx,\n",
 	       dev->name, ei_status.name, dev->mem_start, dev->mem_end-1);
     else
 	printk("\n%s: %s using programmed I/O (REJUMPER for SHARED MEMORY).\n",
@@ -352,9 +349,6 @@
 	if (ei_debug > 2  &&  memcmp(dest_addr, buf, count))
 	    printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n",
 		   dev->name, (int) dest_addr);
-	else if (ei_debug > 4)
-	    printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n",
-		   dev->name, (int) dest_addr);
 	return;
     }
     /* No shared memory, put the packet out the slow way. */
@@ -395,19 +389,11 @@
 	if (dev->mem_start + ring_offset + count > end_of_ring) {
 	    /* We must wrap the input move. */
 	    int semi_count = end_of_ring - (dev->mem_start + ring_offset);
-	    if (ei_debug > 4)
-		printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
-		       dev->name, dev->mem_start, ring_offset,
-		       dev->mem_start + ring_offset);
 	    memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
 	    count -= semi_count;
 	    memcpy(buf + semi_count, (char *)dev->rmem_start, count);
 	    return dev->rmem_start + count;
 	}
-	if (ei_debug > 4)
-	    printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
-		   dev->name, dev->mem_start, ring_offset,
-		   dev->mem_start + ring_offset);
 	memcpy(buf, (char *)dev->mem_start + ring_offset, count);
 	return ring_offset + count;
     }
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- 0.99pl15/linux/drivers/net/3c507.c	Wed Feb  2 17:30:02 1994
+++ linux/drivers/net/3c507.c	Sun Mar  6 16:12:05 1994
@@ -11,6 +11,8 @@
 
 	Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings)
 	and jrs@world.std.com (Rick Sladkey) for testing and bugfixes.
+	Mark Salazar <leslie@access.digex.net> made the changes for cards with
+	only 16K packet buffers.
 
 	Things remaining to do:
 	Verify that the tx and rx buffers don't have fencepost errors.
@@ -19,7 +21,7 @@
 */
 
 static char *version =
-	"3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n";
+	"3c507.c:v0.99-15f 2/17/94 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 
@@ -145,6 +147,17 @@
 #define iSCB_CBL		0xC	/* Command BLock offset. */
 #define iSCB_RFA		0xE	/* Rx Frame Area offset. */
 
+/*  Since the 3c507 maps the shared memory window so that the last byte is
+	at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or
+	48K cooresponding to window sizes of 64K, 48K, 32K and 16K respectively. 
+	We can account for this be setting the 'SBC Base' entry in the ISCP table
+	below for all the 16 bit offset addresses, and also adding the 'SCB Base'
+	value to all 24 bit physical addresses (in the SCP table and the TX and RX
+	Buffer Descriptors).
+					-Mark	
+	*/
+#define SCB_BASE		((unsigned)64*1024 - (dev->mem_end - dev->mem_start))
+ 
 /*
   What follows in 'init_words[]' is the "program" that is downloaded to the
   82586 memory.	 It's mostly tables and command blocks, and starts at the
@@ -192,7 +205,7 @@
   The Tx command chain and buffer list is setup as follows:
   A Tx command table, with the data buffer pointing to...
   A Tx data buffer descriptor.  The packet is in a single buffer, rather than
-     chaining together several smaller buffers.
+	chaining together several smaller buffers.
   A NoOp command, which initially points to itself,
   And the packet data.
 
@@ -213,13 +226,17 @@
 
   */
 
-short init_words[] = {
+unsigned short init_words[] = {
+	/*	System Configuration Pointer (SCP). */
 	0x0000,					/* Set bus size to 16 bits. */
-	0x0000,0x0000,			/* Set control mailbox (SCB) addr. */
-	0,0,					/* pad to 0x000000. */
+	0,0,					/* pad words. */
+	0x0000,0x0000,			/* ISCP phys addr, set in init_82586_mem(). */
+
+	/*	Intermediate System Configuration Pointer (ISCP). */
 	0x0001,					/* Status word that's cleared when init is done. */
 	0x0008,0,0,				/* SCB offset, (skip, skip) */
 
+	/* System Control Block (SCB). */
 	0,0xf000|RX_START|CUC_START,	/* SCB status and cmd. */
 	CONFIG_CMD,				/* Command list pointer, points to Configure. */
 	RX_BUF_START,				/* Rx block list. */
@@ -270,11 +287,11 @@
 
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
-   If dev->base_addr == 0, probe all likely locations.
-   If dev->base_addr == 1, always return failure.
-   If dev->base_addr == 2, (detachable devices only) alloate space for the
-   device and return success.
-   */
+	If dev->base_addr == 0, probe all likely locations.
+	If dev->base_addr == 1, always return failure.
+	If dev->base_addr == 2, (detachable devices only) alloate space for the
+	device and return success.
+	*/
 int
 el16_probe(struct device *dev)
 {
@@ -369,9 +386,6 @@
 			size = ((mem_config & 3) + 1) << 14;
 			base = 0x0c0000 + ( (mem_config & 0x18) << 12);
 		}
-		if (size != 0x10000)
-			printk("%s: Warning, this version probably only works with 64K of"
-				   "shared memory.\n", dev->name);
 		dev->mem_start = base;
 		dev->mem_end = base + size;
 	}
@@ -380,7 +394,7 @@
 	dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0;
 	dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
 
-	printk(", IRQ %d, %sternal xcvr, memory %#x-%#x.\n", dev->irq,
+	printk(", IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->irq,
 		   dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1);
 
 	if (net_debug)
@@ -538,9 +552,9 @@
 	
 	status = shmem[iSCB_STATUS>>1];
 	
-    if (net_debug > 4) {
+	if (net_debug > 4) {
 		printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);
-    }
+	}
 
 	/* Disable the 82586's input to the interrupt line. */
 	outb(0x80, ioaddr + MISC_CTRL);
@@ -661,6 +675,7 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned short *write_ptr;
+	unsigned short SCB_base = SCB_BASE;
 
 	int cur_rxbuf = lp->rx_head = RX_BUF_START;
 	
@@ -683,7 +698,7 @@
 		
 		*write_ptr++ = 0x0000;				/* Buffer: Actual count */
 		*write_ptr++ = -1;					/* Buffer: Next (none). */
-		*write_ptr++ = cur_rxbuf + 0x20;		/* Buffer: Address low */
+		*write_ptr++ = cur_rxbuf + 0x20 + SCB_base;	/* Buffer: Address low */
 		*write_ptr++ = 0x0000;
 		/* Finally, the number of bytes in the buffer. */
 		*write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20;
@@ -712,12 +727,13 @@
 	   and hold the 586 in reset during the memory initialization. */
 	outb(0x20, ioaddr + MISC_CTRL);
 
+	/* Fix the ISCP address and base. */
+	init_words[3] = SCB_BASE;
+	init_words[7] = SCB_BASE;
+
 	/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */
-#ifdef old
-	memcpy((void*)dev->mem_start+0xfff6, init_words, 10);
-#else
 	memcpy((void*)dev->mem_end-10, init_words, 10);
-#endif
+
 	/* Write the words at 0x0000. */
 	memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10);
 
@@ -776,7 +792,7 @@
 	/* Output the data buffer descriptor. */
 	*write_ptr++ = length | 0x8000;		/* Byte count parameter. */
 	*write_ptr++ = -1;					/* No next data buffer. */
-	*write_ptr++ = tx_block+22;			/* Buffer follows the NoOp command. */
+	*write_ptr++ = tx_block+22+SCB_BASE;/* Buffer follows the NoOp command. */
 	*write_ptr++ = 0x0000;				/* Buffer address high bits (always zero). */
 
 	/* Output the Loop-back NoOp command. */
@@ -796,10 +812,10 @@
 	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
 		lp->tx_head = TX_BUF_START;
 
-    if (net_debug > 4) {
+	if (net_debug > 4) {
 		printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",
 			   dev->name, ioaddr, length, tx_block, lp->tx_head);
-    }
+	}
 
 	if (lp->tx_head != lp->tx_reap)
 		dev->tbusy = 0;
@@ -893,6 +909,7 @@
  *  version-control: t
  *  kept-new-versions: 5
  *  tab-width: 4
+ *  c-indent-level: 4
  * End:
  */
 
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- 0.99pl15/linux/drivers/net/3c509.c	Wed Feb  2 17:30:02 1994
+++ linux/drivers/net/3c509.c	Tue Mar  8 07:40:10 1994
@@ -13,7 +13,7 @@
 	C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
 */
 
-static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n";
+static char *version = "3c509.c:pl15k 3/5/94 becker@super.org\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -190,7 +190,7 @@
 
 	{
 		char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
-		printk("%s: 3c509 at %#3.3x	 tag %d, %s port, address ",
+		printk("%s: 3c509 at %#3.3x tag %d, %s port, address ",
 			   dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
 	}
 
@@ -377,7 +377,7 @@
 		return 0;
 
 	if (el3_debug > 4) {
-		printk("%s: el3_start_xmit(lenght = %d) called, status %4.4x.\n",
+		printk("%s: el3_start_xmit(lenght = %ld) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
 	}
 #ifndef final_version
@@ -477,10 +477,12 @@
 		if (++i > 10) {
 			printk("%s: Infinite loop in interrupt, status %4.4x.\n",
 				   dev->name, status);
+			/* Clear all interrupts we have handled. */
+			outw(0x68FF, ioaddr + EL3_CMD);
 			break;
 		}
-		/* Clear the other interrupts we have handled. */
-		outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */
+		/* Acknowledge the IRQ. */
+		outw(0x6891, ioaddr + EL3_CMD); /* Ack IRQ */
 	}
 
 	if (el3_debug > 4) {
@@ -549,19 +551,19 @@
 			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
 	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
 		if (rx_status & 0x4000) { /* Error, update stats. */
-			short error = rx_status & 0x3C00;
+			short error = rx_status & 0x3800;
 			lp->stats.rx_errors++;
 			switch (error) {
-			case 0x2000:		lp->stats.rx_over_errors++; break;
-			case 0x2C00:		lp->stats.rx_length_errors++; break;
-			case 0x3400:		lp->stats.rx_crc_errors++; break;
-			case 0x2400:		lp->stats.rx_length_errors++; break;
-			case 0x3000:		lp->stats.rx_frame_errors++; break;
-			case 0x0800:		lp->stats.rx_frame_errors++; break;
+			case 0x0000:		lp->stats.rx_over_errors++; break;
+			case 0x0800:		lp->stats.rx_length_errors++; break;
+			case 0x1000:		lp->stats.rx_frame_errors++; break;
+			case 0x1800:		lp->stats.rx_length_errors++; break;
+			case 0x2000:		lp->stats.rx_frame_errors++; break;
+			case 0x2800:		lp->stats.rx_crc_errors++; break;
 			}
 		}
 		if ( (! (rx_status & 0x4000))
-			|| ! (rx_status & 0x2000)) { /* Dribble bits are OK. */
+			|| ! (rx_status & 0x1000)) { /* Dribble bits are OK. */
 			short pkt_len = rx_status & 0x7ff;
 			int sksize = sizeof(struct sk_buff) + pkt_len + 3;
 			struct sk_buff *skb;
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- 0.99pl15/linux/drivers/net/8390.c	Wed Feb  2 17:30:02 1994
+++ linux/drivers/net/8390.c	Tue Feb 22 08:12:27 1994
@@ -8,6 +8,8 @@
   incorporated herein by reference.
   
   This is the chip-specific code for many 8390-based ethernet adaptors.
+  This is not a complete driver, it must be combined with board-specific
+  code such as ne.c, wd.c, 3c503.c, etc.
   
   The Author may be reached as becker@super.org or
   C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
@@ -14,17 +16,14 @@
   */
 
 static char *version =
-    "8390.c:v0.99-13f 10/18/93 Donald Becker (becker@super.org)\n";
+    "8390.c:v0.99-15e 2/16/94 Donald Becker (becker@super.org)\n";
 #include <linux/config.h>
 
 /*
   Braindamage remaining:
+  Much of this code should be cleaned up post-1.00, but it has been
+  extensively beta tested in the current form.
   
-  Ethernet devices should use a chr_drv device interface, with ioctl()s to
-  configure the card, bring the interface up or down, allow access to
-  statistics, and maybe read() and write() access to raw packets.
-  This won't be done until after Linux 1.00.
-  
   Sources:
   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
   The NE* programming info came from the Crynwr packet driver, and figuring
@@ -59,11 +58,22 @@
 
 #include "8390.h"
 
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(addr, size) kfree_s(addr,size)
-#endif
-
+/* These are the operational function interfaces to board-specific
+   routines.
+	void reset_8390(struct device *dev)
+		Resets the board associated with DEV, including a hardware reset of
+		the 8390.  This is only called when there is a transmit timeout, and
+		it is always followed by 8390_init().
+	void block_output(struct device *dev, int count, const unsigned char *buf,
+					  int start_page)
+		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
+		"page" value uses the 8390's 256-byte pages.
+	int block_input(struct device *dev, int count, char *buf, int ring_offset)
+		Read COUNT bytes from the packet buffer into BUF.  Start reading from
+		RING_OFFSET, the address as the 8390 sees it.  The first read will
+		always be the 4 byte, page aligned 8390 header.  *If* there is a
+		subsequent read, it will be of the rest of the packet.
+*/
 #define ei_reset_8390 (ei_local->reset_8390)
 #define ei_block_output (ei_local->block_output)
 #define ei_block_input (ei_local->block_input)
@@ -75,14 +85,14 @@
 int ei_debug = 1;
 #endif
 
-/* Max number of packets received at one Intr. */
-/*static int high_water_mark = 0;*/
+/* Max number of packets received at one Intr.
+   Current this may only be examined by a kernel debugger. */
+static int high_water_mark = 0;
 
 /* Index to functions. */
-/* Put in the device structure. */
-int ei_open(struct device *dev);
-/* Dispatch from interrupts. */
-void ei_interrupt(int reg_ptr);
+int ei_open(struct device *dev);	/* Put into the device structure. */
+void ei_interrupt(int reg_ptr);		/* Installed as the interrupt handler. */
+
 static void ei_tx_intr(struct device *dev);
 static void ei_receive(struct device *dev);
 static void ei_rx_overrun(struct device *dev);
@@ -107,17 +117,11 @@
     
     if ( ! ei_local) {
 		printk("%s: Opening a non-existent physical device\n", dev->name);
-		return 1;		/* ENXIO would be more accurate. */
+		return ENXIO;
     }
     
     irq2dev_map[dev->irq] = dev;
     NS8390_init(dev, 1);
-    ei_local->tx1 = ei_local->tx2 = 0;
-    /* The old local flags... */
-    ei_local->txing = 0;
-    /* ... are now global. */
-    dev->tbusy = 0;
-    dev->interrupt = 0;
     dev->start = 1;
     ei_local->irqlock = 0;
     return 0;
@@ -128,31 +132,36 @@
     int e8390_base = dev->base_addr;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
     int length, send_length;
-    int tmp_tbusy;	  /* we must lock dev_tint in dev.c with dev->t_busy =1 */
-    /* because on a slow pc a quasi endless loop can appear */
     
+	/* We normally shouldn't be called if dev->tbusy is set, but the
+	   existing code does anyway.
+	   If it has been too long (> 100 or 150ms.) since the last Tx we assume
+	   the board has died and kick it. */
+
     if (dev->tbusy) {	/* Do timeouts, just like the 8003 driver. */
 		int txsr = inb(e8390_base+EN0_TSR), isr;
 		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < 5	||	(tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
+		if (tickssofar < 10	||	(tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
 			return 1;
 		}
 		isr = inb(e8390_base+EN0_ISR);
 		printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n",
 			   dev->name, txsr, isr);
-		/* It's possible to check for an IRQ conflict here.
-		   I may have to do that someday. */
+		/* Does the 8390 thinks it has posted an interrupt? */
 		if (isr)
-			printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq);
-		else
+			printk("%s: Possible IRQ conflict on IRQ%d?\n", dev->name, dev->irq);
+		else {
+			/* The 8390 probably hasn't gotten on the cable yet. */
 			printk("%s: Possible network cable problem?\n", dev->name);
-		/* It futile, but try to restart it anyway. */
+			ei_local->interface_num ^= 1; 	/* Try a different xcvr.  */
+		}
+		/* Try to restart the card.  Perhaps the user has fixed something. */
 		ei_reset_8390(dev);
 		NS8390_init(dev, 1);
-		printk("\n");
+		dev->trans_start = jiffies;
     }
     
-    /* This is new: it means some higher layer thinks we've missed an
+    /* Sending a NULL skb means some higher layer thinks we've missed an
        tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
        itself. */
     if (skb == NULL) {
@@ -167,28 +176,22 @@
     }
     skb->arp=1;
     
+    length = skb->len;
     if (skb->len <= 0)
 		return 0;
-    length = skb->len;
-    send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
-    /* Turn off interrupts so that we can put the packet out safely. */
-    cli();
-    if (dev->interrupt || ei_local->irqlock) {
-		/* We should never get here during an interrupt after 0.99.4. */
-		sti();
-		if (ei_debug > 2)
-			printk("%s: Attempt to reenter critical zone%s.\n",
-				   dev->name, ei_local->irqlock ? " during interrupt" : "");
+
+	/* Block a timer-based transmit from overlapping. */
+	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
 		return 1;
-    }
+	}
+
     /* Mask interrupts from the ethercard. */
     outb(0x00,	e8390_base + EN0_IMR);
-	
-    /* Atomically lock out dev.c:dev_tint(). */
-    tmp_tbusy = set_bit(0, (void*)&dev->tbusy);
-	
     ei_local->irqlock = 1;
-    sti();
+
+    send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+
     if (ei_local->pingpong) {
 		int output_page;
 		if (ei_local->tx1 == 0) {
@@ -205,23 +208,19 @@
 				printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
 					   dev->name, ei_local->tx1, ei_local->lasttx,
 					   ei_local->txing);
-		} else {
-			/* We can get to here if we get an rx interrupt and queued
-			   a tx packet just before masking 8390 irqs above. */
-			if (ei_debug > 2)
+		} else {	/* We should never get here. */
+			if (ei_debug)
 				printk("%s: No packet buffer space for ping-pong use.\n",
 					   dev->name);
-			cli();
 			ei_local->irqlock = 0;
-			dev->tbusy = tmp_tbusy;
+			dev->tbusy = 1;
 			outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-			sti();
 			return 1;
 		}
-		dev->trans_start = jiffies;
 		ei_block_output(dev, length, skb->data, output_page);
 		if (! ei_local->txing) {
 			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
@@ -229,25 +228,22 @@
 			ei_local->txing = 1;
 		} else
 			ei_local->txqueue++;
-		if (ei_local->tx1  &&  ei_local->tx2)
-			tmp_tbusy = 1;
-    } else {
-		dev->trans_start = jiffies;
-		ei_block_output(dev, length, skb->data,
-						ei_local->tx_start_page);
+
+		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);
 		NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
-		tmp_tbusy = 1;
-    }  /* PINGPONG */
+		dev->trans_start = jiffies;
+		dev->tbusy = 1;
+    }
     
+    /* Turn 8390 interrupts back on. */
+    ei_local->irqlock = 0;
+    outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
     if (skb->free)
 		kfree_skb (skb, FREE_WRITE);
     
-    /* Turn 8390 interrupts back on. */
-    cli();
-    outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-    ei_local->irqlock = 0;
-    dev->tbusy=tmp_tbusy;
-    sti();
     return 0;
 }
 
@@ -289,7 +285,7 @@
     
     /* !!Assumption!! -- we stay in page 0.	 Don't break this. */
     while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
-		   && ++boguscount < 20) {
+		   && ++boguscount < 5) {
 		if (interrupts & ENISR_RDC) {
 			/* Ack meaningless DMA complete. */
 			outb_p(ENISR_RDC, e8390_base + EN0_ISR);
@@ -374,24 +370,19 @@
 		ei_local->txing = 0;
 		dev->tbusy = 0;
     }
-    
-    /* Do the statistics _after_ we start the next TX. */
+
+    /* Minimize Tx latency: update the statistics after we restart TXing. */
+	if (status & ENTSR_COL) ei_local->stat.collisions++;
     if (status & ENTSR_PTX)
 		ei_local->stat.tx_packets++;
-    else
+    else {
 		ei_local->stat.tx_errors++;
-    if (status & ENTSR_COL)
-		ei_local->stat.collisions++;
-    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++;
+		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 (INET_BH);
 }
@@ -403,11 +394,11 @@
     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;
-    int boguscount = 0;
+    int rx_pkt_count = 0;
     struct e8390_pkt_hdr rx_frame;
     int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
     
-    while (++boguscount < 10) {
+    while (++rx_pkt_count < 10) {
 		int pkt_len;
 		
 		/* Get the rx page (incoming packet pointer). */
@@ -420,8 +411,9 @@
 		if (this_frame >= ei_local->stop_page)
 			this_frame = ei_local->rx_start_page;
 		
-		/* Someday we'll omit the previous step, iff we never get this message.*/
-		if (ei_debug > 0	&&	this_frame != ei_local->current_page)
+		/* Someday we'll omit the previous, iff we never get this message.
+		   (There is at least one clone claimed to have a problem.)  */
+		if (ei_debug > 0  &&  this_frame != ei_local->current_page)
 			printk("%s: mismatched read page pointers %2x vs %2x.\n",
 				   dev->name, this_frame, ei_local->current_page);
 		
@@ -439,46 +431,23 @@
 		/* Check for bogosity warned by 3c503 book: the status byte is never
 		   written.  This happened a lot during testing! This code should be
 		   cleaned up someday. */
-		if (	 rx_frame.next != next_frame
+		if (rx_frame.next != next_frame
 			&& rx_frame.next != next_frame + 1
 			&& rx_frame.next != next_frame - num_rx_pages
 			&& rx_frame.next != next_frame + 1 - num_rx_pages) {
-#ifndef EI_DEBUG
 			ei_local->current_page = rxing_page;
 			outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+			ei_local->stat.rx_errors++;
 			continue;
-#else
-			static int last_rx_bogosity = -1;
-			printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
-				   dev->name, rx_frame.status, rx_frame.next, rx_frame.count,
-				   current_offset);
-			
-			if (ei_local->stat.rx_packets != last_rx_bogosity) {
-				/* Maybe we can avoid resetting the chip... empty the packet ring. */
-				ei_local->current_page = rxing_page;
-				printk("%s:	setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
-					   dev->name, ei_local->current_page, next_frame,
-					   rx_frame.next, rx_frame.status);
-				last_rx_bogosity = ei_local->stat.rx_packets;
-				outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
-				continue;
-			} else {
-				/* Oh no Mr Bill! Last ditch error recovery. */
-				printk("%s: recovery failed, resetting at packet #%d..",
-					   dev->name, ei_local->stat.rx_packets);
-				sti();
-				ei_reset_8390(dev);
-				NS8390_init(dev, 1);
-				printk("restarting.\n");
-				return;
-			}
-#endif	/* EI8390_NOCHECK */
 		}
-		
-		if ((pkt_len < 46  ||  pkt_len > 1535) && ei_debug)
-			printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n",
-				   dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
-		if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
+
+		if (pkt_len < 60  ||  pkt_len > 1518) {
+			if (ei_debug)
+				printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+					   dev->name, rx_frame.count, rx_frame.status,
+					   rx_frame.next);
+			ei_local->stat.rx_errors++;
+		} else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
 			int sksize = sizeof(struct sk_buff) + pkt_len;
 			struct sk_buff *skb;
 			
@@ -495,37 +464,28 @@
 				skb->len = pkt_len;
 				skb->dev = dev;
 				
-				/* 'skb->data' points to the start of sk_buff data area. */
 				ei_block_input(dev, pkt_len, (char *) skb->data,
 							   current_offset + sizeof(rx_frame));
-#ifdef HAVE_NETIF_RX
 				netif_rx(skb);
-#else
-				skb->lock = 0;
-				if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev)) {
-					kfree_skbmem(skb, sksize);
-					lp->stats.rx_dropped++;
-					break;
-				}
-#endif
 				ei_local->stat.rx_packets++;
 			}
 		} else {
 			int errs = rx_frame.status;
 			if (ei_debug)
-				printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n",
-					   dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
+				printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+					   dev->name, rx_frame.status, rx_frame.next,
+					   rx_frame.count);
 			if (errs & ENRSR_FO)
 				ei_local->stat.rx_fifo_errors++;
 		}
 		next_frame = rx_frame.next;
 		
-		/* This should never happen, it's here for debugging. */
+		/* This _should_ never happen: it's here for avoiding bad clones. */
 		if (next_frame >= ei_local->stop_page) {
-			printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame);
+			printk("%s: next frame inconsistency, %#2x..", dev->name,
+				   next_frame);
 			next_frame = ei_local->rx_start_page;
 		}
-		ei_local->current_page += 1 + ((pkt_len+4)>>8);
 		ei_local->current_page = next_frame;
 		outb(next_frame-1, e8390_base+EN0_BOUNDARY);
     }
@@ -532,7 +492,11 @@
     /* If any worth-while packets have been received, dev_rint()
        has done a mark_bh(INET_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;
+
     /* Bug alert!  Reset ENISR_OVER to avoid spurious overruns! */
     outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);
     return;
@@ -553,12 +517,13 @@
 		printk("%s: Receiver overrun.\n", dev->name);
     ei_local->stat.rx_over_errors++;
     
-    /* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
+    /* The old Biro driver does dummy = inb_p( RBCR[01] ); at this point.
        It might mean something -- magic to speed up a reset?  A 8390 bug?*/
     
-    /* Wait for reset in case the NIC is doing a tx or rx.	This could take up to
-       1.5msec, but we have no way of timing something in that range.  The 'jiffies'
-       are just a sanity check. */
+    /* Wait for the reset to complete.	This should happen almost instantly,
+	   but could take up to 1.5msec in certain rare instances.  There is no
+	   easy way of timing something in that range, so we use 'jiffies' as
+	   a sanity check. */
     while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
 		if (jiffies - reset_start_time > 1) {
 			printk("%s: reset did not complete at ei_rx_overrun.\n",
@@ -565,7 +530,7 @@
 				   dev->name);
 			NS8390_init(dev, 1);
 			return;
-		};
+		}
     
     /* Remove packets right away. */
     ei_receive(dev);
@@ -713,6 +678,10 @@
     outb_p(ei_local->rx_start_page,	 e8390_base + EN1_CURPAG);
     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
     sti();
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    ei_local->tx1 = ei_local->tx2 = 0;
+    ei_local->txing = 0;
     if (startp) {
 		outb_p(0xff,  e8390_base + EN0_ISR);
 		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
@@ -751,6 +720,7 @@
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 8390.c"
  *  version-control: t
  *  kept-new-versions: 5
+ *  c-indent-level: 4
  *  tab-width: 4
  * End:
  */
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- 0.99pl15/linux/drivers/net/CONFIG	Fri Jan 28 09:32:24 1994
+++ linux/drivers/net/CONFIG	Tue Feb 22 08:40:09 1994
@@ -30,6 +30,9 @@
 #	  D_LINK_IO	The D-Link I/O address (0x378 == typical)
 #	  D_LINK_IRQ	The D-Link IRQ number to use (IRQ7 == typical)
 #	  D_LINK_DEBUG	Enable or disable D-Link debugging
+#  DEPCA		The DIGITAL series of AT Ethernet Cards (DE100, DE200)
+#	  DEPCA_IRQ	Set the desired IRQ (=0, for autoprobe)
+#	  DEPCA_DEBUG	Set the desired debug level
 #
 
 # The following options exist, but cannot be set in this file.
@@ -50,6 +53,7 @@
 NE_OPTS		=
 HP_OPTS		=
 PLIP_OPTS	=
+DEPCA_OPTS	= -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1
 
 # The following are the only parameters that must be set in this file.
 DL_OPTS		= -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- 0.99pl15/linux/drivers/net/Makefile	Thu Dec 16 12:24:12 1993
+++ linux/drivers/net/Makefile	Tue Feb 22 08:38:04 1994
@@ -105,6 +105,8 @@
 endif
 ifdef CONFIG_DEPCA
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o)
+depca.o: depca.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 endif
 ifdef CONFIG_ATP
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o)
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- 0.99pl15/linux/drivers/net/Space.c	Wed Dec  1 14:44:15 1993
+++ linux/drivers/net/Space.c	Fri Feb 18 11:18:28 1994
@@ -139,18 +139,15 @@
 #endif
 
 /* The first device defaults to I/O base '0', which means autoprobe. */
-#ifdef EI8390
-# define ETH0_ADDR EI8390
-#else
+#ifndef ETH0_ADDR
 # define ETH0_ADDR 0
 #endif
-#ifdef EI8390_IRQ
-# define ETH0_IRQ EI8390_IRQ
-#else
+#ifndef ETH0_IRQ
 # define ETH0_IRQ 0
 #endif
-/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe".
-   Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */
+/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
+   which means "don't probe".  These entries exist to only to provide empty
+   slots which may be enabled at boot-time. */
 
 static struct device eth3_dev = {
     "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- 0.99pl15/linux/drivers/net/at1700.c	Wed Feb  2 17:30:03 1994
+++ linux/drivers/net/at1700.c	Sun Mar  6 16:13:56 1994
@@ -12,7 +12,7 @@
 */
 
 static char *version =
-	"at1700.c:v0.03 11/16/93  Donald Becker (becker@super.org)\n";
+	"at1700.c:v0.06 3/3/94  Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 
@@ -19,6 +19,9 @@
 /*
   Sources:
     The Fujitsu MB86695 datasheet.
+
+	After this driver was written, ATI provided their EEPROM configuration
+	code header file.  Thanks to Gerry Sockins of ATI.
 */
 
 #include <linux/kernel.h>
@@ -30,12 +33,12 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/malloc.h>
+#include <linux/string.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <errno.h>
-#include <memory.h>
 
 #include "dev.h"
 #include "eth.h"
@@ -142,24 +145,28 @@
 
 	for (port = &ports[0]; *port; port++) {
 		int ioaddr = *port;
-#ifdef HAVE_PORTRESERVE
 		if (check_region(ioaddr, 32))
 			continue;
-#endif
-		if (inw(ioaddr) != 0x0000)
-			continue;
 		if (at1700_probe1(dev, ioaddr) == 0)
 			return 0;
 	}
 
-	return ENODEV;			/* ENODEV would be more accurate. */
+	return ENODEV;
 }
 
+/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
+   "signature", the default bit pattern after a reset.  This *doesn't* work --
+   there is no way to reset the bus interface without a complete power-cycle!
+
+   It turns out that ATI came to the same conclusion I did: the only thing
+   that can be done is checking a few bits and then diving right into an
+   EEPROM read. */
+
 int at1700_probe1(struct device *dev, short ioaddr)
 {
-	unsigned short signature[4]         = {0x0000, 0xffff, 0x41f6, 0xefb6};
-	unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00};
-	char irqmap[4] = {3, 4, 5, 9};
+	unsigned short signature[4]         = {0xffff, 0xffff, 0x7ff7, 0xff5f};
+	unsigned short signature_invalid[4] = {0xffff, 0xffff, 0x7ff7, 0xdf0f};
+	char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
 	unsigned short *station_address = (unsigned short *)dev->dev_addr;
 	unsigned int i, irq;
 
@@ -168,18 +175,21 @@
 	   */
 	for (i = 0; i < 4; i++)
 		if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) {
-			if (net_debug > 1)
+			if (net_debug > 2)
 				printk("AT1700 signature match failed at %d (%04x vs. %04x)\n",
 					   i, inw(ioaddr + 2*i), signature[i]);
 			return -ENODEV;
 		}
-#ifdef HAVE_PORTRESERVE
+	if (read_eeprom(ioaddr, 4) != 0x0000
+		|| read_eeprom(ioaddr, 5) & 0x00ff != 0x00F4)
+		return -ENODEV;
+
 	/* Grab the region so that we can find another board if the IRQ request
 	   fails. */
 	snarf_region(ioaddr, 32);
-#endif
 
-	irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ];
+	irq = irqmap[(read_eeprom(ioaddr, 12)&0x04)
+				 | (read_eeprom(ioaddr, 0)>>14)];
 
 	/* Snarf the interrupt vector now. */
 	if (request_irq(irq, &net_interrupt)) {
@@ -417,10 +427,6 @@
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
 
-		if (net_debug > 4)
-			printk("%s: Transmitting a packet of length %d.\n", dev->name,
-				   skb->len);
-
 		/* Turn off the possible Tx interrupts. */
 		outb(0x00, ioaddr + TX_INTR);
 		
@@ -551,7 +557,6 @@
 			skb->len = pkt_len;
 			skb->dev = dev;
 
-			/* 'skb->data' points to the start of sk_buff data area. */
 			insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1);
 
 			if (net_debug > 5) {
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- 0.99pl15/linux/drivers/net/atp.c	Wed Feb  2 17:40:40 1994
+++ linux/drivers/net/atp.c	Tue Mar  1 19:29:05 1994
@@ -12,7 +12,7 @@
 */
 
 static char *version =
-	"atp.c:v0.03 1/19/94 Donald Becker (becker@super.org)\n";
+	"atp.c:v0.04 2/25/94 Donald Becker (becker@super.org)\n";
 
 /*
 	This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket
@@ -611,7 +611,7 @@
 		} else if (num_tx_since_rx > 8
 				   && jiffies > dev->last_rx + 100) {
 			if (net_debug > 2)
-				printk("%s: Missed packet? No Rx after %d Tx and %d jiffies"
+				printk("%s: Missed packet? No Rx after %d Tx and %ld jiffies"
 					   " status %02x  CMR1 %02x.\n", dev->name,
 					   num_tx_since_rx, jiffies - dev->last_rx, status,
 					   (read_nibble(ioaddr, CMR1) >> 3) & 15);
@@ -623,6 +623,8 @@
 			break;
     }
 
+	/* This following code fixes a rare (and very difficult to track down)
+	   problem where the adaptor forgets its ethernet address. */
 	{
 		int i;
 		for (i = 0; i < 6; i++)
@@ -686,12 +688,12 @@
 		skb->len = pkt_len;
 		skb->dev = dev;
 		
-		/* 'skb->data' points to the start of sk_buff data area. */
 		read_block(ioaddr, pkt_len, skb->data, dev->if_port);
 
 		if (net_debug > 6) {
 			unsigned char *data = skb->data;
-			printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..",
+			printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x"
+				   "%02x%02x%02x %02x%02x..",
 				   data[0], data[1], data[2], data[3], data[4], data[5],
 				   data[6], data[7], data[8], data[9], data[10], data[11],
 				   data[12], data[13]);
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- 0.99pl15/linux/drivers/net/depca.c
+++ linux/drivers/net/depca.c	Fri Mar  4 09:20:19 1994
@@ -0,0 +1,1362 @@
+/*  depca.c: A DIGITAL DEPCA ethernet driver for linux.
+
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 David C. Davies and United States Government as
+    represented by the Director, National Security Agency.  This software
+    may be used and distributed according to the terms of the GNU Public
+    License, incorporated herein by reference.
+
+    This driver is written for the Digital Equipment Corporation series
+    of DEPCA ethernet cards:
+
+    	DE100 DEPCA
+	DE200 DEPCA Turbo
+	DE202 DEPCA Turbo (TP BNC)
+	DE210 DEPCA
+
+    The driver has been tested on DE100 and DE20x cards in a relatively busy 
+    network.
+
+    The author may be reached as davies@wanton.enet.dec.com or
+    Digital Equipment Corporation, 146 Main Street, Maynard MA 01754.
+
+    =========================================================================
+    The driver was based on the 'lance.c' driver from Donald Becker which is
+    included with the standard driver distribution for linux. Modifications
+    were made to most routines and the hardware recognition routines were
+    written from scratch. Primary references used were:
+
+    1) Lance.c code in /linux/drivers/net/
+    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
+       AMD, 1992 [(800) 222-9323].
+    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
+       AMD, Pub. #17881, May 1993.
+    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
+       AMD, Pub. #16907, May 1992
+    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
+    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
+    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
+       Digital Equipment Corporation, 1989
+    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
+    
+    Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
+    The hash filter code was  derived from Reference  3 and has been  tested
+    only to the extent that the Table  A-1, page A-7,  was confirmed to fill
+    the   filter bit   positions  correctly.  Hash   filtering  is  not  yet
+    implemented in the current driver set.
+
+    The  DE200 series boards have   on-board 64kB RAM  for  use as a  shared
+    memory network buffer. Only  the DE100 cards  make  use of a  2kB buffer
+    mode  which has not  been implemented in  this driver (only the 32kB and
+    64kB modes are supported).
+
+    At the  most only 2 DEPCA  cards can be supported  because there is only
+    provision for two I/O base addresses on the cards (0x300 and 0x200). The
+    base  address is  'autoprobed' by  looking  for  the self  test PROM and
+    detecting the  card name.  The shared memory  base address is decoded by
+    'autoprobing' the Ethernet PROM address information. The second DEPCA is
+    detected and information placed  in the base_addr  variable of the  next
+    device  structure   (which is created    if  necessary),  thus  enabling
+    ethif_probe initialization for the device.
+
+    ************************************************************************
+
+    NOTE: If you are using two  DEPCAs, it is important  that you assign the
+    base memory addresses  correctly.  The driver  autoprobes I/O 0x300 then
+    0x200.  The base memory  address for the  first device must be less than
+    that of the second so that the auto probe will  correctly assign the I/O
+    and  memory addresses on  the same card.  I can't  think of  a way to do
+    this unambiguously at the moment, since there is nothing on the cards to
+    tie I/O and memory information together.
+
+    I   am unable to test    2 DEPCAs together for   now,   so this code  is
+    unchecked. All reports, good or bad, are welcome.
+
+    ************************************************************************
+
+    The board IRQ  setting must be  at  an unused  IRQ  which is auto-probed
+    using   Donald Becker's   autoprobe   routines. DE100   board IRQs   are
+    {2,3,4,5,7}, whereas  the DE200 is at  {5,9,10,11,15}. Note that IRQ2 is
+    really IRQ9 in machines with 16 IRQ lines.
+
+    No 16MB memory  limitation should exist with this  driver as DMA is  not
+    used and the common memory area is in low memory on the network card (my
+    current system has 20MB and I've not had problems yet).
+
+    The DE203,  DE204  and DE205 cards  may  also work  with this driver  (I
+    haven't tested  them so I don't  know). If you have  one of these cards,
+    place the name in the DEPCA_SIGNATURE string  around line 160, recompile
+    the kernel and reboot. Check if the card  is recognised and works - mail
+    me if so, so that I can add it into the list of supported cards!
+
+    TO DO:
+    ------
+
+    1. Implement the 2k buffer mode - does anyone need it??
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1   25-jan-94     Initial writing
+      0.2   27-jan-94     Added LANCE TX buffer chaining
+      0.3    1-feb-94     Added multiple DEPCA support
+      0.31   4-feb-94     Added DE202 recognition
+      0.32  19-feb-94     Tidy up. Improve multi-DEPCA support.
+
+    =========================================================================
+*/
+
+static char *version = "depca.c:v0.32 2/19/94 davies@wanton.enet.dec.com\n";
+
+#include <stdarg.h>
+#include <linux/config.h>
+#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 <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+#include "depca.h"
+
+#ifdef DEPCA_DEBUG
+int depca_debug = DEPCA_DEBUG;
+#else
+int depca_debug = 1;
+#endif
+
+#ifndef DEPCA_IRQ
+/*#define DEPCA_IRQ	{5,9,10,11,15,0}*/
+#define DEPCA_IRQ	5
+#endif
+
+#ifndef PROBE_LENGTH
+#define PROBE_LENGTH    32
+#endif
+
+#ifndef PROBE_SEQUENCE
+#define PROBE_SEQUENCE "FF0055AAFF0055AA"
+#endif
+
+#ifndef DEPCA_SIGNATURE
+#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE202","DE210",""}
+#define DEPCA_NAME_LENGTH 8
+#endif
+
+#ifndef DEPCA_RAM_BASE_ADDRESSES
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#endif
+static short mem_chkd = 0;               /* holds which base addrs have been */
+					 /* checked, for multi-DEPCA case */
+
+#ifndef DEPCA_IO_PORTS
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#endif
+
+#ifndef DEPCA_TOTAL_SIZE
+#define DEPCA_TOTAL_SIZE 0x10
+#endif
+
+#ifndef MAX_NUM_DEPCAS
+#define MAX_NUM_DEPCAS 2
+#endif
+
+/*
+** Set the number of Tx and Rx buffers. 
+*/
+#ifndef DEPCA_BUFFER_LOG_SZ
+#define RING_SIZE	16              /* 16 buffers */
+#else
+#define RING_SIZE	(1 << (DEPCA_BUFFERS_LOG_SZ))
+#endif  /* DEPCA_BUFFER_LOG_SZ */
+
+#define PKT_BUF_SZ	1544            /* Buffer size for each Tx/Rx buffer */
+#define PKT_SZ   	1514            /* Maximum ethernet packet length */
+#define DAT_SZ   	1500            /* Maximum ethernet data length */
+#define PKT_HDR_LEN     14              /* Addresses and data length info */
+
+#ifdef HAVE_MULTICAST
+#ifndef CRC_POLYNOMIAL
+#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
+#endif /* CRC_POLYNOMIAL */
+#endif /* HAVE_MULTICAST */
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif  /* HAVE_ALLOC_SKB */
+
+/*
+** The DEPCA Rx and Tx ring descriptors. 
+*/
+struct depca_rx_head {
+    long base;
+    short buf_length;		/* This length is negative 2's complement! */
+    short msg_length;		/* This length is "normal". */
+};
+
+struct depca_tx_head {
+    long base;
+    short length;		/* This length is negative 2's complement! */
+    short misc;                 /* Errors and TDR info */
+};
+
+struct depca_ring_info {
+};
+
+/*
+** The Lance initialization block, described in databook, in common memory.
+*/
+struct depca_init {
+    unsigned short mode;	/* Mode register */
+    unsigned char phys_addr[ETH_ALEN];	/* Physical ethernet address */
+    unsigned short filter[4];	/* Multicast filter. */
+    unsigned long rx_ring;     	/* Rx ring base pointer & ring length */
+    unsigned long tx_ring;	/* Tx ring base pointer & ring length */
+};
+
+struct depca_private {
+    char devname[8];            /* Not used */
+    struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
+    struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
+    struct depca_init	init_block;/* Initialization block */
+    long dma_buffs;		/* Start address of Rx and Tx buffers. */
+    int	cur_rx, cur_tx;		/* The next free ring entry */
+    int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+    int dma;
+    struct enet_statistics stats;
+    char old_depca;
+    short ringSize;             /* ring size based on available memory */
+    short rmask;                /* modulus mask based on ring size */
+    long rlen;                  /* log2(ringSize) for the descriptors */
+};
+
+/*
+** Public Functions
+*/
+static int depca_open(struct device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void depca_interrupt(int reg_ptr);
+static int depca_close(struct device *dev);
+static struct enet_statistics *depca_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+/*
+** Private functions
+*/
+static int depca_probe1(struct device *dev, short ioaddr);
+static void depca_init_ring(struct device *dev);
+static int depca_rx(struct device *dev);
+static int depca_tx(struct device *dev);
+
+static void LoadCSRs(struct device *dev);
+static int InitRestartDepca(struct device *dev);
+static char *DepcaSignature(unsigned long mem_addr);
+static int DevicePresent(short ioaddr);
+#ifdef HAVE_MULTICAST
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
+#endif
+
+static int num_depcas = 0, num_eth = 0;;
+
+/*
+** Miscellaneous defines...
+*/
+#define STOP_DEPCA \
+    outw(CSR0, DEPCA_ADDR);\
+    outw(STOP, DEPCA_DATA)
+
+
+
+int depca_probe(struct device *dev)
+{
+    int *port, ports[] = DEPCA_IO_PORTS;
+    int base_addr = dev->base_addr;
+    int status;
+    struct device *eth0 = (struct device *) NULL;
+
+    if (base_addr > 0x1ff) {	      /* Check a single specified location. */
+		status = depca_probe1(dev, base_addr);
+    } else if (base_addr > 0) {	      /* Don't probe at all. */
+		status = -ENXIO;
+    } else {                          /* First probe for the DEPCA test */
+                                      /* pattern in ROM */
+
+      for (status = -ENODEV, port = &ports[0]; 
+	                    *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
+	int ioaddr = *port;
+
+#ifdef HAVE_PORTRESERVE
+	if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
+	    continue;
+#endif
+	if (DevicePresent(DEPCA_PROM) == 0) {
+	  if (num_depcas > 0) {        /* only gets here in autoprobe */
+
+	    /*
+	    ** Check the device structures for an end of list or unused device
+	    */
+	    while (dev->next != (struct device *)NULL) {
+	      if (dev->next->base_addr == 0xffe0) break;
+	      dev = dev->next;         /* walk through eth device list */
+	      num_eth++;               /* increment eth device number */
+	    }
+
+	    /*
+	    ** If no more device structures, malloc one up. If memory could
+	    ** not be allocated, print an error message.
+	    ** 
+	    */
+	    if (dev->next == (struct device *)NULL) {
+	      dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+                                                                  GFP_KERNEL);
+	    } else {
+	      printk("eth%d: Device not initialised, insufficient memory\n",
+		                                                      num_eth);
+	    }
+
+	    /*
+	    ** If the memory was allocated, point to the new memory area
+	    ** and initialize it (name, I/O address, next device (NULL) and
+	    ** initialisation probe routine).
+	    */
+	    if ((dev->next != (struct device *)NULL) &&
+		(num_eth > 0) && (num_eth < 9999)) {
+	      dev = dev->next;         /* point to the new device */
+	      dev->name = (char *)(dev + sizeof(struct device));
+	      sprintf(dev->name,"eth%d", num_eth); /* New device name */
+	      dev->base_addr = ioaddr; /* assign the io address */
+	      dev->next = (struct device *)NULL; /* mark the end of list */
+	      dev->init = &depca_probe;/* initialisation routine */
+	    }
+	  } else {
+	    eth0 = dev;                /* remember the first device */
+	    status = depca_probe1(dev, ioaddr);
+	  }
+	  num_depcas++;
+	  num_eth++;
+	}
+      }
+      if (eth0) dev = eth0;             /* restore the first device */
+    }
+
+    if (status) dev->base_addr = base_addr;
+
+    return status;			/* ENODEV would be more accurate. */
+}
+
+static int
+depca_probe1(struct device *dev, short ioaddr)
+{
+    struct depca_private *lp;
+    int i,j, status=0;
+    unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+    char *name=(char *)NULL;
+    int nicsr, offset;
+
+
+    /*
+    ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot
+    */
+    STOP_DEPCA;
+
+    nicsr = inw(DEPCA_NICSR);
+    nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+    outw(nicsr, DEPCA_NICSR);
+
+    if (inw(DEPCA_DATA) == STOP) {
+
+    /* Now find out what kind of DEPCA we have. The DE100 uses a different
+    ** addressing scheme for some registers compared to the DE2xx series.
+    ** Note that a base address location is marked as checked if no DEPCA is
+    ** there or one is found (when the search is immediately terminated). This
+    ** shortens the search time a little for multiple DEPCAs.
+    */
+
+      for (j = 0, i = 0; mem_base[i] && (j == 0);) {
+	if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
+	  name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
+	  mem_chkd |= (0x01 << i);           /* mark location checked */
+	  if (*name != (char)NULL) {         /* one found? */
+	    j = 1;                           /* set exit flag */
+	  } else {
+	    i++;                             /* increment search index */
+	  }
+	}
+      }
+
+      if (*name != (char)NULL) {          /* found a DEPCA device */
+	mem_start = mem_base[i];
+	dev->base_addr = ioaddr;
+
+	printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name);
+
+      /* There is a 32 byte station address PROM at DEPCA_PROM address.
+	 The first six bytes are the station address. They can be read
+	 directly since the signature search set up the ROM address 
+	 counter correctly just before this function.
+
+	 For the DE100 we have to be careful about which port is used to
+	 read the ROM info.
+      */
+
+	if (strstr(name,"DE100")!=(char *)NULL) {
+	  j = 1;
+	} else {
+	  j = 0;
+	}
+
+	printk("ethernet address ");
+	for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
+	  printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+	}
+	printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+
+	for (;i<32;i++) {                /* leave ROM counter in known state */
+	  j=inb(DEPCA_PROM);
+	}
+
+#ifdef HAVE_PORTRESERVE
+	snarf_region(ioaddr, DEPCA_TOTAL_SIZE);
+#endif
+
+	/* 
+	 ** Determine the base address for the DEPCA RAM from the NI-CSR
+	 ** and make up a DEPCA-specific-data structure. 
+        */
+
+	if (nicsr & BUF) {
+	  offset = 0x8000;              /* 32kbyte RAM */
+	  nicsr &= ~BS;                 /* DEPCA RAM in top 32k */
+	  printk(",\n      with 32kB RAM");
+	} else {
+	  offset = 0x0000;              /* 64kbyte RAM */
+	  printk(",\n      with 64kB RAM");
+	}
+
+	mem_start += offset;
+	printk(" starting at 0x%.5lx", mem_start);
+
+	/*
+	 ** Enable the shadow RAM.
+	*/
+	nicsr |= SHE;
+	outw(nicsr, DEPCA_NICSR);
+ 
+	/*
+	** Calculate the ring size based on the available RAM
+	** found above. Allocate an equal number of buffers, each
+	** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx. Make sure
+	** that this ring size is <= RING_SIZE. The ring size must be
+	** a power of 2.
+	*/
+
+	j = ((0x10000 - offset) / PKT_BUF_SZ) >> 1;
+	for (i=0;j>1;i++) {
+	  j >>= 1;
+	}
+
+	/* Hold the ring size information here before the depca
+	** private structure is allocated. Need this for the memory
+	** space calculations.
+	*/
+	j = 1 << i;
+
+	/*
+	** Set up memory information in the device structure.
+	** Align the descriptor rings on an 8 byte (quadword) boundary.
+	**
+	**     depca_private area
+	**     rx ring descriptors
+	**     tx ring descriptors
+	**     rx buffers
+	**     tx buffers
+	**
+	*/
+
+	/* private area & initialise */
+	dev->priv = (void *)((mem_start + 0x07) & ~0x07);      
+	lp = (struct depca_private *)dev->priv;
+	memset(dev->priv, 0, sizeof(struct depca_private));
+
+	/* Tx & Rx descriptors (aligned to a quadword boundary) */
+	mem_start = ((((unsigned long)dev->priv + 
+		        sizeof(struct depca_private)) +
+			(unsigned long)0x07) & (unsigned long)~0x07);
+	lp->rx_ring = (struct depca_rx_head *)mem_start;
+
+	mem_start += (sizeof(struct depca_rx_head) * j);
+	lp->tx_ring = (struct depca_tx_head *)mem_start;
+
+	mem_start += (sizeof(struct depca_tx_head) * j);
+	lp->dma_buffs = mem_start & 0x00ffffff;
+
+	mem_start += (PKT_BUF_SZ * j);
+	/* (mem_start now points to the start of the Tx buffers) */
+
+	/* Initialise the data structures */
+	memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
+	memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
+
+	/* This should never happen. */
+	if ((int)(lp->rx_ring) & 0x07) {
+	  printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
+	  return -ENXIO;
+	}
+
+	/*
+	** Finish initialising the ring information.
+	*/
+	lp->ringSize = j;
+	if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
+	lp->rmask = lp->ringSize - 1;
+
+	/*
+	** calculate the real RLEN size for the descriptors. It is
+	** log2(ringSize).
+	*/
+	for (i=0, j = lp->ringSize; j>1; i++) {
+	  j >>= 1;
+	}
+	lp->rlen = (unsigned long)(i << 29);
+
+	/*
+	** load the initialisation block
+	*/
+	depca_init_ring(dev);
+
+	/*
+	** Initialise the control and status registers
+	*/
+	LoadCSRs(dev);
+
+	/*
+	** Enable DEPCA board interrupts for autoprobing
+	*/
+	nicsr = ((nicsr & ~IM)|IEN);
+	outw(nicsr, DEPCA_NICSR);
+
+	/* The DMA channel may be passed in on this parameter. */
+	dev->dma = 0;
+	
+	/* To auto-IRQ we enable the initialization-done and DMA err,
+	 interrupts. For now we will always get a DMA error. */
+	if (dev->irq < 2) {
+	  autoirq_setup(0);
+
+	  /* Trigger an initialization just for the interrupt. */
+	  outw(INEA | INIT, DEPCA_DATA);
+	  
+	  dev->irq = autoirq_report(1);
+	  if (dev->irq) {
+	    printk(" and probed IRQ%d.\n", dev->irq);
+	  } else {
+	    printk(". Failed to detect IRQ line.\n");
+	    status = -EAGAIN;
+	  }
+	} else {
+	  printk(". Assigned IRQ%d.\n", dev->irq);
+	}
+      } else {
+	status = -ENXIO;
+      }
+      if (!status) {
+	if (depca_debug > 0) {
+	  printk(version);
+	}
+
+	/* The DEPCA-specific entries in the device structure. */
+	dev->open = &depca_open;
+	dev->hard_start_xmit = &depca_start_xmit;
+	dev->stop = &depca_close;
+	dev->get_stats = &depca_get_stats;
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_multicast_list;
+#endif
+
+	dev->mem_start = 0;
+	
+	/* Fill in the generic field of the device structure. */
+	for (i = 0; i < DEV_NUMBUFFS; i++) {
+	  dev->buffs[i] = NULL;
+	}
+
+	dev->hard_header     = eth_header;
+	dev->add_arp	     = eth_add_arp;
+	dev->queue_xmit	     = dev_queue_xmit;
+	dev->rebuild_header  = eth_rebuild_header;
+	dev->type_trans	     = eth_type_trans;
+	
+	dev->type	     = ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu	     = 1500; /* eth_mtu */
+	dev->addr_len	     = ETH_ALEN;
+
+	for (i = 0; i < dev->addr_len; i++) {
+	  dev->broadcast[i]=0xff;
+	}
+	
+	/* New-style flags. */
+	dev->flags	     = IFF_BROADCAST;
+	dev->family	     = AF_INET;
+	dev->pa_addr	     = 0;
+	dev->pa_brdaddr	     = 0;
+	dev->pa_mask	     = 0;
+	dev->pa_alen	     = sizeof(unsigned long);
+      }
+    } else {
+      status = -ENXIO;
+    }
+
+    return status;
+}
+
+
+static int
+depca_open(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int i,nicsr,ioaddr = dev->base_addr;
+
+    if (request_irq(dev->irq, &depca_interrupt)) {
+        printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
+	return -EAGAIN;
+    }
+
+    irq2dev_map[dev->irq] = dev;
+
+    /*
+    ** Stop the DEPCA & get the board status information.  
+    */
+    STOP_DEPCA;
+    nicsr = inw(DEPCA_NICSR);
+
+    /* 
+    ** Re-initialize the DEPCA... 
+    */
+    depca_init_ring(dev);                 /* initialize the descriptor rings */
+    LoadCSRs(dev);
+
+    if (depca_debug > 1){
+      printk("%s: depca open with irq %d\n",dev->name,dev->irq);
+      printk("Descriptor head addresses:\n");
+      printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+      printk("Descriptor addresses:\n");
+      for (i=0;i<lp->ringSize;i++){
+	printk("\t0x%8.8lx  0x%8.8lx\n",(long)&lp->rx_ring[i].base,
+	                                (long)&lp->tx_ring[i].base);
+      }
+      printk("Buffer addresses:\n");
+      for (i=0;i<lp->ringSize;i++){
+	printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring[i].base,
+                                        (long)lp->tx_ring[i].base);
+      }
+      printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
+      printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+      printk("\tphysical address: ");
+      for (i=0;i<6;i++){
+	printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+      }
+      printk("\n\tlogical address filter: 0x");
+      for (i=0;i<4;i++){
+	printk("%2.2x",(short)lp->init_block.filter[i]);
+      }
+      printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
+      printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
+      printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
+      printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n", 
+                                         (short)lp->ringSize, 
+                                          (char)lp->rmask,
+                                          (long)lp->rlen);
+      outw(CSR2,DEPCA_ADDR);
+      printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
+      outw(CSR1,DEPCA_ADDR);
+      printk("%4.4x\n",inw(DEPCA_DATA));
+      outw(CSR3,DEPCA_ADDR);
+      printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
+    }
+
+    /*
+    ** Enable DEPCA board interrupts
+    */
+    nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN);
+    outw(nicsr, DEPCA_NICSR);
+    outw(CSR0,DEPCA_ADDR);
+
+    dev->tbusy = 0;                         
+    dev->interrupt = 0;
+    dev->start = 1;
+
+    InitRestartDepca(dev);                /* ignore the return status */
+
+    if (depca_debug > 1){
+      printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
+      printk("nicsr: 0x%4.4x\n",inw(DEPCA_NICSR));
+    }
+
+    return 0;			          /* Always succeed */
+}
+
+/* Initialize the lance Rx and Tx descriptor rings. */
+static void
+depca_init_ring(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    unsigned long i;
+
+    lp->init_block.mode = DTX | DRX;	     /* Disable Rx and Tx. */
+    lp->cur_rx = lp->cur_tx = 0;
+    lp->dirty_rx = lp->dirty_tx = 0;
+
+    /* Initialize the base addresses and length of each buffer in the ring */
+    for (i = 0; i < lp->ringSize; i++) {
+	lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
+	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+	lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
+	                                           (unsigned long)(0x00ffffff);
+    }
+
+    /* Set up the initialization block */
+    for (i = 0; i < ETH_ALEN; i++) {
+      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    }
+    for (i = 0; i < 4; i++) {
+      lp->init_block.filter[i] = 0x0000;
+    }
+    lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen;
+    lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen;
+
+    lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */ 
+}
+
+/* 
+** Writes a socket buffer to TX descriptor ring and starts transmission 
+*/
+static int
+depca_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    int status = 0;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+      int tickssofar = jiffies - dev->trans_start;
+      if (tickssofar < 5) {
+	status = -1;
+      } else {
+	STOP_DEPCA;
+	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	       dev->name, inw(DEPCA_DATA));
+	
+	depca_init_ring(dev);
+	LoadCSRs(dev);
+	InitRestartDepca(dev);
+	dev->tbusy=0;
+	dev->trans_start = jiffies;
+      }
+      return status;
+    }
+
+    if (skb == NULL) {
+	dev_tint(dev);
+	return 0;
+    }
+
+    /* Fill in the ethernet header. */
+    if (!skb->arp  &&  dev->rebuild_header(skb->data, dev)) {
+	skb->dev = dev;
+	arp_queue (skb);
+	return 0;
+    }
+    skb->arp=1;
+
+    if (skb->len <= 0) {
+      return 0;
+    }
+
+    if (depca_debug > 3) {
+	outw(CSR0, DEPCA_ADDR);
+	printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
+	       inw(DEPCA_DATA));
+    }
+
+    /* Block a timer-based transmit from overlapping.  This could better be
+       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (set_bit(0, (void*)&dev->tbusy) != 0)
+	printk("%s: Transmitter access conflict.\n", dev->name);
+
+    /*
+    ** The TX buffer, skb, has to be copied into the local network RAM
+    ** for the LANCE to access it. The skb may be at > 16MB for large 
+    ** (memory) systems.
+    */
+    {				/* Fill in a Tx ring entry */
+      unsigned char *buf;
+      int entry = lp->cur_tx++;
+      int len;
+      long skbL = skb->len;
+      char *p = (char *) skb->data;
+
+      entry &= lp->rmask;  		    /* Ring around buffer number. */
+      buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+      /* Wait for a full ring to free up */
+      while (lp->tx_ring[entry].base < 0);
+
+      /* 
+      ** Caution: the write order is important here... don't set up the
+      ** ownership rights until all the other information is in place.
+      */
+      len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
+      if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
+      skbL -= len;
+      lp->tx_ring[entry].length = -len;
+
+      /* Clears various error flags */
+      lp->tx_ring[entry].misc = 0x0000;
+
+      /* copy the data from the socket buffer to the net memory */
+      memcpy((unsigned char *)(buf), skb->data, len);
+
+      /* Hand over buffer ownership to the LANCE */
+      if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
+      lp->tx_ring[entry].base |= (T_OWN|T_STP);
+
+      /* Trigger an immediate send demand. */
+      outw(CSR0, DEPCA_ADDR);
+      outw(INEA | TDMD, DEPCA_DATA);
+
+      dev->trans_start = jiffies;
+
+      for (p += len; skbL > 0; p += len) {
+
+	/* Get new buffer pointer */
+	entry = lp->cur_tx++;
+	entry &= lp->rmask;  		    /* Ring around buffer number. */
+	buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+	/* Wait for a full ring to free up */
+	while (lp->tx_ring[entry].base < 0);
+	dev->tbusy=0;
+
+	/* Copy ethernet header to the new buffer */
+	memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN);
+
+	/* Determine length of data buffer */
+	len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
+	if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
+	skbL -= len;
+	lp->tx_ring[entry].length = -len;
+
+	/* Clears various error flags */
+	lp->tx_ring[entry].misc = 0x0000;
+
+	/* copy the data from the socket buffer to the net memory */
+	memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
+
+	/* Hand over buffer ownership to the LANCE */
+	if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
+	lp->tx_ring[entry].base |= T_OWN;
+      }
+
+      if (depca_debug > 4) {
+	unsigned char *pkt =
+	  (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+	printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
+	       dev->name, entry, (unsigned long) &lp->tx_ring[entry],
+	       lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
+	printk("%s:  Tx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
+	       dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
+	       pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
+	       pkt[14], pkt[15]);
+      }
+      
+      /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
+      if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
+	dev->tbusy=0;
+      }
+
+      if (skb->free) {
+	kfree_skb (skb, FREE_WRITE);
+      }
+    }
+
+    return 0;
+}
+
+/*
+** The DEPCA interrupt handler. 
+*/
+static void
+depca_interrupt(int reg_ptr)
+{
+    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
+    struct depca_private *lp;
+    int csr0, ioaddr, nicsr;
+
+    if (dev == NULL) {
+	printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+	return;
+    } else {
+      lp = (struct depca_private *)dev->priv;
+      ioaddr = dev->base_addr;
+    }
+
+    if (dev->interrupt)
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+    dev->interrupt = MASK_INTERRUPTS;
+
+    /* mask the DEPCA board interrupts and turn on the LED */
+    nicsr = inw(DEPCA_NICSR);
+    nicsr |= (IM|LED);
+    outw(nicsr, DEPCA_NICSR);
+
+    outw(CSR0, DEPCA_ADDR);
+    csr0 = inw(DEPCA_DATA);
+
+    /* Acknowledge all of the current interrupt sources ASAP. */
+    outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+
+    if (depca_debug > 5)
+	printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+	       dev->name, csr0, inw(DEPCA_DATA));
+
+    if (csr0 & RINT)		/* Rx interrupt (packet arrived) */
+	depca_rx(dev);
+
+    if (csr0 & TINT) 	        /* Tx interrupt (packet sent) */
+        depca_tx(dev);
+
+    /* Clear the interrupts we've handled. */
+    outw(CSR0, DEPCA_ADDR);
+    outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+
+    if (depca_debug > 4) {
+      printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+	     dev->name, inw(DEPCA_ADDR),
+	     inw(DEPCA_DATA));
+    }
+
+    /* Unmask the DEPCA board interrupts and turn off the LED */
+    nicsr = (nicsr & ~IM & ~LED);
+    outw(nicsr, DEPCA_NICSR);
+
+    dev->interrupt = UNMASK_INTERRUPTS;
+    return;
+}
+
+static int
+depca_rx(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int entry = lp->cur_rx & lp->rmask;
+
+    /* If we own the next entry, it's a new packet. Send it up. */
+    for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
+	int status = lp->rx_ring[entry].base >> 16 ;
+
+	if (status & R_ERR) {	       /* There was an error. */
+	    lp->stats.rx_errors++;     /* Update the error stats. */
+	    if (status & R_FRAM) lp->stats.rx_frame_errors++;
+	    if (status & R_OFLO) lp->stats.rx_over_errors++;
+	    if (status & R_CRC)  lp->stats.rx_crc_errors++;
+	    if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+	} else {	  /* Malloc up new buffer, compatible  with net-2e. */
+	    short pkt_len = lp->rx_ring[entry].msg_length;
+	    int sksize = sizeof(struct sk_buff) + pkt_len;
+	    struct sk_buff *skb;
+
+	    skb = alloc_skb(sksize, GFP_ATOMIC);
+	    if (skb == NULL) {
+		printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+		lp->stats.rx_dropped++;	/* Really, deferred. */
+		break;
+	    }
+	    skb->mem_len = sksize;
+	    skb->mem_addr = skb;
+	    skb->len = pkt_len;
+	    skb->dev = dev;
+	    memcpy(skb->data,
+		   (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
+		   pkt_len);
+	    /* 
+	    ** Notify the upper protocol layers that there is another 
+	    ** packet to handle
+	    */
+#ifdef HAVE_NETIF_RX
+	    netif_rx(skb);
+#else
+	    skb->lock = 0;
+	    if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+		kfree_skbmem(skb, sksize);
+		lp->stats.rx_dropped++;
+		break;
+	    }
+#endif
+	    lp->stats.rx_packets++;
+	}
+
+	/* turn over ownership of the current entry back to the LANCE */
+	lp->rx_ring[entry].base |= R_OWN;
+    }
+
+    /* 
+    ** We should check that at least two ring entries are free.  If not,
+    ** we should free one and mark stats->rx_dropped++. 
+    */
+
+    return 0;
+}
+
+/*
+** Buffer sent - check for buffer errors.
+*/
+static int
+depca_tx(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int dirty_tx = lp->dirty_tx & lp->rmask;
+
+  if (depca_debug > 5)
+    printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
+	   dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
+  
+  /* 
+  ** While the dirty entry is not the current one AND 
+  ** the LANCE doesn't own it... 
+  */
+  for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
+                                       dirty_tx = ++lp->dirty_tx & lp->rmask) {
+    unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
+    int status = lp->tx_ring[dirty_tx].base >> 16;
+
+    if (status < 0) {                          /* Packet not yet sent! */
+      printk("interrupt for packet not yet sent!\n");
+      break;
+    }
+    if (status & T_ERR) { /* There was an major error, log it. */
+      int err_status = lp->tx_ring[dirty_tx].misc;
+
+      lp->stats.tx_errors++;
+      if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+      if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+      if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+      if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+      /* We should re-init() after the FIFO error. */
+    } else if (status & (T_MORE | T_ONE)) {
+      lp->stats.collisions++;
+    } else {
+      lp->stats.tx_packets++;
+    }
+
+    if (depca_debug > 5)
+      printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
+	     dev->name, dirty_tx,
+	     tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+  }
+  /*mark_bh(INET_BH);*/
+  return 0;
+}
+
+static int
+depca_close(struct device *dev)
+{
+    int ioaddr = dev->base_addr;
+
+    dev->start = 0;
+    dev->tbusy = 1;
+
+    outw(CSR0, DEPCA_ADDR);
+
+    if (depca_debug > 1) {
+      printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	     dev->name, inw(DEPCA_DATA));
+    }
+
+    /* 
+    ** We stop the DEPCA here -- it occasionally polls
+    ** memory if we don't. 
+    */
+    outw(STOP, DEPCA_DATA);
+
+    free_irq(dev->irq);
+
+    irq2dev_map[dev->irq] = 0;
+
+    return 0;
+}
+
+static void LoadCSRs(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int ioaddr = dev->base_addr;
+
+  outw(CSR1, DEPCA_ADDR);                /* initialisation block address LSW */
+  outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA);
+  outw(CSR2, DEPCA_ADDR);                /* initialisation block address MSW */
+  outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA);
+  outw(CSR3, DEPCA_ADDR);                /* ALE control */
+  outw(ACON, DEPCA_DATA);
+  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
+}
+
+static int InitRestartDepca(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int ioaddr = dev->base_addr;
+  int i, status=0;
+
+  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
+  outw(INIT, DEPCA_DATA);                /* initialize DEPCA */
+
+  /* wait for lance to complete initialisation */
+  for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); 
+
+  if (i!=100) {
+    /* clear IDON by writing a "1", enable interrupts and start lance */
+    outw(IDON | INEA | STRT, DEPCA_DATA);
+    if (depca_debug > 2) {
+      printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
+	     dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+    }
+  } else {
+    status = -1;
+    printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
+	   dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+  }
+
+  return status;
+}
+
+static struct enet_statistics *
+depca_get_stats(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+
+    /* Null body since there is no framing error counter */
+
+    return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/*
+** Set or clear the multicast filter for this adaptor.
+** num_addrs == -1	Promiscuous mode, receive all packets
+** num_addrs == 0	Normal mode, clear multicast list
+** num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+** 			best-effort filtering.
+*/
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+  short ioaddr = dev->base_addr;
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  
+  /* We take the simple way out and always enable promiscuous mode. */
+  STOP_DEPCA;                       /* Temporarily stop the depca.  */
+
+  lp->init_block.mode = PROM;       /* Set promiscuous mode */
+  if (num_addrs >= 0) {
+    short multicast_table[4];
+    int i;
+
+    SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table);
+
+    /* 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++) {
+      lp->init_block.filter[i] = multicast_table[i];
+    }
+    lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
+  } else {
+    lp->init_block.mode |= PROM;    /* Set promiscuous mode */
+  }
+
+  outw(CSR0, DEPCA_ADDR);
+  outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Derived from a 'C' program in the AMD data book:
+** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
+** Pub #17781, Rev. A, May 1993
+*/
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
+{
+  char j, ctrl, bit, octet, hashcode;
+  short int i;
+  long int CRC, poly = (long int) CRC_POLYNOMIAL;
+
+  for (i=0;i<num_addrs;i++) {                /* for each address in the list */
+    if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */ 
+      CRC = (long int) 0xffffffff;           /* init CRC for each address */
+      for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
+	for(j=0;j<8;j++) {                   /* process each address bit */
+	  bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
+	  ctrl = ((CRC < 0) ? 1 : 0);        /* shift the control bit */
+	  CRC <<= 1;                         /* shift the CRC */
+	  if (bit ^ ctrl) {                  /* (bit) XOR (control bit) */
+	    CRC ^= poly;                     /* (CRC) XOR (polynomial) */
+	  }
+	}
+      }
+      hashcode = (CRC & 0x00000001);         /* hashcode is 6 LSb of CRC ... */
+      for (j=0;j<5;j++) {                    /* ... in reverse order. */
+	hashcode <<= 1;
+	CRC >>= 1;
+	hashcode |= (CRC & 0x00000001);
+      }                                      
+      octet = hashcode >> 3;                  /* bit[3-5] -> octet in filter */
+                                              /* bit[0-2] -> bit in octet */
+      multicast_table[octet] |= (1 << (hashcode & 0x07));
+    }
+  }
+  return;
+}
+
+#endif  /* HAVE_MULTICAST */
+
+/*
+** Look for a particular board name in the on-board Remote Diagnostics
+** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** base address.
+*/
+static char *DepcaSignature(unsigned long mem_addr)
+{
+  unsigned long i,j,k;
+  static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
+  static char thisName[DEPCA_NAME_LENGTH];
+  char tmpstr[17];
+
+  for (i=0;i<16;i++) {                  /* copy the first 16 bytes of ROM to */
+    tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+  }
+  tmpstr[i]=(char)NULL;
+
+  strcpy(thisName,"");
+  for (i=0;*signatures[i]!=(char)NULL && *thisName==(char)NULL;i++) {
+    for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
+      if (signatures[i][k] == tmpstr[j]) {              /* track signature */
+	k++;
+      } else {                     /* lost signature; begin search again */
+	k=0;
+      }
+    }
+    if (k == strlen(signatures[i])) {
+      strcpy(thisName,signatures[i]);
+    }
+  }
+
+  return thisName;                    /* return the device name string */
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all DEPCA products.
+*/
+
+static int DevicePresent(short ioaddr)
+{
+  static short fp=1,sigLength=0;
+  static char devSig[] = PROBE_SEQUENCE;
+  char data;
+  int i, j, status = 0;
+  static char asc2hex(char value);
+
+/* 
+** Convert the ascii signature to a hex equivalent & pack in place 
+*/
+  if (fp) {                               /* only do this once!... */
+    for (i=0,j=0;devSig[i]!=(char)NULL && !status;i+=2,j++) {
+      if ((devSig[i]=asc2hex(devSig[i]))>=0) {
+	devSig[i]<<=4;
+	if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){
+	  devSig[j]=devSig[i]+devSig[i+1];
+	} else {
+	  status= -1;
+	}
+      } else {
+	status= -1;
+      }
+    }
+    sigLength=j;
+    fp = 0;
+  }
+
+/* 
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the length of the (signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+  if (!status) {
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+      data = inb(ioaddr);
+      if (devSig[j] == data) {    /* track signature */
+	j++;
+      } else {                    /* lost signature; begin search again */
+	j=0;
+      }
+    }
+
+    if (j!=sigLength) {
+      status = -ENODEV;           /* search failed */
+    }
+  }
+
+  return status;
+}
+
+static char asc2hex(char value)
+{
+  value -= 0x30;                  /* normalise to 0..9 range */
+  if (value >= 0) {
+    if (value > 9) {              /* but may not be 10..15 */
+      value &= 0x1f;              /* make A..F & a..f be the same */
+      value -= 0x07;              /* normalise to 10..15 range */
+      if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */
+	value = -1;               /* ...signal error */
+      }
+    }
+  } else {                        /* outside 0..9 range... */
+    value = -1;                   /* ...signal error */
+  }
+  return value;                   /* return hex char or error */
+}
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c depca.c"
+ * End:
+ */
+
+
+
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/depca.h linux/drivers/net/depca.h
--- 0.99pl15/linux/drivers/net/depca.h
+++ linux/drivers/net/depca.h	Tue Feb 22 08:35:15 1994
@@ -0,0 +1,128 @@
+/*
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 David C. Davies. This software may be used and distributed
+    according to the terms of the GNU Public License, incorporated herein by
+    reference.
+*/
+
+/*
+** I/O addresses. Note that the 2k buffer option is not supported in
+** this driver.
+*/
+#define DEPCA_NICSR ioaddr+0x00   /* Network interface CSR */
+#define DEPCA_RBI   ioaddr+0x02   /* RAM buffer index (2k buffer mode) */
+#define DEPCA_DATA  ioaddr+0x04   /* LANCE registers' data port */
+#define DEPCA_ADDR  ioaddr+0x06   /* LANCE registers' address port */
+#define DEPCA_PROM  ioaddr+0x0c   /* Ethernet address ROM data port */
+#define DEPCA_RBSA  ioaddr+0x0e   /* RAM buffer starting address (2k buff.) */
+
+/*
+** These are LANCE registers addressable through DEPCA_ADDR 
+*/
+#define CSR0       0
+#define CSR1       1
+#define CSR2       2
+#define CSR3       3
+
+/* 
+** NETWORK INTERFACE CSR (NI_CSR) bit definitions 
+*/
+ 
+#define TO       	0x0100	/* Time Out for remote boot */
+#define SHE      	0x0080  /* SHadow memory Enable */
+#define BS       	0x0040  /* Bank Select */
+#define BUF      	0x0020	/* BUFfer size (1->32k, 0->64k) */
+#define RBE      	0x0010	/* Remote Boot Enable (1->net boot) */
+#define AAC      	0x0008  /* for DEPCA family compatability */
+#define IM       	0x0004	/* Interrupt Mask (1->mask) */
+#define IEN      	0x0002	/* Interrupt tristate ENable (1->enable) */
+#define LED      	0x0001	/* LED control */
+
+/* 
+** Control and Status Register 0 (CSR0) bit definitions 
+*/
+
+#define ERR     	0x8000 	/* Error summary */
+#define BABL    	0x4000 	/* Babble transmitter timeout error  */
+#define CERR    	0x2000 	/* Collision Error */
+#define MISS    	0x1000 	/* Missed packet */
+#define MERR    	0x0800 	/* Memory Error */
+#define RINT    	0x0400 	/* Receiver Interrupt */
+#define TINT    	0x0200 	/* Transmit Interrupt */
+#define IDON    	0x0100 	/* Initialization Done */
+#define INTR    	0x0080 	/* Interrupt Flag */
+#define INEA    	0x0040 	/* Interrupt Enable */
+#define RXON    	0x0020 	/* Receiver on */
+#define TXON    	0x0010 	/* Transmitter on */
+#define TDMD    	0x0008 	/* Transmit Demand */
+#define STOP    	0x0004 	/* Stop */
+#define STRT    	0x0002 	/* Start */
+#define INIT    	0x0001 	/* Initialize */
+
+/*
+** CONTROL AND STATUS REGISTER 3 (CSR3)
+*/
+
+#define BSWP    	0x0004	/* Byte SWaP */
+#define ACON    	0x0002	/* ALE control */
+#define BCON    	0x0001	/* Byte CONtrol */
+
+/*
+** Initialization Block Mode Register 
+*/
+
+#define PROM       	0x8000 	/* Promiscuous Mode */
+#define EMBA       	0x0080	/* Enable Modified Back-off Algorithm */
+#define INTL       	0x0040 	/* Internal Loopback */
+#define DRTY       	0x0020 	/* Disable Retry */
+#define COLL       	0x0010 	/* Force Collision */
+#define DTCR       	0x0008 	/* Disable Transmit CRC */
+#define LOOP       	0x0004 	/* Loopback */
+#define DTX        	0x0002 	/* Disable the Transmitter */
+#define DRX        	0x0001 	/* Disable the Receiver */
+
+/*
+** Receive Message Descriptor 1 (RMD1) bit definitions. 
+*/
+
+#define R_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define R_ERR     	0x4000 	/* Error Summary */
+#define R_FRAM    	0x2000 	/* Framing Error */
+#define R_OFLO    	0x1000 	/* Overflow Error */
+#define R_CRC     	0x0800 	/* CRC Error */
+#define R_BUFF    	0x0400 	/* Buffer Error */
+#define R_STP     	0x0200 	/* Start of Packet */
+#define R_ENP     	0x0100 	/* End of Packet */
+
+/*
+** Transmit Message Descriptor 1 (TMD1) bit definitions. 
+*/
+
+#define T_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define T_ERR     	0x4000 	/* Error Summary */
+#define T_ADD_FCS 	0x2000 	/* More the 1 retry needed to Xmit */
+#define T_MORE    	0x1000	/* >1 retry to transmit packet */
+#define T_ONE     	0x0800 	/* 1 try needed to transmit the packet */
+#define T_DEF     	0x0400 	/* Deferred */
+#define T_STP       0x02000000 	/* Start of Packet */
+#define T_ENP       0x01000000	/* End of Packet */
+
+/*
+** Transmit Message Descriptor 3 (TMD3) bit definitions.
+*/
+
+#define TMD3_BUFF    0x8000	/* BUFFer error */
+#define TMD3_UFLO    0x4000	/* UnderFLOw error */
+#define TMD3_RES     0x2000	/* REServed */
+#define TMD3_LCOL    0x1000	/* Late COLlision */
+#define TMD3_LCAR    0x0800	/* Loss of CARrier */
+#define TMD3_RTRY    0x0400	/* ReTRY error */
+
+/*
+** Miscellaneous
+*/
+
+#define MASK_INTERRUPTS   1
+#define UNMASK_INTERRUPTS 0
+
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- 0.99pl15/linux/drivers/net/eexpress.c	Wed Feb  2 17:30:04 1994
+++ linux/drivers/net/eexpress.c	Sun Mar  6 16:12:05 1994
@@ -19,7 +19,7 @@
 */
 
 static char *version =
-	"eexpress.c:v0.06 10/27/93 Donald Becker (becker@super.org)\n";
+	"eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 
@@ -154,7 +154,7 @@
 #define ASIC_RESET		0x40
 #define _586_RESET		0x80
 
-/* Offsets into the System Control Block structure. */
+/* Offsets to elements of the System Control Block structure. */
 #define SCB_STATUS	0xc008
 #define SCB_CMD		0xc00A
 #define	 CUC_START	 0x0100
@@ -175,8 +175,8 @@
   program space than initializing the individual tables, and I feel it's much
   cleaner.
 
-  The databook is particularly useless for the first two structures, I had
-  to use the Crynwr driver as an example.
+  The databook is particularly useless for the first two structures; they are
+  completely undocumented.  I had to use the Crynwr driver as an example.
 
    The memory setup is as follows:
    */
@@ -194,17 +194,18 @@
 
 #define TX_BUF_START	0x0100
 #define NUM_TX_BUFS 	4
-#define TX_BUF_SIZE 	(1518+14+20+16) /* packet+header+TBD */
+#define TX_BUF_SIZE		0x0680	/* packet+header+TBD+extra (1518+14+20+16) */
+#define TX_BUF_END		0x2000
 
 #define RX_BUF_START	0x2000
 #define RX_BUF_SIZE 	(0x640)	/* packet+header+RBD+extra */
-#define RX_BUF_END		0x8000
+#define RX_BUF_END		0x4000
 
 /*
   That's it: only 86 bytes to set up the beast, including every extra
   command available.  The 170 byte buffer at DUMP_DATA is shared between the
   Dump command (called only by the diagnostic program) and the SetMulticastList
-  command. 
+  command.
 
   To complete the memory setup you only have to write the station address at
   SA_OFFSET and create the Tx & Rx buffer lists.
@@ -277,7 +278,7 @@
 #endif
 
 	/* 0x0056: A continuous transmit command, only here for testing. */
-	0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x803ff, -1, DUMP_DATA, 0,
+	0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x83ff, -1, DUMP_DATA, 0,
 };
 
 /* Index to functions, as function prototypes. */
@@ -326,6 +327,7 @@
 #ifdef notdef
 		for (i = 16; i > 0; i--)
 			sum += inb(id_addr);
+		printk("EtherExpress ID checksum is %04x.\n", sum);
 #else
 		for (i = 4; i > 0; i--) {
 			short id_val = inb(id_addr);
@@ -353,7 +355,7 @@
 	station_addr[1] = read_eeprom(ioaddr, 3);
 	station_addr[2] = read_eeprom(ioaddr, 4);
 
-	/* Check the first three octets of the S.A. for the manufactor's code. */ 
+	/* Check the first three octets of the S.A. for the manufactor's code. */
 	if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
 		printk(" rejected (invalid address %04x%04x%04x).\n",
 			   station_addr[2], station_addr[1], station_addr[0]);
@@ -551,8 +553,8 @@
 	struct device *dev = (struct device *)(irq2dev_map[irq]);
 	struct net_local *lp;
 	int ioaddr, status, boguscount = 0;
-	short ack_cmd = 0;
-	
+	short ack_cmd;
+
 	if (dev == NULL) {
 		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
 		return;
@@ -595,7 +597,7 @@
 		if (net_debug > 5)
 			printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
 		lp->tx_reap += TX_BUF_SIZE;
-		if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
+		if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE)
 			lp->tx_reap = TX_BUF_START;
 		if (++boguscount > 4)
 			break;
@@ -611,13 +613,22 @@
 	ack_cmd = status & 0xf000;
 
 	if ((status & 0x0700) != 0x0200  &&  dev->start) {
-		if (net_debug)
+		short saved_write_ptr = inw(ioaddr + WRITE_PTR);
+		if (net_debug > 1)
 			printk("%s: Command unit stopped, status %04x, restarting.\n",
 				   dev->name, status);
-		/* If this ever occurs we should really re-write the idle loop, reset
-		   the Tx list, and do a complete restart of the command unit.
-		   For now we rely on the Tx timeout if the resume doesn't work. */
-		ack_cmd |= CUC_RESUME;
+		/* If this ever occurs we must re-write the idle loop, reset
+		   the Tx list, and do a complete restart of the command unit. */
+		outw(IDLELOOP, ioaddr + WRITE_PTR);
+		outw(0, ioaddr);
+		outw(CmdNOp, ioaddr);
+		outw(IDLELOOP, ioaddr);
+		outw(IDLELOOP, SCB_CBL);
+		lp->tx_cmd_link = IDLELOOP + 4;
+		lp->tx_head = lp->tx_reap = TX_BUF_START;
+		/* Restore the saved write pointer. */
+		outw(saved_write_ptr, ioaddr + WRITE_PTR);
+		ack_cmd |= CUC_START;
 	}
 
 	if ((status & 0x0070) != 0x0040  &&  dev->start) {
@@ -624,9 +635,21 @@
 		short saved_write_ptr = inw(ioaddr + WRITE_PTR);
 		/* The Rx unit is not ready, it must be hung.  Restart the receiver by
 		   initializing the rx buffers, and issuing an Rx start command. */
-		if (net_debug)
-			printk("%s: Rx unit stopped, status %04x, restarting.\n",
-				   dev->name, status);
+		lp->stats.rx_errors++;
+		if (net_debug > 1) {
+			int cur_rxbuf = RX_BUF_START;
+			printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n",
+				   dev->name, status, lp->rx_head, lp->rx_tail);
+			while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) {
+				int i;
+				printk("  Rx buf at %04x:", cur_rxbuf);
+				outw(cur_rxbuf, ioaddr + READ_PTR);
+				for (i = 0; i < 0x20; i += 2)
+					printk(" %04x", inw(ioaddr));
+				printk(".\n");
+				cur_rxbuf += RX_BUF_SIZE;
+			}
+		}
 		init_rx_bufs(dev);
 		outw(RX_BUF_START, SCB_RFA);
 		outw(saved_write_ptr, ioaddr + WRITE_PTR);
@@ -813,8 +836,7 @@
 }
 
 /* Initialize the Rx-block list. */
-static void
-init_rx_bufs(struct device *dev)
+static void init_rx_bufs(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
@@ -828,14 +850,14 @@
 		outw(0x0000, ioaddr);				/* Command */
 		outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */
 		outw(cur_rxbuf + 22, ioaddr);		/* Buffer offset */
-		outw(0x0000, ioaddr); 				/* Pad for dest addr. */
-		outw(0x0000, ioaddr);
-		outw(0x0000, ioaddr);
-		outw(0x0000, ioaddr); 				/* Pad for source addr. */
-		outw(0x0000, ioaddr);
-		outw(0x0000, ioaddr);
-		outw(0x0000, ioaddr);				/* Pad for protocol. */
-		
+		outw(0xFeed, ioaddr); 				/* Pad for dest addr. */
+		outw(0xF00d, ioaddr);
+		outw(0xF001, ioaddr);
+		outw(0x0505, ioaddr); 				/* Pad for source addr. */
+		outw(0x2424, ioaddr);
+		outw(0x6565, ioaddr);
+		outw(0xdeaf, ioaddr);				/* Pad for protocol. */
+
 		outw(0x0000, ioaddr);				/* Buffer: Actual count */
 		outw(-1, ioaddr);					/* Buffer: Next (none). */
 		outw(cur_rxbuf + 0x20, ioaddr);		/* Buffer: Address low */
@@ -890,7 +912,7 @@
 
 	/* Set the next free tx region. */
 	lp->tx_head = tx_block + TX_BUF_SIZE;
-	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
+	if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE)
 		lp->tx_head = TX_BUF_START;
 
     if (net_debug > 4) {
@@ -985,7 +1007,7 @@
 			printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name,
 				   rx_head, next_rx_frame, rx_head + RX_BUF_SIZE);
 			next_rx_frame = rx_head + RX_BUF_SIZE;
-			if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) 
+			if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE)
 				next_rx_frame = RX_BUF_START;
 		}
 #endif
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- 0.99pl15/linux/drivers/net/hp.c	Mon Jan  3 08:31:18 1994
+++ linux/drivers/net/hp.c	Sun Mar  6 16:12:05 1994
@@ -13,7 +13,7 @@
 */
 
 static char *version =
-	"hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n";
+	"hp.c:v0.99.15k 3/3/94 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -56,7 +56,7 @@
 static void hp_init_card(struct device *dev);
 
 /* The map from IRQ number to HP_CONFIGURE register setting. */
-/* My default is IRQ5	   0  1	 2	3  4  5	 6	7  8  9 10 11 */
+/* My default is IRQ5	   0  1	 2  3  4  5  6	7  8  9 10 11 */
 static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
 
 
@@ -86,24 +86,19 @@
 
 int hpprobe1(struct device *dev, int ioaddr)
 {
-	int status, i, board_id, wordmode;
+	int i, board_id, wordmode;
 	char *name;
 	unsigned char *station_addr = dev->dev_addr;
 
 	/* Check for the HP physical address, 08 00 09 xx xx xx. */
+	/* This really isn't good enough: we may pick up HP LANCE boards
+	   also!  Avoid the lance 0x5757 signature. */
 	if (inb(ioaddr) != 0x08
 		|| inb(ioaddr+1) != 0x00
-		|| inb(ioaddr+2) != 0x09)
+		|| inb(ioaddr+2) != 0x09
+		|| inb(ioaddr+14) == 0x57)
 		return ENODEV;
 
-	/* This really isn't good enough, we may pick up HP LANCE boards also! */
-	/* Verify that there is a 8390 at the expected location. */
-	outb(E8390_NODMA + E8390_STOP, ioaddr);
-	SLOW_DOWN_IO;
-	status = inb(ioaddr);
-	if (status != 0x21 && status != 0x23)
-		return ENODEV;
-
 	/* Set up the parameters based on the board ID.
 	   If you have additional mappings, please mail them to becker@super.org. */
 	if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
@@ -182,31 +177,22 @@
 {
 	int hp_base = dev->base_addr - NIC_OFFSET;
 	int saved_config = inb_p(hp_base + HP_CONFIGURE);
-	int reset_start_time = jiffies;
 
-	if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies);
+	if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
 	outb_p(0x00, hp_base + HP_CONFIGURE);
 	ei_status.txing = 0;
-
-	sti();
-	/* We shouldn't use the boguscount for timing, but this hasn't been
-	   checked yet, and you could hang your machine if jiffies break... */
-	{
-		int boguscount = 150000;
-		while(jiffies - reset_start_time < 2)
-			if (boguscount-- < 0) {
-				printk("jiffy failure (t=%d)...", jiffies);
-				break;
-			}
-	}
+	/* Pause just a few cycles for the hardware reset to take place. */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
 
 	outb_p(saved_config, hp_base + HP_CONFIGURE);
-	while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2) {
-			printk("%s: hp_reset_8390() did not complete.\n", dev->name);
-			return;
-		}
-	if (ei_debug > 1) printk("8390 reset done (%d).", jiffies);
+	SLOW_DOWN_IO; SLOW_DOWN_IO;
+	
+	if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
+		printk("%s: hp_reset_8390() did not complete.\n", dev->name);
+
+	if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
+	return;
 }
 
 /* Block input and output, similar to the Crynwr packet driver.	 If you
@@ -320,9 +306,10 @@
 
 /*
  * Local variables:
- *	compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * c-indent-level: 4
  * End:
  */
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- 0.99pl15/linux/drivers/net/lance.c	Wed Feb  2 17:41:54 1994
+++ linux/drivers/net/lance.c	Fri Mar  4 09:16:19 1994
@@ -205,7 +205,7 @@
     int pad0, pad1;		/* Used for alignment */
 };
 
-static unsigned long lance_probe1(short ioaddr, unsigned long mem_start);
+unsigned long lance_probe1(short ioaddr, unsigned long mem_start);
 static int lance_open(struct device *dev);
 static void lance_init_ring(struct device *dev);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -236,7 +236,7 @@
     return mem_start;
 }
 
-static unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
+unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
 {
     struct device *dev;
     struct lance_private *lp;
@@ -556,18 +556,18 @@
     if ((int)(skb->data) + skb->len > 0x01000000) {
 	if (lance_debug > 5)
 	    printk("%s: bouncing a high-memory packet (%#x).\n",
-		   dev->name, (int)skb->data);
+		   dev->name, (int)(skb->data));
 	memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);
 	lp->tx_ring[entry].base =
 	    (int)(lp->tx_bounce_buffs + entry) | 0x83000000;
 	if (skb->free)
 	    kfree_skb (skb, FREE_WRITE);
-    } else
-    {
-    	/* Gimme!!! */
+    } else {
+    	/* We can't free the packet yet, so we inform the memory management
+	   code that we are still using it. */
     	if(skb->free==0)
     		skb_kept_by_device(skb);
-	lp->tx_ring[entry].base = (int)skb->data | 0x83000000;
+	lp->tx_ring[entry].base = (int)(skb->data) | 0x83000000;
     }
     lp->cur_tx++;
 
@@ -638,11 +638,12 @@
 		if (err_status & 0x0800) lp->stats.tx_carrier_errors++;
 		if (err_status & 0x1000) lp->stats.tx_window_errors++;
 		if (err_status & 0x4000) lp->stats.tx_fifo_errors++;
-		/* We should re-init() after the FIFO error. */
-	    } else if (status & 0x18000000)
-		lp->stats.collisions++;
-	    else
+		/* Perhaps we should re-init() after the FIFO error. */
+	    } else {
+		if (status & 0x18000000)
+		    lp->stats.collisions++;
 		lp->stats.tx_packets++;
+	    }
 
 	    /* We don't free the skb if it's a data-only copy in the bounce
 	       buffer.  The address checks here are sorted -- the first test
@@ -654,7 +655,8 @@
 		    kfree_skb(skb, FREE_WRITE);
 		else
 		    skb_device_release(skb,FREE_WRITE);
-		/* Warning: skb may well vanish at the point you call device_release! */
+		/* Warning: skb may well vanish at the point you call
+		   device_release! */
 	    }
 	    dirty_tx++;
 	}
@@ -704,8 +706,13 @@
     while (lp->rx_ring[entry].base >= 0) {
 	int status = lp->rx_ring[entry].base >> 24;
 
-	if (status & 0x40) {	/* There was an error. */
-	    lp->stats.rx_errors++;
+	if (status != 0x03) {		/* There was an error. */
+	    /* There is an tricky error noted by John Murphy,
+	       <murf@perftech.com> to Russ Nelson: Even with full-sized
+	       buffers it's possible for a jabber packet to use two
+	       buffers, with only the last correctly noting the error. */
+	    if (status & 0x01)	/* Only count a general error at the */
+		lp->stats.rx_errors++; /* end of a packet.*/
 	    if (status & 0x20) lp->stats.rx_frame_errors++;
 	    if (status & 0x10) lp->stats.rx_over_errors++;
 	    if (status & 0x08) lp->stats.rx_crc_errors++;
@@ -835,6 +842,12 @@
     outw(0, ioaddr+LANCE_ADDR);
     outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */
 }
+#endif
+
+#ifdef HAVE_DEVLIST
+static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
+struct netdev_entry lance_drv =
+{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist};
 #endif
 
 /*
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- 0.99pl15/linux/drivers/net/ne.c	Fri Jan 28 09:50:24 1994
+++ linux/drivers/net/ne.c	Sun Mar  6 16:12:04 1994
@@ -17,7 +17,7 @@
 /* Routines for the NatSemi-based designs (NE[12]000). */
 
 static char *version =
-    "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n";
+    "ne.c:v0.99-15k 3/3/94 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -155,11 +155,10 @@
     }
 
     if (wordlength == 2) {
-	/* We must set the 8390 for word mode, AND RESET IT. */
-	int tmp;
+	/* We must set the 8390 for word mode. */
 	outb_p(0x49, ioaddr + EN0_DCFG);
-	tmp = inb_p(NE_BASE + NE_RESET);
-	outb(tmp, NE_BASE + NE_RESET);
+	/* We used to reset the ethercard here, but it doesn't seem
+	   to be necessary. */
 	/* Un-double the SA_prom values. */
 	for (i = 0; i < 16; i++)
 	    SA_prom[i] = SA_prom[i+i];
@@ -265,7 +264,7 @@
     int tmp = inb_p(NE_BASE + NE_RESET);
     int reset_start_time = jiffies;
 
-    if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies);
+    if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
     ei_status.txing = 0;
 
     outb_p(tmp, NE_BASE + NE_RESET);
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- 0.99pl15/linux/drivers/net/slip.c	Wed Feb  2 17:30:15 1994
+++ linux/drivers/net/slip.c	Sun Mar 13 15:47:58 1994
@@ -19,6 +19,8 @@
  *		Alan Cox	:	Honours the old SL_COMPRESSED flag
  *		Alan Cox	:	KISS AX.25 and AXUI IP support
  *		Michael Riepe	:	Automatic CSLIP recognition added
+ *		Charles Hedrick :	CSLIP header length problem fix.
+ *		Alan Cox	:	Corrected non-IP cases of the above.
  */
  
 #include <asm/segment.h>
@@ -231,12 +233,19 @@
 	
 	sl->mtu=dev->mtu;
 	l=(dev->mtu *2);
+/*
+ * allow for arrival of larger UDP packets, even if we say not to
+ * also fixes a bug in which SunOS sends 512-byte packets even with
+ * an MSS of 128
+ */
+	if (l < (576 * 2))
+	  l = 576 * 2;
 	
 	DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n"));
 	
-	tb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
-	rb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
-	cb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
+	tb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
+	rb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
+	cb= (unsigned char *) kmalloc(l + 4, GFP_ATOMIC);
 	
 	if(tb==NULL || rb==NULL || cb==NULL)
 	{
@@ -522,6 +531,7 @@
 {
   struct tty_struct *tty;
   struct slip *sl;
+  int size;
 
   /* Find the correct SLIP channel to use. */
   sl = &sl_ctrl[dev->base_addr];
@@ -543,26 +553,35 @@
   /* We were not, so we are now... :-) */
   if (skb != NULL) {
 #ifdef CONFIG_AX25  
-  	if(sl->mode & SL_MODE_AX25)
-  	{
-  		if(!skb->arp && dev->rebuild_header(skb->data,dev))
-  		{
-  			skb->dev=dev;
-  			arp_queue(skb);
-  			return 0;
-  		}
-  		skb->arp=1;
-  	}
+	if(sl->mode & SL_MODE_AX25)
+	{
+		if(!skb->arp && dev->rebuild_header(skb->data,dev))
+		{
+			skb->dev=dev;
+			arp_queue(skb);
+			return 0;
+		}
+		skb->arp=1;
+	}
 #endif  	
 	sl_lock(sl);
-/*	sl_hex_dump(skb->data,skb->len);*/
-	sl_encaps(sl, skb->data, skb->len);
-	if (skb->free) kfree_skb(skb, FREE_WRITE);
+	size = skb->len;
+	if (!(sl->mode & SL_MODE_AX25)) {
+		if (size < sizeof(struct iphdr)) {
+			printk("Runt IP frame fed to slip!\n");
+		} else {
+			size = ((struct iphdr *)(skb->data))->tot_len;
+			size = ntohs(size);
+		}
+	}
+	/*	sl_hex_dump(skb->data,skb->len);*/
+	sl_encaps(sl, skb->data, size);
+	if (skb->free)
+		kfree_skb(skb, FREE_WRITE);
   }
   return(0);
 }
 
-
 /* Return the frame type ID.  This is normally IP but maybe be AX.25. */
 static unsigned short
 sl_type_trans (struct sk_buff *skb, struct device *dev)
@@ -642,6 +661,14 @@
    * rmem_start	Start of RECV frame buffer
    */
   l = (dev->mtu * 2);
+/*
+ * allow for arrival of larger UDP packets, even if we say not to
+ * also fixes a bug in which SunOS sends 512-byte packets even with
+ * an MSS of 128
+ */
+  if (l < (576 * 2))
+    l = 576 * 2;
+
   p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
   if (p == NULL) {
 	DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n"));
diff -u +recursive +new-file 0.99pl15/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- 0.99pl15/linux/drivers/net/smc-ultra.c	Thu Dec 23 10:38:34 1993
+++ linux/drivers/net/smc-ultra.c	Tue Mar  1 19:29:05 1994
@@ -14,7 +14,7 @@
 */
 
 static char *version =
-    "smc-ultra.c:v0.05 12/21/93 Donald Becker (becker@super.org)\n";
+    "smc-ultra.c:v0.07 3/1/94 Donald Becker (becker@super.org)\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -63,7 +63,7 @@
     unsigned short ioaddr = dev->base_addr;
 
     if (ioaddr > 0x1ff)
-	return ! ultraprobe1(ioaddr, dev);
+	return ultraprobe1(ioaddr, dev);
     else if (ioaddr > 0)
 	return ENXIO;		/* Don't probe at all. */
 
@@ -139,7 +139,7 @@
   dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
 
   { 
-      int addr_tbl[4] = {0x0C0000, 0x0D0000, 0xFC0000, 0xFD0000};
+      int addr_tbl[4] = {0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000};
       short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff};
 
       dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
@@ -158,7 +158,7 @@
   dev->mem_end = dev->rmem_end
       = dev->mem_start + (ei_status.stop_page - START_PG)*256;
 
-  printk(",%s IRQ %d memory %#x-%#x.\n", eeprom_irq ? "" : "assigned ",
+  printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ",
 	 dev->irq, dev->mem_start, dev->mem_end-1);
   if (ei_debug > 0)
       printk(version);
@@ -193,7 +193,7 @@
     int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */
 
     outb(ULTRA_RESET, cmd_port);
-    if (ei_debug > 1) printk("resetting Ultra, t=%d...", jiffies);
+    if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies);
     ei_status.txing = 0;
 
     outb(ULTRA_MEMENB, cmd_port);
diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- 0.99pl15/linux/drivers/scsi/aha1542.c	Mon Jan 24 09:23:20 1994
+++ linux/drivers/scsi/aha1542.c	Mon Feb 14 22:06:26 1994
@@ -675,7 +675,7 @@
   WAIT(INTRFLAGS(base),INTRMASK,HACC,0);
   aha1542_intr_reset(base);
   
-  if (mbenable_result[0] & 0x08) {
+  if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
      mbenable_cmd[0]=CMD_MBENABLE;
      mbenable_cmd[1]=0;
      mbenable_cmd[2]=mbenable_result[1];
diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- 0.99pl15/linux/drivers/scsi/constants.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/constants.c	Tue Feb 15 07:26:30 1994
@@ -18,7 +18,7 @@
 #ifdef CONSTANTS
 #undef CONSTANTS
 #endif
-#define CONSTANTS (CONST_CMD | CONST_STATUS | CONST_SENSE | CONST_XSENSE)
+#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE)
 #endif
 
 #if (CONSTANTS & CONST_COMMAND)
diff -u +recursive +new-file 0.99pl15/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- 0.99pl15/linux/drivers/scsi/scsi.c	Thu Dec 30 11:39:04 1993
+++ linux/drivers/scsi/scsi.c	Thu Mar 10 09:11:50 1994
@@ -127,15 +127,21 @@
 static struct blist blacklist[] = 
 {
    {"DENON","DRD-25X","V"},   /* A cdrom that locks up when probed at lun != 0 */
-   {"MAXTOR","XT-4380S","B3C"},  /* Locks-up when LUN>0 polled. */
+   {"IMS", "CDD521/10","2.06"},   /* Locks-up when LUN>0 polled. */
+   {"MAXTOR","XT-3280","PR02"},   /* Locks-up when LUN>0 polled. */
+   {"MAXTOR","XT-4380S","B3C"},   /* Locks-up when LUN>0 polled. */
    {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
-   {"MAXTOR","XT-4170S","B5A"},  /* Locks-up sometimes when LUN>0 polled. */
+   {"MAXTOR","XT-4170S","B5A"},   /* Locks-up sometimes when LUN>0 polled. */
+   {"MAXTOR","XT-8760S","B7B"},   /* guess what? */
    {"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
+   {"RODIME","RO3000S","2.33"},  /* Locks up if polled for lun != 0 */
    {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x
 				     * controller, which causes SCSI code to reset bus.*/
    {"SEAGATE", "ST296","921"},   /* Responds to all lun */
    {"SONY","CD-ROM CDU-541","4.3d"},
    {"TANDBERG","TDC 3600","U07"},  /* Locks up if polled for lun != 0 */
+   {"TEAC","CD-ROM","1.06"},	/* causes failed REQUEST SENSE on lun 1 for seagate
+				 * controller, which causes SCSI code to reset bus.*/
    {"TEXEL","CD-ROM","1.06"},   /* causes failed REQUEST SENSE on lun 1 for seagate
 				 * controller, which causes SCSI code to reset bus.*/
    {NULL, NULL, NULL}};	
@@ -385,7 +391,7 @@
 
 			scsi_devices[NR_SCSI_DEVICES].tagged_queue = 0;
 
-			if ((scsi_devices[NR_SCSI_DEVICES].scsi_level == SCSI_2) &&
+			if ((scsi_devices[NR_SCSI_DEVICES].scsi_level >= SCSI_2) &&
 			    (scsi_result[7] & 2)) {
 			    scsi_devices[NR_SCSI_DEVICES].tagged_supported = 1;
 			    scsi_devices[NR_SCSI_DEVICES].current_tag = 0;
@@ -449,6 +455,9 @@
 			/* Some scsi devices cannot be polled for lun != 0
 			   due to firmware bugs */
 			if(blacklisted(scsi_result)) break;
+			/* Old drives like the MAXTOR XT-3280 say vers=0 */
+			if ((scsi_result[2] & 0x07) == 0)
+			    break;
 			/* Some scsi-1 peripherals do not handle lun != 0.
 			   I am assuming that scsi-2 peripherals do better */
 			if((scsi_result[2] & 0x07) == 1 && 
diff -u +recursive +new-file 0.99pl15/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- 0.99pl15/linux/drivers/sound/os.h	Tue Dec 21 10:24:00 1993
+++ linux/drivers/sound/os.h	Fri Feb 11 13:07:33 1994
@@ -140,7 +140,7 @@
 
 #define DEFINE_TIMER(name, proc) \
   static struct timer_list name = \
-  {NULL, 0, 0, proc}
+  {NULL, NULL, 0, 0, proc}
 
 /*
  * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
diff -u +recursive +new-file 0.99pl15/linux/fs/binfmt_coff.c linux/fs/binfmt_coff.c
--- 0.99pl15/linux/fs/binfmt_coff.c	Thu Jan 20 14:36:30 1994
+++ linux/fs/binfmt_coff.c	Mon Feb 14 18:41:55 1994
@@ -7,43 +7,12 @@
  * This file is based upon code written by Eric Youndale for the ELF object
  * file format.
  *
- * Revision information:
- *    28 August 1993
- *       Al Longyear (longyear@sii.com)
- *       initial release to alpha level testing. This version does not load
- *       shared libraries, but will identify them and log the file names.
+ * Author: Al Longyear (longyear@sii.com)
  *
- *     4 September 1993
- *       Al Longyear (longyear@sii.com)
- *       Added support for shared libraries.
- *
- *     9 September 1993
- *       Al Longyear (longyear@sii.com)
- *       Load the FS register with the proper value prior to the call to
- *       sys_uselib().
- *
- *       Built the parameter and envionment strings before destroying the
- *       current executable.
- *
- *    10 September 1993
- *       Al Longyear (longyear@sii.com)
- *       Added new parameter to the create_tables() function to allow the
- *       proper creation of the IBCS environment stack when the process is
- *       started.
- *
- *       Added code to create_tables() which I mistakenly deleted in the
- *       last patch.
- *
- *    13 September 1993
- *       Al Longyear (longyear@sii.com)
- *       Removed erroneous code which mistakenly folded .data with .bss for
- *       a shared library. 
- *
- *     8 Janurary 1994
- *       Al Longyear (longyear@sii.com)
- *       Corrected problem with read of library section returning the byte
- *       count rather than zero. This was a change between the pl12 and
- *       pl14 kernels which slipped by me.
+ * Latest Revision:
+ *    3 Feburary 1994
+ *      Al Longyear (longyear@sii.com)
+ *      Cleared first page of bss section using put_fs_byte.
  */
 
 #include <linux/fs.h>
@@ -105,6 +74,37 @@
 }
 
 /*
+ *    Clear the bytes in the last page of data.
+ */
+
+static
+int clear_memory (unsigned long addr, unsigned long size)
+{
+    int status;
+
+    size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
+    if (size == 0)
+        status = 0;
+    else {
+      
+#ifdef COFF_DEBUG
+        printk ("un-initialized storage in last page %d\n", size);
+#endif
+
+	status = verify_area (VERIFY_WRITE,
+			      (void *) addr, size);
+#ifdef COFF_DEBUG
+	printk ("result from verify_area = %d\n", status);
+#endif
+
+	if (status >= 0)
+	    while (size-- != 0)
+	        put_fs_byte (0, addr++);
+    }
+    return status;
+}
+
+/*
  *  Helper function to process the load operation.
  */
 
@@ -521,11 +521,13 @@
 	    zeromap_page_range (PAGE_ALIGN (bss_vaddr),
 				PAGE_ALIGN (bss_size),
 				PAGE_COPY);
+
+	    status = clear_memory (bss_vaddr, bss_size);
 	}
 /*
  *  Load any shared library for the executable.
  */
-	if (lib_ok && lib_count != 0) {
+	if (status >= 0 && lib_ok && lib_count != 0) {
 	    int nIndex;
 	    COFF_SCNHDR *sect_ptr = sect_bufr;
 /*
diff -u +recursive +new-file 0.99pl15/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- 0.99pl15/linux/fs/binfmt_elf.c	Thu Jan 20 14:36:30 1994
+++ linux/fs/binfmt_elf.c	Thu Feb 17 09:07:27 1994
@@ -13,6 +13,7 @@
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
+#include <linux/shm.h>
 
 #include <asm/segment.h>
 
@@ -21,6 +22,8 @@
 asmlinkage int sys_open(const char *, int, int);
 asmlinkage int sys_brk(unsigned long);
 
+#define DLINFO_ITEMS 8
+
 #include <linux/elf.h>
 
 /* We need to explicitly zero any fractional pages
@@ -43,17 +46,220 @@
   };
 }
 
+unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
+{
+	unsigned long *argv,*envp, *dlinfo;
+	unsigned long * sp;
+	struct vm_area_struct *mpnt;
+
+	mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+	if (mpnt) {
+		mpnt->vm_task = current;
+		mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+		mpnt->vm_end = TASK_SIZE;
+		mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+		mpnt->vm_share = NULL;
+		mpnt->vm_inode = NULL;
+		mpnt->vm_offset = 0;
+		mpnt->vm_ops = NULL;
+		insert_vm_struct(current, mpnt);
+		current->stk_vma = mpnt;
+	}
+	sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
+	if(exec) sp -= DLINFO_ITEMS*2;
+	dlinfo = sp;
+	sp -= envc+1;
+	envp = sp;
+	sp -= argc+1;
+	argv = sp;
+	if (!ibcs) {
+		put_fs_long((unsigned long)envp,--sp);
+		put_fs_long((unsigned long)argv,--sp);
+	}
+
+	/* The constant numbers (0-9) that we are writing here are
+	   described in the header file sys/auxv.h on at least
+	   some versions of SVr4 */
+	if(exec) { /* Put this here for an ELF program interpreter */
+	  struct elf_phdr * eppnt;
+	  eppnt = (struct elf_phdr *) exec->e_phoff;
+	  put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
+	  put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
+	  put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
+	  put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
+	  put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
+	  put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
+	  put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
+	  put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
+	};
+
+	put_fs_long((unsigned long)argc,--sp);
+	current->arg_start = (unsigned long) p;
+	while (argc-->0) {
+		put_fs_long((unsigned long) p,argv++);
+		while (get_fs_byte(p++)) /* nothing */ ;
+	}
+	put_fs_long(0,argv);
+	current->arg_end = current->env_start = (unsigned long) p;
+	while (envc-->0) {
+		put_fs_long((unsigned long) p,envp++);
+		while (get_fs_byte(p++)) /* nothing */ ;
+	}
+	put_fs_long(0,envp);
+	current->env_end = (unsigned long) p;
+	return sp;
+}
+
+
+/* This is much more generalized than the library routine read function,
+   so we keep this separate.  Techincally the library read function
+   is only provided so that we can read a.out libraries that have
+   an ELF header */
+
+static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
+			     struct inode * interpreter_inode)
+{
+        struct file * file;
+	struct elf_phdr *elf_phdata  =  NULL;
+	struct elf_phdr *eppnt;
+	unsigned int len;
+	unsigned int load_addr;
+	int elf_exec_fileno;
+	int elf_bss;
+	int old_fs, retval;
+	unsigned int last_bss;
+	int error;
+	int i, k;
+	
+	elf_bss = 0;
+	last_bss = 0;
+	error = load_addr = 0;
+	
+	/* First of all, some simple consistency checks */
+	if((interp_elf_ex->e_type != ET_EXEC && 
+	    interp_elf_ex->e_type != ET_DYN) || 
+	   (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
+	   (!interpreter_inode->i_op || !interpreter_inode->i_op->bmap || 
+	    !interpreter_inode->i_op->default_file_ops->mmap)){
+		return 0xffffffff;
+	};
+	
+	/* Now read in all of the header information */
+	
+	if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) 
+	    return 0xffffffff;
+	
+	elf_phdata =  (struct elf_phdr *) 
+		kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
+	if(!elf_phdata) return 0xffffffff;
+	
+	old_fs = get_fs();
+	set_fs(get_ds());
+	retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
+			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+	set_fs(old_fs);
+	
+	elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+	if (elf_exec_fileno < 0) return 0xffffffff;
+	file = current->filp[elf_exec_fileno];
+
+	eppnt = elf_phdata;
+	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+	  if(eppnt->p_type == PT_LOAD) {
+	    error = do_mmap(file, 
+			    eppnt->p_vaddr & 0xfffff000,
+			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+			    PROT_READ | PROT_WRITE | PROT_EXEC,
+			    MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
+			    eppnt->p_offset & 0xfffff000);
+	    
+	    if(!load_addr && interp_elf_ex->e_type == ET_DYN)
+	      load_addr = error;
+	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+	    if(k > elf_bss) elf_bss = k;
+	    if(error < 0 && error > -1024) break;  /* Real error */
+	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+	    if(k > last_bss) last_bss = k;
+	  }
+	
+	/* Now use mmap to map the library into memory. */
+
+	
+	sys_close(elf_exec_fileno);
+	if(error < 0 && error > -1024) {
+	        kfree(elf_phdata);
+		return 0xffffffff;
+	}
+
+	padzero(elf_bss);
+	len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
+
+	/* Map the last of the bss segment */
+	if (last_bss > len)
+	  do_mmap(NULL, len, last_bss-len,
+		  PROT_READ|PROT_WRITE|PROT_EXEC,
+		  MAP_FIXED|MAP_PRIVATE, 0);
+	kfree(elf_phdata);
+
+	return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
+}
+
+static unsigned int load_aout_interp(struct exec * interp_ex,
+			     struct inode * interpreter_inode)
+{
+  int retval;
+  unsigned int elf_entry;
+  
+  current->brk = interp_ex->a_bss +
+    (current->end_data = interp_ex->a_data +
+     (current->end_code = interp_ex->a_text));
+  elf_entry = interp_ex->a_entry;
+  
+  
+  if (N_MAGIC(*interp_ex) == OMAGIC) {
+    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+    retval = read_exec(interpreter_inode, 32, (char *) 0, 
+		       interp_ex->a_text+interp_ex->a_data);
+  } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+    do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+    retval = read_exec(interpreter_inode,
+		       N_TXTOFF(*interp_ex) ,
+		       (char *) N_TXTADDR(*interp_ex),
+		       interp_ex->a_text+interp_ex->a_data);
+  } else
+    retval = -1;
+  
+  if(retval >= 0)
+    do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & 
+	    0xfffff000, interp_ex->a_bss,
+	    PROT_READ|PROT_WRITE|PROT_EXEC,
+	    MAP_FIXED|MAP_PRIVATE, 0);
+  if(retval < 0) return 0xffffffff;
+  return elf_entry;
+}
+
 /*
  * These are the functions used to load ELF style executables and shared
  * libraries.  There is no binary dependent code anywhere else.
  */
 
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
 int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 {
 	struct elfhdr elf_ex;
+	struct elfhdr interp_elf_ex;
 	struct file * file;
-  	struct exec ex;
+  	struct exec interp_ex;
 	struct inode *interpreter_inode;
+	unsigned int load_addr;
+	unsigned int interpreter_type = INTERPRETER_NONE;
 	int i;
 	int old_fs;
 	int error;
@@ -69,6 +275,7 @@
 	char passed_fileno[6];
 	
 	status = 0;
+	load_addr = 0;
 	elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
 	
 	if (elf_ex.e_ident[0] != 0x7f ||
@@ -141,12 +348,15 @@
 				retval = read_exec(interpreter_inode,0,bprm->buf,128);
 			
 			if(retval >= 0){
-				ex = *((struct exec *) bprm->buf);		/* exec-header */
+				interp_ex = *((struct exec *) bprm->buf);		/* exec-header */
+				interp_elf_ex = *((struct elfhdr *) bprm->buf);	  /* exec-header */
 				
-#if 0
-				printk("Interpreter: %x %x %x\n",N_MAGIC(ex), ex.a_text,ex.a_data);
-#endif
 			};
+			if(retval < 0) {
+			  kfree (elf_phdata);
+			  kfree(elf_interpreter);
+			  return retval;
+			};
 		};
 		elf_ppnt++;
 	};
@@ -155,16 +365,28 @@
 	
 	/* Some simple consistency checks for the interpreter */
 	if(elf_interpreter){
+	        interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
 		if(retval < 0) {
 			kfree(elf_interpreter);
 			kfree(elf_phdata);
 			return -ELIBACC;
 		};
-		if((N_MAGIC(ex) != OMAGIC) && (N_MAGIC(ex) != ZMAGIC)) {
-			kfree(elf_interpreter);
-			kfree(elf_phdata);
-			return -ELIBBAD;
-		};
+		/* Now figure out which format our binary is */
+		if((N_MAGIC(interp_ex) != OMAGIC) && 
+		   (N_MAGIC(interp_ex) != ZMAGIC) &&
+		   (N_MAGIC(interp_ex) != QMAGIC)) 
+		  interpreter_type = INTERPRETER_ELF;
+
+		if (interp_elf_ex.e_ident[0] != 0x7f ||
+		    strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
+		  interpreter_type &= ~INTERPRETER_ELF;
+
+		if(!interpreter_type)
+		  {
+		    kfree(elf_interpreter);
+		    kfree(elf_phdata);
+		    return -ELIBBAD;
+		  };
 	}
 	
 	/* OK, we are done with that, now set up the arg stuff,
@@ -173,12 +395,14 @@
 	if (!bprm->sh_bang) {
 		char * passed_p;
 		
-		sprintf(passed_fileno, "%d", elf_exec_fileno);
-		passed_p = passed_fileno;
+		if(interpreter_type == INTERPRETER_AOUT) {
+		  sprintf(passed_fileno, "%d", elf_exec_fileno);
+		  passed_p = passed_fileno;
 		
-		if(elf_interpreter) {
-			bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
-			bprm->argc++;
+		  if(elf_interpreter) {
+		    bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
+		    bprm->argc++;
+		  };
 		};
 		if (!bprm->p) {
 		        if(elf_interpreter) {
@@ -217,49 +441,27 @@
 		
 		if(elf_ppnt->p_type == PT_INTERP) {
 			/* Set these up so that we are able to load the interpreter */
-			current->brk = ex.a_bss +
-				(current->end_data = ex.a_data +
-				 (current->end_code = ex.a_text));
-			elf_entry = ex.a_entry;
-			
-			/* Now load the interpreter into user address space */
-			set_fs(old_fs);
-			
-			if (N_MAGIC(ex) == OMAGIC) {
-			  do_mmap(NULL, 0, ex.a_text+ex.a_data,
-				  PROT_READ|PROT_WRITE|PROT_EXEC,
-				  MAP_FIXED|MAP_PRIVATE, 0);
-			  retval = read_exec(interpreter_inode, 32, (char *) 0, 
-					     ex.a_text+ex.a_data);
-				iput(interpreter_inode);
-			} else if (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC) {
-			  do_mmap(NULL, 0, ex.a_text+ex.a_data,
-				  PROT_READ|PROT_WRITE|PROT_EXEC,
-				  MAP_FIXED|MAP_PRIVATE, 0);
-			  retval = read_exec(interpreter_inode,
-					     N_TXTOFF(ex) ,
-					     (char *) N_TXTADDR(ex),
-					     ex.a_text+ex.a_data);
-			  iput(interpreter_inode);
-			} else
-				retval = -1;
-			
-			old_fs = get_fs();
-			set_fs(get_ds());
-			
-			if(retval >= 0)
-			  do_mmap(NULL, (ex.a_text + ex.a_data + 0xfff) & 
-				  0xfffff000, ex.a_bss,
-				  PROT_READ|PROT_WRITE|PROT_EXEC,
-				  MAP_FIXED|MAP_PRIVATE, 0);
+		  /* Now load the interpreter into user address space */
+		  set_fs(old_fs);
 
-			kfree(elf_interpreter);
-			
-			if(retval < 0) { 
-				kfree(elf_phdata);
-				send_sig(SIGSEGV, current, 0);
-				return 0;
-			};
+		  if(interpreter_type & 1) elf_entry = 
+		    load_aout_interp(&interp_ex, interpreter_inode);
+
+		  if(interpreter_type & 2) elf_entry = 
+		    load_elf_interp(&interp_elf_ex, interpreter_inode);
+
+		  old_fs = get_fs();
+		  set_fs(get_ds());
+
+		  iput(interpreter_inode);
+		  kfree(elf_interpreter);
+			
+		  if(elf_entry == 0xffffffff) { 
+		    printk("Unable to load interpreter\n");
+		    kfree(elf_phdata);
+		    send_sig(SIGSEGV, current, 0);
+		    return 0;
+		  };
 		};
 		
 		
@@ -276,6 +478,8 @@
 				elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
 #endif
 			
+			if(!load_addr) 
+			  load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
 			k = elf_ppnt->p_vaddr;
 			if(k > start_code) start_code = k;
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
@@ -285,14 +489,7 @@
 			if(end_data < k) end_data = k; 
 			k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
 			if(k > elf_brk) elf_brk = k;		     
-			
-			if(status == 0xffffffff) {
-				set_fs(old_fs);
-				kfree(elf_phdata);
-				send_sig(SIGSEGV, current, 0);
-				return 0;
-			};
-		};
+		      };
 		elf_ppnt++;
 	};
 	set_fs(old_fs);
@@ -307,8 +504,15 @@
 	current->start_stack = p = elf_stack - 4;
 #endif
 	bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
-	bprm->p = (unsigned long) create_tables((char *)bprm->p,bprm->argc,bprm->envc,0);
-	if(elf_interpreter) current->arg_start += strlen(passed_fileno) + 1;
+	bprm->p = (unsigned long) 
+	  create_elf_tables((char *)bprm->p,
+			bprm->argc,
+			bprm->envc,
+			(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+			load_addr,    
+			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+	if(interpreter_type == INTERPRETER_AOUT)
+	  current->arg_start += strlen(passed_fileno) + 1;
 	current->start_brk = current->brk = elf_brk;
 	current->end_code = end_code;
 	current->start_code = start_code;
@@ -324,6 +528,13 @@
 
 	padzero(elf_bss);
 
+	/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
+	   and some applications "depend" upon this behavior.
+	   Since we do not have the power to recompile these, we
+	   emulate the SVr4 behavior.  Sigh.  */
+	error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+			MAP_FIXED | MAP_PRIVATE, 0);
+
 	regs->eip = elf_entry;		/* eip, magic happens :-) */
 	regs->esp = bprm->p;			/* stack pointer */
 	if (current->flags & PF_PTRACED)
@@ -331,8 +542,8 @@
 	return 0;
 }
 
-/* This is really simpleminded and specialized - we are loading an a.out library that is given
-   an ELF header */
+/* This is really simpleminded and specialized - we are loading an
+   a.out library that is given an ELF header. */
 
 int load_elf_library(int fd){
         struct file * file;
diff -u +recursive +new-file 0.99pl15/linux/fs/buffer.c linux/fs/buffer.c
--- 0.99pl15/linux/fs/buffer.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/buffer.c	Thu Mar 10 14:20:55 1994
@@ -484,17 +484,15 @@
 #endif
 	}
 
-	if (!bh && nr_free_pages > 5) {
-		if (grow_buffers(GFP_BUFFER, size))
-			goto repeat;
-	}
-	
-/* and repeat until we find something good */
 	if (!bh) {
+		if (nr_free_pages > 5)
+			if (grow_buffers(GFP_BUFFER, size))
+				goto repeat;
 		if (!grow_buffers(GFP_ATOMIC, size))
 			sleep_on(&buffer_wait);
 		goto repeat;
 	}
+
 	wait_on_buffer(bh);
 	if (bh->b_count || bh->b_size != size)
 		goto repeat;
@@ -750,16 +748,14 @@
 	bh = create_buffers(address, size);
 	if (!bh)
 		return 0;
+	/* do any of the buffers already exist? punt if so.. */
 	p = b;
 	for (offset = 0 ; offset < PAGE_SIZE ; offset += size) {
 		block = *(p++);
 		if (!block)
 			goto not_aligned;
-		tmp = get_hash_table(dev, block, size);
-		if (tmp) {
-			brelse(tmp);
+		if (find_buffer(dev, block, size))
 			goto not_aligned;
-		}
 	}
 	tmp = bh;
 	p = b;
@@ -920,7 +916,7 @@
 	do {
 		if (!tmp)
 			return 0;
-		if (tmp->b_count || tmp->b_dirt || tmp->b_lock)
+		if (tmp->b_count || tmp->b_dirt || tmp->b_lock || tmp->b_wait)
 			return 0;
 		tmp = tmp->b_this_page;
 	} while (tmp != bh);
@@ -956,8 +952,14 @@
 	bh = free_list;
 	i = nr_buffers >> priority;
 	for ( ; i-- > 0 ; bh = bh->b_next_free) {
-		if (bh->b_count || !bh->b_this_page)
+		if (bh->b_count ||
+		    (priority >= 5 &&
+		     mem_map[MAP_NR((unsigned long) bh->b_data)] > 1)) {
+			put_last_free(bh);
 			continue;
+		}
+		if (!bh->b_this_page)
+			continue;
 		if (bh->b_lock)
 			if (priority)
 				continue;
@@ -973,6 +975,29 @@
 			return 1;
 	}
 	return 0;
+}
+
+void show_buffers(void)
+{
+	struct buffer_head * bh;
+	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
+
+	printk("Buffer memory:   %6dkB\n",buffermem>>10);
+	printk("Buffer heads:    %6d\n",nr_buffer_heads);
+	printk("Buffer blocks:   %6d\n",nr_buffers);
+	bh = free_list;
+	do {
+		found++;
+		if (bh->b_lock)
+			locked++;
+		if (bh->b_dirt)
+			dirty++;
+		if (bh->b_count)
+			used++, lastused = found;
+		bh = bh->b_next_free;
+	} while (bh != free_list);
+	printk("Buffer mem: %d buffers, %d used (last=%d), %d locked, %d dirty\n",
+		found, used, lastused, locked, dirty);
 }
 
 /*
diff -u +recursive +new-file 0.99pl15/linux/fs/exec.c linux/fs/exec.c
--- 0.99pl15/linux/fs/exec.c	Thu Jan 20 14:36:50 1994
+++ linux/fs/exec.c	Fri Mar  4 14:10:38 1994
@@ -134,7 +134,11 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 	memcpy(corefile,"core.",5);
+#if 0
 	memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+	corefile[4] = '\0';
+#endif
 	if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
 		inode = NULL;
 		goto end_coredump;
@@ -688,6 +692,7 @@
 		retval = fn(&bprm, regs);
 		if (retval == 0) {
 			iput(bprm.inode);
+			current->did_exec = 1;
 			return 0;
 		}
 		fmt++;
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES
--- 0.99pl15/linux/fs/ext2/CHANGES	Sun Jan  9 16:47:20 1994
+++ linux/fs/ext2/CHANGES	Thu Mar 10 18:48:35 1994
@@ -1,3 +1,14 @@
+Changes from version 0.4b to version 0.5
+========================================
+	- New superblock fields: s_lastcheck and s_checkinterval added
+	  by Uwe Ohse <uwe@tirka.gun.de> to implement timedependent checks
+	  of the file system
+	- Real random numbers for secure rm added by Pierre del Perugia
+	  <delperug@gla.ecoledoc.ibp.fr>
+	- The mount warnings related to the state of a fs are not printed
+	  if the fs is mounted read-only, idea by Nick Holloway
+	  <alfie@dcs.warwick.ac.uk>
+
 Changes from version 0.4a to version 0.4b
 =========================================
 	- Copyrights changed to include the name of my laboratory.
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- 0.99pl15/linux/fs/ext2/balloc.c	Thu Feb  3 13:22:23 1994
+++ linux/fs/ext2/balloc.c	Tue Feb 22 08:15:49 1994
@@ -359,16 +359,13 @@
 
 	ext2_debug ("goal=%lu.\n", goal);
 
-	if (goal < es->s_first_data_block || goal >= es->s_blocks_count) {
-		ext2_warning (sb, "ext2_new_block",
-			      "Goal out of bounds: %lu", goal);
-		goal = es->s_first_data_block;
-	}
 repeat:
 	/*
 	 * First, test whether the goal block is free.
 	 */
-	i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb));
+	if (goal < es->s_first_data_block || goal >= es->s_blocks_count)
+		goal = es->s_first_data_block;
+	i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb);
 	gdp = get_group_desc (sb, i, &bh2);
 	if (gdp->bg_free_blocks_count > 0) {
 		j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
@@ -608,6 +605,7 @@
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
+	unsigned long desc_blocks;
 	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i, j;
@@ -617,6 +615,8 @@
 	desc_count = 0;
 	bitmap_count = 0;
 	gdp = NULL;
+	desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
+		      EXT2_DESC_PER_BLOCK(sb);
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
 		desc_count += gdp->bg_free_blocks_count;
@@ -623,6 +623,16 @@
 		bitmap_nr = load_block_bitmap (sb, i);
 		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
+		if (!test_bit (0, bh->b_data))
+			ext2_error (sb, "ext2_check_blocks_bitmap",
+				    "Superblock in group %d is marked free", i);
+
+		for (j = 0; j < desc_blocks; j++)
+			if (!test_bit (j + 1, bh->b_data))
+				ext2_error (sb, "ext2_check_blocks_bitmap",
+					    "Descriptor block #%d in group "
+					    "%d is marked free", j, i);
+
 		if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Block bitmap for group %d is marked free",
@@ -635,9 +645,9 @@
 
 		for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++)
 			if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
-			ext2_error (sb, "ext2_check_blocks_bitmap",
-				    "Block #%d of the inode table in group %d "
-				    "is marked free", j, i);
+				ext2_error (sb, "ext2_check_blocks_bitmap",
+					    "Block #%d of the inode table in "
+					    "group %d is marked free", j, i);
 
 		x = ext2_count_free (bh, sb->s_blocksize);
 		if (gdp->bg_free_blocks_count != x)
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- 0.99pl15/linux/fs/ext2/inode.c	Sat Jan  8 14:35:10 1994
+++ linux/fs/ext2/inode.c	Mon Feb  7 15:32:00 1994
@@ -69,10 +69,11 @@
 {
 #ifdef EXT2_PREALLOCATE
 	if (inode->u.ext2_i.i_prealloc_count) {
+		int i = inode->u.ext2_i.i_prealloc_count;
+		inode->u.ext2_i.i_prealloc_count = 0;
 		ext2_free_blocks (inode->i_sb,
 				  inode->u.ext2_i.i_prealloc_block,
-				  inode->u.ext2_i.i_prealloc_count);
-		inode->u.ext2_i.i_prealloc_count = 0;
+				  i);
 	}
 #endif
 }
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- 0.99pl15/linux/fs/ext2/namei.c	Fri Dec 31 11:59:50 1993
+++ linux/fs/ext2/namei.c	Fri Feb 11 14:55:41 1994
@@ -653,15 +653,13 @@
 		retval = -ENOTDIR;
 		goto end_rmdir;
 	}
-	if (!empty_dir (inode)) {
+	down(&inode->i_sem);
+	if (!empty_dir (inode))
 		retval = -ENOTEMPTY;
-		goto end_rmdir;
-	}
-	if (de->inode != inode->i_ino) {
+	else if (de->inode != inode->i_ino)
 		retval = -ENOENT;
-		goto end_rmdir;
-	}
-	if (inode->i_count > 1) {
+	else {
+		if (inode->i_count > 1) {
 		/*
 		 * Are we deleting the last instance of a busy directory?
 		 * Better clean up if so.
@@ -669,9 +667,11 @@
 		 * Make directory empty (it will be truncated when finally
 		 * dereferenced).  This also inhibits ext2_add_entry.
 		 */
-		inode->i_size = 0;
+			inode->i_size = 0;
+		}
+		retval = ext2_delete_entry (de, bh);
 	}
-	retval = ext2_delete_entry (de, bh);
+	up(&inode->i_sem);
 	if (retval)
 		goto end_rmdir;
 	bh->b_dirt = 1;
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- 0.99pl15/linux/fs/ext2/super.c	Sun Jan  9 16:47:21 1994
+++ linux/fs/ext2/super.c	Thu Mar 10 18:48:35 1994
@@ -267,17 +267,21 @@
 static void ext2_setup_super (struct super_block * sb,
 			      struct ext2_super_block * es)
 {
-	if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
-		printk ("EXT2-fs warning: mounting unchecked fs, "
-			"running e2fsck is recommended\n");
-	else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
-		printk ("EXT2-fs warning: mounting fs with errors, "
-			"running e2fsck is recommended\n");
-	else if (es->s_max_mnt_count >= 0 &&
-	         es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
-		printk ("EXT2-fs warning: maximal mount count reached, "
-			"running e2fsck is recommended\n");
 	if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
+			printk ("EXT2-fs warning: mounting unchecked fs, "
+				"running e2fsck is recommended\n");
+		else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
+			printk ("EXT2-fs warning: mounting fs with errors, "
+				"running e2fsck is recommended\n");
+		else if (es->s_max_mnt_count >= 0 &&
+		         es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
+			printk ("EXT2-fs warning: maximal mount count reached, "
+				"running e2fsck is recommended\n");
+		else if (es->s_checkinterval &&
+			(es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME))
+			printk ("EXT2-fs warning: checktime reached, "
+				"running e2fsck is recommended\n");
 		es->s_state &= ~EXT2_VALID_FS;
 		if (!es->s_max_mnt_count)
 			es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
diff -u +recursive +new-file 0.99pl15/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- 0.99pl15/linux/fs/ext2/truncate.c	Sat Jan  8 14:35:10 1994
+++ linux/fs/ext2/truncate.c	Tue Feb 22 08:15:49 1994
@@ -12,6 +12,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
@@ -28,6 +33,10 @@
 		:"a" (value), "c" (size / 4), "D" ((long) (addr)) \
 		:"cx", "di")
 
+static int ext2_secrm_seed = 152;	/* Random generator base */
+
+#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
+
 /*
  * Truncate has the most races in the whole filesystem: coding it is
  * a pain in the a**. Especially as I don't do any locking...
@@ -80,7 +89,7 @@
 		inode->i_dirt = 1;
 		if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
 			clear_block (bh->b_data, inode->i_sb->s_blocksize,
-				     CURRENT_TIME);
+				     RANDOM_INT);
 			bh->b_dirt = 1;
 		}
 		brelse (bh);
@@ -156,7 +165,7 @@
 		ind_bh->b_dirt = 1;
 		if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
 			clear_block (bh->b_data, inode->i_sb->s_blocksize,
-				     CURRENT_TIME);
+				     RANDOM_INT);
 			bh->b_dirt = 1;
 		}
 		brelse (bh);
diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/README linux/fs/hpfs/README
--- 0.99pl15/linux/fs/hpfs/README
+++ linux/fs/hpfs/README	Wed Feb 23 09:45:39 1994
@@ -0,0 +1,25 @@
+Linux can read, but not write, OS/2 HPFS partitions.
+
+Mount options are the same as for msdos partitions.
+
+  uid=nnn	All files in the partition will be owned by user id nnn.
+  gid=nnn	All files in the partition will be in group nnn.
+  umask=nnn	The permission mask (see umask(1)) for the partition.
+  conv=binary   Data is returned exactly as is, with CRLF's.  [default]
+  conv=text     (Carriage return, line feed) is replaced with newline.
+  conv=auto     Chooses, file by file, conv=binary or conv=text (by guessing)
+
+There is one mount option unique to HPFS.
+
+  case=lower	Convert file names to lower case.  [default]
+  case=asis     Return file names as is, in mixed case.
+
+Case is not significant in filename matching, like real HPFS.
+
+
+Command line example
+    mkdir -p /os2/c
+    mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c
+
+/etc/fstab example
+    /dev/sdb5	/d/f    hpfs    ro,uid=402,gid=402,umask=002
diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/hpfs.h linux/fs/hpfs/hpfs.h
--- 0.99pl15/linux/fs/hpfs/hpfs.h	Wed Dec  1 14:44:15 1993
+++ linux/fs/hpfs/hpfs.h	Wed Feb 23 09:45:39 1994
@@ -131,7 +131,7 @@
 
 /* The code page info pointed to by the spare block consists of an index
    block and blocks containing character maps.  The following is pretty
-   sketchy, but Linux is Latin-1 so it doesn't matter. */
+   sketchy, but Linux doesn't use code pages so it doesn't matter. */
 
 /* block pointed to by spareblock->code_page_dir */
 
diff -u +recursive +new-file 0.99pl15/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- 0.99pl15/linux/fs/hpfs/hpfs_fs.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/hpfs/hpfs_fs.c	Wed Feb 23 09:45:40 1994
@@ -6,7 +6,7 @@
  *  Chris Smith 1993
  *
  *  Sources & references:
- *   Duncan, _Design ... of HPFS_, MSSJ 4(5)   (C) 1989 Microsoft Corp
+ *   Duncan, _Design ... of HPFS_, MSJ 4(5)   (C) 1989 Microsoft Corp
  *   linux/fs/minix  Copyright (C) 1991, 1992, 1993  Linus Torvalds
  *   linux/fs/msdos  Written 1992, 1993 by Werner Almesberger
  *   linux/fs/isofs  Copyright (C) 1991  Eric Youngdale
@@ -124,7 +124,7 @@
 static void hpfs_read_inode(struct inode *);
 static void hpfs_put_super(struct super_block *);
 static void hpfs_statfs(struct super_block *, struct statfs *);
-static int hpfs_remount_fs(struct super_block *, int *);
+static int hpfs_remount_fs(struct super_block *, int *, char *);
 
 static const struct super_operations hpfs_sops =
 {
@@ -752,7 +752,7 @@
  * remount.  Don't let read only be turned off.
  */
 
-static int hpfs_remount_fs(struct super_block *s, int *flags)
+static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 {
 	if (!(*flags & MS_RDONLY))
 		return -EINVAL;
diff -u +recursive +new-file 0.99pl15/linux/fs/inode.c linux/fs/inode.c
--- 0.99pl15/linux/fs/inode.c	Wed Feb  2 08:45:07 1994
+++ linux/fs/inode.c	Fri Feb 11 14:13:07 1994
@@ -384,6 +384,7 @@
 	clear_inode(inode);
 	inode->i_count = 1;
 	inode->i_nlink = 1;
+	inode->i_sem.count = 1;
 	nr_free_inodes--;
 	if (nr_free_inodes < 0) {
 		printk ("VFS: get_empty_inode: bad free inode count.\n");
diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- 0.99pl15/linux/fs/isofs/dir.c	Sun Dec 12 12:26:43 1993
+++ linux/fs/isofs/dir.c	Tue Mar  1 18:47:38 1994
@@ -191,6 +191,8 @@
 			    for (i = 0; i < dlen && i < NAME_MAX; i++) {
 			      if (!(c = dpnt[i])) break;
 			      if (c >= 'A' && c <= 'Z') c |= 0x20;  /* lower case */
+			      if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
+				break;  /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
 			      if (c == ';' && i == dlen-2 && de->name[i+1] == '1') 
 				break;  /* Drop trailing ';1' */
 			      if (c == ';') c = '.';  /* Convert remaining ';' to '.' */
diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- 0.99pl15/linux/fs/isofs/inode.c	Sat Jan 29 14:55:06 1994
+++ linux/fs/isofs/inode.c	Sun Mar 13 20:39:14 1994
@@ -344,7 +344,7 @@
 	if (!(bh=bread(inode->i_dev,block, bufsize))) {
 	  printk("unable to read i-node block");
 	  goto fail;
-	};
+	}
 	
 	pnt = ((unsigned char *) bh->b_data
 	       + (inode->i_ino & (bufsize - 1)));
@@ -353,18 +353,23 @@
 
 	if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
 		cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
+		if (cpnt == NULL) {
+			printk(KERN_INFO "NoMem ISO inode %d\n",inode->i_ino);
+			brelse(bh);
+			goto fail;
+		}
 		memcpy(cpnt, bh->b_data, bufsize);
 		brelse(bh);
 		if (!(bh = bread(inode->i_dev,++block, bufsize))) {
-		        kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
+			kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
 			printk("unable to read i-node block");
 			goto fail;
-		      };
+		}
 		memcpy((char *)cpnt + bufsize, bh->b_data, bufsize);
 		pnt = ((unsigned char *) cpnt
 		       + (inode->i_ino & (bufsize - 1)));
 		raw_inode = ((struct iso_directory_record *) pnt);
-	};
+	}
 
 	inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */
 	inode->i_nlink = 1;
@@ -383,7 +388,7 @@
 				break;
 		if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';') 
 			inode->i_mode |= S_IXUGO; /* execute permission */
-	};
+	}
 	inode->i_uid = 0;
 	inode->i_gid = 0;
 	inode->i_size = isonum_733 (raw_inode->size);
@@ -394,7 +399,7 @@
 	    inode->i_sb->u.isofs_sb.s_cruft == 'n') {
 	  printk("Warning: defective cdrom.  Enabling \"cruft\" mount option.\n");
 	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
-	};
+	}
 
 /* Some dipshit decided to store some other bit of information in the high
    byte of the file length.  Catch this and holler.  WARNING: this will make
@@ -404,12 +409,12 @@
 	   inode->i_size & 0xff000000){
 /*	  printk("Illegal format on cdrom.  Pester manufacturer.\n"); */
 	  inode->i_size &= 0x00ffffff;
-	};
+	}
 	
 	if (raw_inode->interleave[0]) {
 		printk("Interleaved files not (yet) supported.\n");
 		inode->i_size = 0;
-	};
+	}
 
 #ifdef DEBUG
 	/* I have no idea what extended attributes are used for, so
@@ -458,8 +463,7 @@
 	case 'm':
 	  inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M; /* File type */
 	  break;
-	};
-	
+	}
 
 /* Now test for possible Rock Ridge extensions which will override some of
    these numbers in the inode structure. */
@@ -472,11 +476,6 @@
 #endif
 	brelse(bh);
 	
-	if (cpnt) {
-		kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
-		cpnt = NULL;
-	};
-	
 	inode->i_op = NULL;
 	if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && 
 	    isonum_723 (raw_inode->volume_sequence_number) != 1) {
@@ -494,6 +493,10 @@
 	    inode->i_op = &blkdev_inode_operations;
 	  else if (S_ISFIFO(inode->i_mode))
 	    init_fifo(inode);
+	}
+	if (cpnt) {
+		kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
+		cpnt = NULL;
 	}
 	return;
       fail:
diff -u +recursive +new-file 0.99pl15/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- 0.99pl15/linux/fs/isofs/rock.c	Sat Jan  8 14:35:11 1994
+++ linux/fs/isofs/rock.c	Tue Mar  1 18:45:15 1994
@@ -316,6 +316,7 @@
 	 struct SL_component * slp;
 	 slen = rr->len - 5;
 	 slp = &rr->u.SL.link;
+	 inode->i_size = 0;
 	 while (slen > 1){
 	   rootflag = 0;
 	   switch(slp->flags &~1){
diff -u +recursive +new-file 0.99pl15/linux/fs/namei.c linux/fs/namei.c
--- 0.99pl15/linux/fs/namei.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/namei.c	Sun Feb 13 14:01:51 1994
@@ -275,7 +275,7 @@
 	struct inode ** res_inode, struct inode * base)
 {
 	const char * basename;
-	int namelen,error,i;
+	int namelen,error;
 	struct inode * dir, *inode;
 	struct task_struct ** p;
 
@@ -297,43 +297,35 @@
 		*res_inode=dir;
 		return 0;
 	}
-	for (i = 0; i < 5; i++) {	/* races... */
-		dir->i_count++;		/* lookup eats the dir */
+	dir->i_count++;		/* lookup eats the dir */
+	if (flag & O_CREAT) {
+		down(&dir->i_sem);
 		error = lookup(dir,basename,namelen,&inode);
-		if (!error)
-			break;
-		if (!(flag & O_CREAT)) {
-			iput(dir);
-			return error;
-		}
-		if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
-			iput(dir);
-			return -EACCES;
-		}
-		if (!dir->i_op || !dir->i_op->create) {
-			iput(dir);
-			return -EACCES;
-		}
-		if (IS_RDONLY(dir)) {
-			iput(dir);
-			return -EROFS;
-		}
-		dir->i_count++;		/* create eats the dir */
-		error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
-		if (error != -EEXIST) {
+		if (!error) {
+			if (flag & O_EXCL) {
+				iput(inode);
+				error = -EEXIST;
+			}
+		} else if (!permission(dir,MAY_WRITE | MAY_EXEC))
+			error = -EACCES;
+		else if (!dir->i_op || !dir->i_op->create)
+			error = -EACCES;
+		else if (IS_RDONLY(dir))
+			error = -EROFS;
+		else {
+			dir->i_count++;		/* create eats the dir */
+			error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
+			up(&dir->i_sem);
 			iput(dir);
 			return error;
 		}
-	}
+		up(&dir->i_sem);
+	} else
+		error = lookup(dir,basename,namelen,&inode);
 	if (error) {
 		iput(dir);
 		return error;
 	}
-	if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
-		iput(dir);
-		iput(inode);
-		return -EEXIST;
-	}
 	error = follow_link(dir,inode,flag,mode,&inode);
 	if (error)
 		return error;
@@ -415,7 +407,10 @@
 		iput(dir);
 		return -EPERM;
 	}
-	return dir->i_op->mknod(dir,basename,namelen,mode,dev);
+	down(&dir->i_sem);
+	error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
+	up(&dir->i_sem);
+	return error;
 }
 
 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
@@ -467,7 +462,10 @@
 		iput(dir);
 		return -EPERM;
 	}
-	return dir->i_op->mkdir(dir,basename,namelen,mode);
+	down(&dir->i_sem);
+	error = dir->i_op->mkdir(dir,basename,namelen,mode);
+	up(&dir->i_sem);
+	return error;
 }
 
 asmlinkage int sys_mkdir(const char * pathname, int mode)
@@ -590,7 +588,10 @@
 		iput(dir);
 		return -EPERM;
 	}
-	return dir->i_op->symlink(dir,basename,namelen,oldname);
+	down(&dir->i_sem);
+	error = dir->i_op->symlink(dir,basename,namelen,oldname);
+	up(&dir->i_sem);
+	return error;
 }
 
 asmlinkage int sys_symlink(const char * oldname, const char * newname)
@@ -646,7 +647,10 @@
 		iput(oldinode);
 		return -EPERM;
 	}
-	return dir->i_op->link(oldinode, dir, basename, namelen);
+	down(&dir->i_sem);
+	error = dir->i_op->link(oldinode, dir, basename, namelen);
+	up(&dir->i_sem);
+	return error;
 }
 
 asmlinkage int sys_link(const char * oldname, const char * newname)
@@ -719,8 +723,11 @@
 		iput(new_dir);
 		return -EPERM;
 	}
-	return old_dir->i_op->rename(old_dir, old_base, old_len, 
+	down(&new_dir->i_sem);
+	error = old_dir->i_op->rename(old_dir, old_base, old_len, 
 		new_dir, new_base, new_len);
+	up(&new_dir->i_sem);
+	return error;
 }
 
 asmlinkage int sys_rename(const char * oldname, const char * newname)
diff -u +recursive +new-file 0.99pl15/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- 0.99pl15/linux/fs/nfs/proc.c	Wed Dec 29 06:52:29 1993
+++ linux/fs/nfs/proc.c	Mon Feb 14 12:48:36 1994
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/nfs/proc.c
  *
- *  Copyright (C) 1992  Rick Sladkey
+ *  Copyright (C) 1992, 1993, 1994  Rick Sladkey
  *
  *  OS-independent nfs remote procedure call functions
  */
@@ -41,7 +41,7 @@
 
 #endif /* !NFS_PROC_DEBUG */
 
-static int *nfs_rpc_header(int *p, int procedure);
+static int *nfs_rpc_header(int *p, int procedure, int ruid);
 static int *nfs_rpc_verify(int *p);
 static int nfs_stat_to_errno(int stat);
 
@@ -192,11 +192,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  getattr\n");
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_GETATTR);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
 		nfs_rpc_free(p0);
@@ -208,8 +210,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply getattr\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply getattr failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -219,11 +226,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  setattr\n");
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_SETATTR);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	p = xdr_encode_sattr(p, sattr);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
@@ -236,8 +245,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply setattr\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply setattr failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -247,6 +261,7 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  lookup %s\n", name);
 #ifdef NFS_PROC_DEBUG
@@ -255,7 +270,8 @@
 #endif
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_LOOKUP);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
@@ -269,8 +285,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply lookup\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply lookup failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -280,11 +301,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  readlink\n");
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_READLINK);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
 		nfs_rpc_free(p0);
@@ -300,8 +323,13 @@
 		else
 			PRINTK("NFS reply readlink %s\n", res);
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply readlink failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -311,12 +339,14 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 	int len = 0; /* = 0 is for gcc */
 
 	PRINTK("NFS call  read %d @ %d\n", count, offset);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_READ);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	*p++ = htonl(offset);
 	*p++ = htonl(count);
@@ -336,8 +366,13 @@
 		else
 			PRINTK("NFS reply read %d\n", len);
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply read failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
 }
@@ -347,11 +382,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  write %d @ %d\n", count, offset);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_WRITE);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	*p++ = htonl(offset); /* traditional, could be any value */
 	*p++ = htonl(offset);
@@ -367,8 +404,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply write\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply write failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -379,11 +421,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  create %s\n", name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_CREATE);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	p = xdr_encode_sattr(p, sattr);
@@ -398,8 +442,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply create\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply create failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -408,11 +457,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  remove %s\n", name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_REMOVE);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
@@ -424,8 +475,13 @@
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		PRINTK("NFS reply remove\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply remove failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -436,11 +492,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_RENAME);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
 	p = xdr_encode_fhandle(p, old_dir);
 	p = xdr_encode_string(p, old_name);
 	p = xdr_encode_fhandle(p, new_dir);
@@ -454,8 +512,13 @@
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		PRINTK("NFS reply rename\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply rename failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -465,11 +528,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  link %s\n", name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_LINK);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
@@ -482,8 +547,13 @@
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		PRINTK("NFS reply link\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply link failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -493,11 +563,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  symlink %s -> %s\n", name, path);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_SYMLINK);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	p = xdr_encode_string(p, path);
@@ -511,8 +583,13 @@
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		PRINTK("NFS reply symlink\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply symlink failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -523,11 +600,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  mkdir %s\n", name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_MKDIR);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	p = xdr_encode_sattr(p, sattr);
@@ -542,8 +621,13 @@
 		p = xdr_decode_fattr(p, fattr);
 		PRINTK("NFS reply mkdir\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply mkdir failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -552,11 +636,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  rmdir %s\n", name);
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_RMDIR);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
 	p = xdr_encode_fhandle(p, dir);
 	p = xdr_encode_string(p, name);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
@@ -568,8 +654,13 @@
 	else if ((status = ntohl(*p++)) == NFS_OK) {
 		PRINTK("NFS reply rmdir\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply rmdir failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -579,6 +670,7 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 	int i = 0; /* = 0 is for gcc */
 	int size;
 	int eof;
@@ -587,7 +679,8 @@
 	size = server->rsize;
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_READDIR);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	*p++ = htonl(cookie);
 	*p++ = htonl(size);
@@ -615,8 +708,13 @@
 			       eof ? "eof" : "");
 		}
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply readdir failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
 }
@@ -626,11 +724,13 @@
 {
 	int *p, *p0;
 	int status;
+	int ruid = 0;
 
 	PRINTK("NFS call  statfs\n");
 	if (!(p0 = nfs_rpc_alloc()))
 		return -EIO;
-	p = nfs_rpc_header(p0, NFSPROC_STATFS);
+retry:
+	p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
 	p = xdr_encode_fhandle(p, fhandle);
 	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
 		nfs_rpc_free(p0);
@@ -642,8 +742,13 @@
 		p = xdr_decode_fsinfo(p, res);
 		PRINTK("NFS reply statfs\n");
 	}
-	else
+	else {
+		if (!ruid && current->euid == 0 && current->uid != 0) {
+			ruid = 1;
+			goto retry;
+		}
 		PRINTK("NFS reply statfs failed = %d\n", status);
+	}
 	nfs_rpc_free(p0);
 	return -nfs_stat_to_errno(status);
 }
@@ -652,7 +757,7 @@
  * Here are a few RPC-assist functions.
  */
 
-static int *nfs_rpc_header(int *p, int procedure)
+static int *nfs_rpc_header(int *p, int procedure, int ruid)
 {
 	int *p1, *p2;
 	int i;
@@ -673,7 +778,7 @@
 	p1 = p++;
 	*p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
 	p = xdr_encode_string(p, (char *) sys);
-	*p++ = htonl(current->euid);
+	*p++ = htonl(ruid ? current->uid : current->euid);
 	*p++ = htonl(current->egid);
 	p2 = p++;
 	for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++)
diff -u +recursive +new-file 0.99pl15/linux/fs/nfs/sock.c linux/fs/nfs/sock.c
--- 0.99pl15/linux/fs/nfs/sock.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/nfs/sock.c	Tue Mar  1 08:03:41 1994
@@ -108,7 +108,7 @@
 					continue;
 				if (server->flags & NFS_MOUNT_SOFT) {
 					printk("NFS server %s not responding, "
-						"timed out", server_name);
+						"timed out\n", server_name);
 					result = -EIO;
 					break;
 				}
diff -u +recursive +new-file 0.99pl15/linux/fs/proc/array.c linux/fs/proc/array.c
--- 0.99pl15/linux/fs/proc/array.c	Thu Feb  3 13:18:45 1994
+++ linux/fs/proc/array.c	Thu Feb 17 10:36:54 1994
@@ -42,10 +42,10 @@
 
 	if (count < 0)
 		return -EINVAL;
-	if (p >= high_memory)
+	if (p >= high_memory + PAGE_SIZE)
 		return 0;
-	if (count > high_memory - p)
-		count = high_memory - p;
+	if (count > high_memory + PAGE_SIZE - p)
+		count = high_memory + PAGE_SIZE - p;
 	read = 0;
 
 	if (p < sizeof(struct user) && count > 0) {
@@ -441,7 +441,7 @@
 	return sz;
 }
 
-asmlinkage int get_module_list( char *);
+extern int get_module_list(char *);
 
 static int array_read(struct inode * inode, struct file * file,char * buf, int count)
 {
diff -u +recursive +new-file 0.99pl15/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- 0.99pl15/linux/fs/proc/inode.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/proc/inode.c	Wed Feb 23 09:47:59 1994
@@ -84,7 +84,8 @@
 	inode->i_nlink = 1;
 	inode->i_size = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-	inode->i_blocks = inode->i_blksize = 0;
+	inode->i_blocks = 0;
+	inode->i_blksize = 1024;
 	ino = inode->i_ino;
 	pid = ino >> 16;
 	p = task[0];
diff -u +recursive +new-file 0.99pl15/linux/fs/proc/link.c linux/fs/proc/link.c
--- 0.99pl15/linux/fs/proc/link.c	Thu Feb  3 14:47:55 1994
+++ linux/fs/proc/link.c	Fri Mar 11 11:28:10 1994
@@ -111,6 +111,10 @@
 	unsigned int dev,ino;
 	char buf[64];
 
+	if (!S_ISLNK(inode->i_mode)) {
+		iput(inode);
+		return -EINVAL;
+	}
 	i = proc_follow_link(NULL, inode, 0, 0, &inode);
 	if (i)
 		return i;
diff -u +recursive +new-file 0.99pl15/linux/fs/select.c linux/fs/select.c
--- 0.99pl15/linux/fs/select.c	Wed Dec  1 14:44:15 1993
+++ linux/fs/select.c	Thu Feb 24 08:06:53 1994
@@ -223,11 +223,10 @@
 		i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
 		if (i)
 			return i;
-		timeout = jiffies;
-		timeout += ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ));
+		timeout = ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ));
 		timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
-		if (timeout <= jiffies)
-			timeout = 0;
+		if (timeout)
+			timeout += jiffies + 1;
 	}
 	current->timeout = timeout;
 	i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex);
diff -u +recursive +new-file 0.99pl15/linux/fs/super.c linux/fs/super.c
--- 0.99pl15/linux/fs/super.c	Tue Feb  1 07:58:24 1994
+++ linux/fs/super.c	Tue Mar  1 08:27:32 1994
@@ -380,7 +380,7 @@
 	return retval;
 }
 
-static int copy_mount_options (char * data, unsigned long *where)
+static int copy_mount_options (const void * data, unsigned long *where)
 {
 	int i;
 	unsigned long page;
diff -u +recursive +new-file 0.99pl15/linux/include/asm/bitops.h linux/include/asm/bitops.h
--- 0.99pl15/linux/include/asm/bitops.h	Wed Dec  1 14:44:15 1993
+++ linux/include/asm/bitops.h	Fri Feb 11 09:25:54 1994
@@ -89,7 +89,7 @@
 	addr += nr >> 5;
 	mask = 1 << (nr & 0x1f);
 	cli();
-	retval = (mask & *addr) == 0;
+	retval = (mask & *addr) != 0;
 	*addr &= ~mask;
 	sti();
 	return retval;
diff -u +recursive +new-file 0.99pl15/linux/include/asm/io.h linux/include/asm/io.h
--- 0.99pl15/linux/include/asm/io.h	Wed Jan  5 07:41:12 1994
+++ linux/include/asm/io.h	Fri Feb  4 09:59:16 1994
@@ -2,6 +2,19 @@
 #define _ASM_IO_H
 
 /*
+ * This file contains the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl and the "string versions" of the same
+ * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
+ * versions of the single-IO instructions (inb_p/inw_p/..).
+ *
+ * This file is not meant to be obfuscating: it's just complicated
+ * to (a) handle it all in a way that makes gcc able to optimize it
+ * as well as possible and (b) trying to avoid writing the same thing
+ * over and over again with slight variations and possibly making a
+ * mistake somewhere.
+ */
+
+/*
  * Thanks to James van Artsdalen for a better timing-fix than
  * the two short jumps: using outb's to a nonexistent port seems
  * to guarantee better timings even on fast machines.
diff -u +recursive +new-file 0.99pl15/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- 0.99pl15/linux/include/linux/ext2_fs.h	Sun Jan  9 16:47:21 1994
+++ linux/include/linux/ext2_fs.h	Thu Mar 10 18:48:36 1994
@@ -52,8 +52,8 @@
 /*
  * The second extended file system version
  */
-#define EXT2FS_DATE		"94/01/08"
-#define EXT2FS_VERSION		"0.4b"
+#define EXT2FS_DATE		"94/03/10"
+#define EXT2FS_VERSION		"0.5"
 
 /*
  * Debug code
@@ -262,6 +262,7 @@
  * Maximal mount counts between two filesystem checks
  */
 #define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */
 
 /*
  * Behaviour when detecting errors
@@ -294,7 +295,9 @@
 	unsigned short s_state;		/* File system state */
 	unsigned short s_errors;	/* Behaviour when detecting errors */
 	unsigned short s_pad;
-	unsigned long  s_reserved[240];	/* Padding to the end of the block */
+	unsigned long  s_lastcheck;	/* time of last check */
+	unsigned long  s_checkinterval;	/* max. time between checks */
+	unsigned long  s_reserved[238];	/* Padding to the end of the block */
 };
 
 /*
diff -u +recursive +new-file 0.99pl15/linux/include/linux/fs.h linux/include/linux/fs.h
--- 0.99pl15/linux/include/linux/fs.h	Mon Jan  3 09:45:26 1994
+++ linux/include/linux/fs.h	Wed Feb 16 09:29:36 1994
@@ -171,6 +171,7 @@
 	time_t		i_ctime;
 	unsigned long	i_blksize;
 	unsigned long	i_blocks;
+	struct semaphore i_sem;
 	struct inode_operations * i_op;
 	struct super_block * i_sb;
 	struct wait_queue * i_wait;
@@ -319,12 +320,13 @@
 extern void putname(char * name);
 
 extern int register_blkdev(unsigned int, const char *, struct file_operations *);
+extern int unregister_blkdev(unsigned int major, const char * name);
 extern int blkdev_open(struct inode * inode, struct file * filp);
 extern struct file_operations def_blk_fops;
 extern struct inode_operations blkdev_inode_operations;
 
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
-extern int unregister_chrdev( unsigned int major, const char * name);
+extern int unregister_chrdev(unsigned int major, const char * name);
 extern int chrdev_open(struct inode * inode, struct file * filp);
 extern struct file_operations def_chr_fops;
 extern struct inode_operations chrdev_inode_operations;
@@ -392,6 +394,7 @@
 extern void put_super(dev_t dev);
 extern dev_t ROOT_DEV;
 
+extern void show_buffers(void);
 extern void mount_root(void);
 
 extern int char_read(struct inode *, struct file *, char *, int);
diff -u +recursive +new-file 0.99pl15/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- 0.99pl15/linux/include/linux/if_ether.h	Thu Feb  3 15:14:03 1994
+++ linux/include/linux/if_ether.h	Fri Feb 18 11:20:46 1994
@@ -5,9 +5,10 @@
  *
  *		Global definitions for the Ethernet IEE 802.3 interface.
  *
- * Version:	@(#)if_ether.h	1.0.1	03/15/93
+ * Version:	@(#)if_ether.h	1.0.1a	02/08/94
  *
  * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *		Donald Becker, <becker@super.org>
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -18,13 +19,15 @@
 #define _LINUX_IF_ETHER_H
 
 
-/* IEEE 802.3 Ethernet magic constants. */
-#define ETH_ALEN	6		/* #bytes in eth addr		*/
-#define ETH_HLEN	14		/* #bytes in eth header		*/
-#define ETH_ZLEN	64		/* min #bytes in frame		*/
-#define ETH_FLEN	1536		/* max #bytes in frame		*/
-#define ETH_DLEN	(ETH_FLEN - ETH_HLEN)	/* max #bytes of data	*/
+/* IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+   and FCS/CRC (frame check sequence). */
+#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#define ETH_HLEN	14		/* Total octets in header.	 */
+#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
+#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
 
+
 /* These are the defined Ethernet Protocol ID's. */
 #define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
 #define ETH_P_ECHO	0x0200		/* Ethernet Echo packet		*/
@@ -38,9 +41,6 @@
 #define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
 #define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
 
-/* Define the Ethernet Broadcast Address (48 bits set to "1"). */
-#define ETH_A_BCAST     "\377\377\377\377\377\377"
-
 /* This is an Ethernet frame header. */
 struct ethhdr {
   unsigned char		h_dest[ETH_ALEN];	/* destination eth addr	*/
@@ -47,21 +47,6 @@
   unsigned char		h_source[ETH_ALEN];	/* source ether addr	*/
   unsigned short	h_proto;		/* packet type ID field	*/
 };
-
-/* This is the complete Ethernet frame. */
-struct ethframe {
-  struct ethhdr		f_hdr;			/* frame header		*/
-  char			f_data[ETH_DLEN];	/* frame data (variable)*/
-};
-
-
-/* Receiver modes */
-#define ETH_MODE_MONITOR	1	/* Monitor mode - no receive	*/
-#define ETH_MODE_PHYS		2	/* Physical address receive only */
-#define ETH_MODE_BCAST		3	/* Broadcast receive + mode 2	*/
-#define ETH_MODE_MCAST		4	/* Multicast receive + mode 3	*/
-#define ETH_MODE_PROMISC	5	/* Promiscuous mode - receive all */
-
 
 /* Ethernet statistics collection data. */
 struct enet_statistics{
diff -u +recursive +new-file 0.99pl15/linux/include/linux/in_systm.h linux/include/linux/in_systm.h
--- 0.99pl15/linux/include/linux/in_systm.h
+++ linux/include/linux/in_systm.h	Mon Feb 14 18:51:45 1994
@@ -0,0 +1,32 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Miscellaneous internetwork definitions for kernel.
+ *
+ * Version:	@(#)in_systm.h  1.0.0   12/17/93
+ *
+ * Authors:	Original taken from Berkeley BSD UNIX 4.3-RENO.
+ *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IN_SYSTM_H
+#define _LINUX_IN_SYSTM_H
+
+/*
+ * Network types.
+ * The n_ types are network-order variants of their natural
+ * equivalents.  The Linux kernel NET-2 code does not use
+ * them (yet), but it might in the future.  This is mostly
+ * there for compatibility with BSD user-level programs.
+ */
+typedef u_short	n_short;	/* short as received from the net	*/
+typedef u_long	n_long;		/* long as received from the net	*/
+typedef u_long	n_time;		/* ms since 00:00 GMT, byte rev		*/
+
+#endif /* _LINUX_IN_SYSTM_H */
diff -u +recursive +new-file 0.99pl15/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- 0.99pl15/linux/include/linux/interrupt.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/interrupt.h	Mon Mar  7 14:34:14 1994
@@ -24,17 +24,17 @@
 
 extern inline void mark_bh(int nr)
 {
-	__asm__ __volatile__("btsl %1,%0":"=m" (bh_active):"ir" (nr));
+	__asm__ __volatile__("orl %1,%0":"=m" (bh_active):"ir" (1<<nr));
 }
 
 extern inline void disable_bh(int nr)
 {
-	__asm__ __volatile__("btcl %1,%0":"=m" (bh_mask):"ir" (nr));
+	__asm__ __volatile__("andl %1,%0":"=m" (bh_mask):"ir" (~(1<<nr)));
 }
 
 extern inline void enable_bh(int nr)
 {
-	__asm__ __volatile__("btsl %1,%0":"=m" (bh_mask):"ir" (nr));
+	__asm__ __volatile__("orl %1,%0":"=m" (bh_mask):"ir" (1<<nr));
 }
 
 #endif
diff -u +recursive +new-file 0.99pl15/linux/include/linux/keyboard.h linux/include/linux/keyboard.h
--- 0.99pl15/linux/include/linux/keyboard.h	Tue Feb  1 13:04:31 1994
+++ linux/include/linux/keyboard.h	Thu Mar  3 08:05:22 1994
@@ -5,6 +5,10 @@
 #define KG_CTRL		2
 #define KG_ALT		3
 #define KG_ALTGR	1
+#define KG_SHIFTL       4
+#define KG_SHIFTR       5
+#define KG_CTRLL        6
+#define KG_CTRLR        7
 
 #define NR_KEYS 128
 #define NR_KEYMAPS 16
@@ -115,6 +119,10 @@
 #define K_CTRL		K(KT_SHIFT,KG_CTRL)
 #define K_ALT		K(KT_SHIFT,KG_ALT)
 #define K_ALTGR		K(KT_SHIFT,KG_ALTGR)
+#define K_SHIFTL        K(KT_SHIFT,KG_SHIFTL)
+#define K_SHIFTR        K(KT_SHIFT,KG_SHIFTR)
+#define K_CTRLL         K(KT_SHIFT,KG_CTRLL)
+#define K_CTRLR         K(KT_SHIFT,KG_CTRLR)
 
 #define NR_SHIFT	4
 
diff -u +recursive +new-file 0.99pl15/linux/include/linux/math_emu.h linux/include/linux/math_emu.h
--- 0.99pl15/linux/include/linux/math_emu.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/math_emu.h	Wed Feb 16 13:07:57 1994
@@ -9,6 +9,11 @@
 	unsigned sigh;
 };
 
+
+/* This structure matches the layout of the data saved to the stack
+   following a device-not-present interrupt, part of it saved
+   automatically by the 80386/80486.
+   */
 struct info {
 	long ___orig_eip;
 	long ___ret_from_system_call;
@@ -29,30 +34,10 @@
 	long ___eflags;
 	long ___esp;
 	long ___ss;
+	long ___vm86_es; /* This and the following only in vm86 mode */
+	long ___vm86_ds;
+	long ___vm86_fs;
+	long ___vm86_gs;
 };
-
-#if 0
-#define EAX (info->___eax)
-#define EBX (info->___ebx)
-#define ECX (info->___ecx)
-#define EDX (info->___edx)
-#define ESI (info->___esi)
-#define EDI (info->___edi)
-#define EBP (info->___ebp)
-#define ESP (info->___esp)
-#define EIP (info->___eip)
-#define ORIG_EIP (info->___orig_eip)
-#define EFLAGS (info->___eflags)
-#define DS (*(unsigned short *) &(info->___ds))
-#define ES (*(unsigned short *) &(info->___es))
-#define FS (*(unsigned short *) &(info->___fs))
-#define CS (*(unsigned short *) &(info->___cs))
-#define SS (*(unsigned short *) &(info->___ss))
-#endif
-
-void __math_abort(struct info *, unsigned int);
-
-#define math_abort(x,y) \
-(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))
 
 #endif
diff -u +recursive +new-file 0.99pl15/linux/include/linux/mm.h linux/include/linux/mm.h
--- 0.99pl15/linux/include/linux/mm.h	Tue Jan 25 11:56:54 1994
+++ linux/include/linux/mm.h	Mon Feb 14 21:27:12 1994
@@ -11,7 +11,7 @@
 
 int __verify_write(unsigned long addr, unsigned long count);
 
-extern inline int verify_area(int type, void * addr, unsigned long size)
+extern inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	if (TASK_SIZE <= (unsigned long) addr)
 		return -EFAULT;
@@ -81,7 +81,7 @@
 extern int nr_secondary_pages;
 extern unsigned long secondary_page_list;
 
-#define MAX_SECONDARY_PAGES 10
+#define MAX_SECONDARY_PAGES 20
 
 /*
  * This is timing-critical - most of the time in getting a new page
diff -u +recursive +new-file 0.99pl15/linux/include/linux/msg.h linux/include/linux/msg.h
--- 0.99pl15/linux/include/linux/msg.h	Thu Dec 23 13:28:50 1993
+++ linux/include/linux/msg.h	Sun Mar  6 16:10:53 1994
@@ -52,7 +52,7 @@
 };
 
 #define MSGMNI   128   /* <= 1K */     /* max # of msg queue identifiers */
-#define MSGMAX  4080   /* <= 4080 */   /* max size of message (bytes) */
+#define MSGMAX  4056   /* <= 4056 */   /* max size of message (bytes) */
 #define MSGMNB 16384   /* ? */        /* default max size of a message queue */
 
 /* unused */
diff -u +recursive +new-file 0.99pl15/linux/include/linux/route.h linux/include/linux/route.h
--- 0.99pl15/linux/include/linux/route.h	Mon Jan 17 14:28:40 1994
+++ linux/include/linux/route.h	Sun Feb 13 17:16:51 1994
@@ -21,21 +21,32 @@
 #include <linux/if.h>
 
 
+/* This structure gets passed by the SIOCADDRTOLD and SIOCDELRTOLD calls. */
+struct old_rtentry {
+	unsigned long	rt_genmask;
+	struct sockaddr	rt_dst;
+	struct sockaddr	rt_gateway;
+	short		rt_flags;
+	short		rt_refcnt;
+	unsigned long	rt_use;
+	char		*rt_dev; 
+};
+
 /* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
 struct rtentry {
-  unsigned long		rt_hash;	/* hash key for lookups		*/
-#define rt_genmask rt_hash
-  struct sockaddr	rt_dst;
-  struct sockaddr	rt_gateway;
-  short			rt_flags;
-  short			rt_refcnt;
-  unsigned long		rt_use;
-#ifdef BSD_COMPATIBLE
-  struct ifnet		*rt_ifp;
-#else
-  void			*rt_dev; 
-#endif
+	unsigned long	rt_hash;	/* hash key for lookups		*/
+	struct sockaddr	rt_dst;		/* target address		*/
+	struct sockaddr	rt_gateway;	/* gateway addr (RTF_GATEWAY)	*/
+	struct sockaddr	rt_genmask;	/* target network mask (IP)	*/
+	short		rt_flags;
+	short		rt_refcnt;
+	unsigned long	rt_use;
+	struct ifnet	*rt_ifp;
+	short		rt_metric;	/* +1 for binary compatibility!	*/
+	char		*rt_dev;	/* forcing the device at add	*/
 };
+
+
 #define	RTF_UP		0x0001		/* route useable		*/
 #define	RTF_GATEWAY	0x0002		/* destination is a gateway	*/
 #define	RTF_HOST	0x0004		/* host entry (net otherwise)	*/
diff -u +recursive +new-file 0.99pl15/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h
--- 0.99pl15/linux/include/linux/sbpcd.h	Sat Jan 29 14:53:18 1994
+++ linux/include/linux/sbpcd.h	Sun Mar  6 16:08:22 1994
@@ -35,12 +35,8 @@
  * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ...
  * there are some soundcards on the market with 0x0630, 0x0650, ...
  *
- * obey! changed against v0.4 !!!
- * for SBPRO cards, specify the CDROM address - no longer the audio address! 
  * example: if your SBPRO audio address is 0x220, specify 0x230.
  *
- * a fill-in is not always necessary - the driver does auto-probing now,
- * with the here specified address first...
  */
 #define CDROM_PORT 0x0230
 
@@ -73,7 +69,9 @@
 #define DBG_DID		16	/* drive ID test */
 #define DBG_RES		17	/* drive reset info */
 #define DBG_SPI		18	/* SpinUp test */
-#define DBG_000		19	/* unnecessary information */
+#define DBG_IOS		19	/* ioctl trace: "subchannel" */
+#define DBG_IO2		20	/* ioctl trace: general */
+#define DBG_000		21	/* unnecessary information */
 
 /*==========================================================================*/
 /*==========================================================================*/
@@ -420,12 +418,7 @@
 /*
  * use "REP INSB" for strobing the data in:
  */
-#if PATCHLEVEL<15
-#define READ_DATA(port, buf, nr) \
-__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","dx","di")
-#else
 #define READ_DATA(port, buf, nr) insb(port, buf, nr)
-#endif
 
 /*==========================================================================*/
 /*
diff -u +recursive +new-file 0.99pl15/linux/include/linux/sched.h linux/include/linux/sched.h
--- 0.99pl15/linux/include/linux/sched.h	Tue Jan 25 11:47:13 1994
+++ linux/include/linux/sched.h	Fri Mar  4 14:13:32 1994
@@ -166,7 +166,7 @@
 
 struct task_struct {
 /* these are hardcoded - don't touch */
-	long state;		/* -1 unrunnable, 0 runnable, >0 stopped */
+	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
 	long counter;
 	long priority;
 	unsigned long signal;
@@ -183,6 +183,7 @@
 	int elf_executable:1;
 	int dumpable:1;
 	int swappable:1;
+	int did_exec:1;
 	unsigned long start_code,end_code,end_data,start_brk,brk,start_stack,start_mmap;
 	unsigned long arg_start, arg_end, env_start, env_end;
 	int pid,pgrp,session,leader;
@@ -263,7 +264,7 @@
 /* schedlink */	&init_task,&init_task, \
 /* signals */	{{ 0, },}, \
 /* stack */	0,(unsigned long) &init_kernel_stack, \
-/* ec,brk... */	0,0,0,0,0,0,0,0,0,0,0,0, \
+/* ec,brk... */	0,0,0,0,0,0,0,0,0,0,0,0,0, \
 /* argv.. */	0,0,0,0, \
 /* pid etc.. */	0,0,0,0, \
 /* suppl grps*/ {NOGROUP,}, \
@@ -302,6 +303,8 @@
 extern struct task_struct *last_task_used_math;
 extern struct task_struct *current;
 extern unsigned long volatile jiffies;
+extern unsigned long itimer_ticks;
+extern unsigned long itimer_next;
 extern struct timeval xtime;
 extern int need_resched;
 
@@ -478,6 +481,21 @@
 	add_wait_queue(wait_address,&entry->wait);
 	p->nr++;
 }
+
+extern void __down(struct semaphore * sem);
+
+extern inline void down(struct semaphore * sem)
+{
+	if (sem->count <= 0)
+		__down(sem);
+	sem->count--;
+}
+
+extern inline void up(struct semaphore * sem)
+{
+	sem->count++;
+	wake_up(&sem->wait);
+}	
 
 static inline unsigned long _get_base(char * addr)
 {
diff -u +recursive +new-file 0.99pl15/linux/include/linux/sockios.h linux/include/linux/sockios.h
--- 0.99pl15/linux/include/linux/sockios.h	Thu Jan 13 20:50:55 1994
+++ linux/include/linux/sockios.h	Sun Feb 13 16:44:20 1994
@@ -39,6 +39,10 @@
 #define SIOCGPGRP	0x8904
 #define SIOCATMARK	0x8905
 
+/* Routing table calls. */
+#define SIOCADDRT	0x890B		/* add routing table entry	*/
+#define SIOCDELRT	0x890C		/* delete routing table entry	*/
+
 /* Socket configuration controls. */
 #define SIOCGIFNAME	0x8910		/* get iface name		*/
 #define SIOCSIFLINK	0x8911		/* set iface channel		*/
@@ -64,9 +68,9 @@
 #define SIOCGIFENCAP	0x8925		/* get/set slip encapsulation   */
 #define SIOCSIFENCAP	0x8926		
 
-/* Routing table calls. */
-#define SIOCADDRT	0x8940		/* add routing table entry	*/
-#define SIOCDELRT	0x8941		/* delete routing table entry	*/
+/* Routing table calls (oldrtent - don't use) */
+#define SIOCADDRTOLD	0x8940		/* add routing table entry	*/
+#define SIOCDELRTOLD	0x8941		/* delete routing table entry	*/
 
 /* ARP cache control calls. */
 #define SIOCDARP	0x8950		/* delete ARP table entry	*/
diff -u +recursive +new-file 0.99pl15/linux/include/linux/termios.h linux/include/linux/termios.h
--- 0.99pl15/linux/include/linux/termios.h	Wed Jan 26 11:17:56 1994
+++ linux/include/linux/termios.h	Tue Mar  1 19:00:15 1994
@@ -150,9 +150,9 @@
 #define VTDLY	0040000
 #define   VT0	0000000
 #define   VT1	0040000
-#define FFDLY	0040000
+#define FFDLY	0100000
 #define   FF0	0000000
-#define   FF1	0040000
+#define   FF1	0100000
 
 /* c_cflag bit meaning */
 #define CBAUD	0000017
diff -u +recursive +new-file 0.99pl15/linux/include/linux/timer.h linux/include/linux/timer.h
--- 0.99pl15/linux/include/linux/timer.h	Sat Jan 29 14:55:05 1994
+++ linux/include/linux/timer.h	Fri Feb 11 12:59:42 1994
@@ -75,6 +75,7 @@
  */
 struct timer_list {
 	struct timer_list *next;
+	struct timer_list *prev;
 	unsigned long expires;
 	unsigned long data;
 	void (*function)(unsigned long);
diff -u +recursive +new-file 0.99pl15/linux/include/linux/timex.h linux/include/linux/timex.h
--- 0.99pl15/linux/include/linux/timex.h	Mon Jan 31 09:01:36 1994
+++ linux/include/linux/timex.h	Sun Mar  6 16:14:51 1994
@@ -25,8 +25,6 @@
 #ifndef _LINUX_TIMEX_H
 #define _LINUX_TIMEX_H
 
-#include <linux/unistd.h>
-
 /*
  * The following defines establish the engineering parameters of the PLL
  * model. The HZ variable establishes the timer interrupt frequency, 100 Hz 
diff -u +recursive +new-file 0.99pl15/linux/include/linux/tty.h linux/include/linux/tty.h
--- 0.99pl15/linux/include/linux/tty.h	Sat Jan 29 13:15:25 1994
+++ linux/include/linux/tty.h	Fri Feb 18 11:08:41 1994
@@ -399,7 +399,7 @@
 
 extern void flush_input(struct tty_struct * tty);
 extern void flush_output(struct tty_struct * tty);
-extern void wait_until_sent(struct tty_struct * tty);
+extern void wait_until_sent(struct tty_struct * tty, int timeout);
 extern int check_change(struct tty_struct * tty, int channel);
 extern void stop_tty(struct tty_struct * tty);
 extern void start_tty(struct tty_struct * tty);
diff -u +recursive +new-file 0.99pl15/linux/include/linux/wait.h linux/include/linux/wait.h
--- 0.99pl15/linux/include/linux/wait.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/wait.h	Fri Feb 11 09:57:58 1994
@@ -11,6 +11,13 @@
 	struct wait_queue * next;
 };
 
+struct semaphore {
+	int count;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, NULL })
+
 struct select_table_entry {
 	struct wait_queue wait;
 	struct wait_queue ** wait_address;
diff -u +recursive +new-file 0.99pl15/linux/include/linux/xd.h linux/include/linux/xd.h
--- 0.99pl15/linux/include/linux/xd.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/xd.h	Sat Feb 12 18:27:32 1994
@@ -131,6 +131,8 @@
 static void xd_wd_init_drive (u_char drive);
 static void xd_seagate_init_controller (u_char *address);
 static void xd_seagate_init_drive (u_char drive);
+static void xd_omti_init_controller (u_char *address);
+static void xd_omti_init_drive (u_char drive);
 static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
 static void xd_override_init_drive (u_char drive);
 
diff -u +recursive +new-file 0.99pl15/linux/init/main.c linux/init/main.c
--- 0.99pl15/linux/init/main.c	Sat Jan 29 14:55:05 1994
+++ linux/init/main.c	Mon Feb  7 16:07:01 1994
@@ -326,6 +326,17 @@
 	envp_init[envs+1] = NULL;
 }
 
+static void copy_options(char * to, char * from)
+{
+	char c = ' ';
+
+	do {
+		if (c == ' ' && !memcmp("mem=", from, 4))
+			memory_end = simple_strtoul(from+4, &from, 0);
+		c = *(to++) = *(from++);
+	} while (c);
+}
+
 static void copro_timeout(void)
 {
 	fpu_error = 1;
@@ -351,7 +362,7 @@
 	memory_end = (1<<20) + (EXT_MEM_K<<10);
 	memory_end &= PAGE_MASK;
 	ramdisk_size = RAMDISK_SIZE;
-	strcpy(command_line,COMMAND_LINE);
+	copy_options(command_line,COMMAND_LINE);
 #ifdef CONFIG_MAX_16M
 	if (memory_end > 16*1024*1024)
 		memory_end = 16*1024*1024;
diff -u +recursive +new-file 0.99pl15/linux/ipc/shm.c linux/ipc/shm.c
--- 0.99pl15/linux/ipc/shm.c	Tue Jan  4 13:08:23 1994
+++ linux/ipc/shm.c	Wed Mar  2 19:35:20 1994
@@ -391,6 +391,12 @@
 	if (shmid < 0)
 		return -EINVAL;
 
+	if (raddr) {
+		err = verify_area(VERIFY_WRITE, raddr, sizeof(long));
+		if (err)
+			return err;
+	}
+
 	shp = shm_segs[id = shmid % SHMMNI];
 	if (shp == IPC_UNUSED || shp == IPC_NOID)
 		return -EINVAL;
@@ -462,6 +468,8 @@
 	shp->attaches = shmd;
 	shp->shm_lpid = current->pid;
 	shp->shm_atime = CURRENT_TIME;
+	if (!raddr)
+		return addr;
 	put_fs_long (addr, raddr);
 	return 0;
 }
diff -u +recursive +new-file 0.99pl15/linux/ipc/util.c linux/ipc/util.c
--- 0.99pl15/linux/ipc/util.c	Wed Dec  1 14:44:15 1993
+++ linux/ipc/util.c	Fri Feb 18 16:20:22 1994
@@ -45,24 +45,19 @@
  * to ipc resources. return 0 if allowed
  */
 int ipcperms (struct ipc_perm *ipcp, short flag)
-{
-	int i; mode_t perm; uid_t euid; int egid;
-	
+{	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
+	int requested_mode, granted_mode;
+
 	if (suser())
 		return 0;
-
-	perm = S_IRWXO; euid = current->euid;
-
-	if (euid == ipcp->cuid || euid == ipcp->uid) 
-		perm = S_IRWXU;
-	else {
-		for (i = 0; (egid = current->groups[i]) != NOGROUP; i++)
-			if ((egid == ipcp->cgid) || (egid == ipcp->gid)) { 
-				perm = S_IRWXG; 
-				break;
-			}
-	}
-	if (!(flag & perm) || flag & perm & ~ipcp->mode)
+	requested_mode = (flag >> 6) | (flag >> 3) | flag;
+	granted_mode = ipcp->mode;
+	if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
+		granted_mode >>= 6;
+	else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
+		granted_mode >>= 3;
+	/* is there some bit set in requested_mode but not in granted_mode? */
+	if (requested_mode & ~granted_mode & 0007)
 		return -1;
 	return 0;
 }
diff -u +recursive +new-file 0.99pl15/linux/kernel/fork.c linux/kernel/fork.c
--- 0.99pl15/linux/kernel/fork.c	Wed Jan 26 11:17:56 1994
+++ linux/kernel/fork.c	Fri Mar  4 14:11:01 1994
@@ -136,6 +136,7 @@
 		goto bad_fork_free;
 	task[nr] = p;
 	*p = *current;
+	p->did_exec = 0;
 	p->kernel_stack_page = 0;
 	p->state = TASK_UNINTERRUPTIBLE;
 	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
diff -u +recursive +new-file 0.99pl15/linux/kernel/itimer.c linux/kernel/itimer.c
--- 0.99pl15/linux/kernel/itimer.c	Wed Dec  1 14:44:15 1993
+++ linux/kernel/itimer.c	Tue Feb 22 09:05:46 1994
@@ -81,14 +81,23 @@
 		return k;
 	switch (which) {
 		case ITIMER_REAL:
+			if (j) {
+				j += 1+itimer_ticks;
+				if (j < itimer_next)
+					itimer_next = j;
+			}
 			current->it_real_value = j;
 			current->it_real_incr = i;
 			break;
 		case ITIMER_VIRTUAL:
+			if (j)
+				j++;
 			current->it_virt_value = j;
 			current->it_virt_incr = i;
 			break;
 		case ITIMER_PROF:
+			if (j)
+				j++;
 			current->it_prof_value = j;
 			current->it_prof_incr = i;
 			break;
diff -u +recursive +new-file 0.99pl15/linux/kernel/ksyms.S linux/kernel/ksyms.S
--- 0.99pl15/linux/kernel/ksyms.S	Fri Jan 28 09:28:22 1994
+++ linux/kernel/ksyms.S	Wed Feb 16 09:30:21 1994
@@ -9,6 +9,8 @@
 
 _register_chrdev
 _unregister_chrdev
+_register_blkdev
+_unregister_blkdev
 _wake_up_interruptible
 
 _wp_works_ok
diff -u +recursive +new-file 0.99pl15/linux/kernel/ksyms.sh linux/kernel/ksyms.sh
--- 0.99pl15/linux/kernel/ksyms.sh	Mon Jan  3 08:37:17 1994
+++ linux/kernel/ksyms.sh	Fri Feb 18 16:54:02 1994
@@ -10,7 +10,7 @@
 #
 #
 
-trap "rm -f ksyms.tmp ksyms.lst" 1 2 
+trap "rm -f ksyms.tmp ksyms.lst ; exit 1" 1 2 
 
 sed -e '/^#/d' -e '/^[	 ]*$/d' ksyms.lst | sort > ksyms.tmp
 
diff -u +recursive +new-file 0.99pl15/linux/kernel/module.c linux/kernel/module.c
--- 0.99pl15/linux/kernel/module.c	Sat Jan  8 14:35:12 1994
+++ linux/kernel/module.c	Fri Feb 11 08:55:26 1994
@@ -233,8 +233,7 @@
 /*
  * Called by the /proc file system to return a current list of modules.
  */
-int
-get_module_list( char *buf)
+int get_module_list(char *buf)
 {
 	char *p;
 	char *q;
diff -u +recursive +new-file 0.99pl15/linux/kernel/sched.c linux/kernel/sched.c
--- 0.99pl15/linux/kernel/sched.c	Wed Feb  2 16:36:33 1994
+++ linux/kernel/sched.c	Tue Feb 22 09:05:37 1994
@@ -192,8 +192,8 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
-static unsigned long itimer_ticks = 0;
-static unsigned long itimer_next = ~0;
+unsigned long itimer_ticks = 0;
+unsigned long itimer_next = ~0;
 static unsigned long lost_ticks = 0;
 
 /*
@@ -359,6 +359,19 @@
 		}
 		tmp = tmp->next;
 	} while (tmp != *q);
+}
+
+void __down(struct semaphore * sem)
+{
+	struct wait_queue wait = { current, NULL };
+	add_wait_queue(&sem->wait, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	while (sem->count <= 0) {
+		schedule();
+		current->state = TASK_UNINTERRUPTIBLE;
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&sem->wait, &wait);
 }
 
 static inline void __sleep_on(struct wait_queue **p, int state)
diff -u +recursive +new-file 0.99pl15/linux/kernel/signal.c linux/kernel/signal.c
--- 0.99pl15/linux/kernel/signal.c	Fri Jan 21 09:19:01 1994
+++ linux/kernel/signal.c	Tue Feb 15 10:50:23 1994
@@ -183,6 +183,9 @@
 		return -EINVAL;
 	p = signum - 1 + current->sigaction;
 	if (action) {
+		int err = verify_area(VERIFY_READ, action, sizeof(*action));
+		if (err)
+			return err;
 		memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
 		if (new_sa.sa_flags & SA_NOMASK)
 			new_sa.sa_mask = 0;
@@ -194,8 +197,10 @@
 			return -EFAULT;
 	}
 	if (oldaction) {
-		if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction)))
-			memcpy_tofs(oldaction, p, sizeof(struct sigaction));
+		int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
+		if (err)
+			return err;
+		memcpy_tofs(oldaction, p, sizeof(struct sigaction));
 	}
 	if (action) {
 		*p = new_sa;
@@ -211,30 +216,36 @@
  */
 asmlinkage int sys_sigreturn(unsigned long __unused)
 {
-#define CHECK_SEG(x) if (x) x |= 3
 #define COPY(x) regs->x = context.x
+#define COPY_SEG(x) \
+if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
+#define COPY_SEG_STRICT(x) \
+if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
 	struct sigcontext_struct context;
 	struct pt_regs * regs;
 
 	regs = (struct pt_regs *) &__unused;
+	if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
+		goto badframe;
 	memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
 	current->blocked = context.oldmask & _BLOCKABLE;
-	CHECK_SEG(context.ss);
-	CHECK_SEG(context.cs);
-	CHECK_SEG(context.ds);
-	CHECK_SEG(context.es);
-	CHECK_SEG(context.fs);
-	CHECK_SEG(context.gs);
-	COPY(eip); COPY(eflags);
+	COPY_SEG(ds);
+	COPY_SEG(es);
+	COPY_SEG(fs);
+	COPY_SEG(gs);
+	COPY_SEG_STRICT(ss);
+	COPY_SEG_STRICT(cs);
+	COPY(eip);
 	COPY(ecx); COPY(edx);
 	COPY(ebx);
 	COPY(esp); COPY(ebp);
 	COPY(edi); COPY(esi);
-	COPY(cs); COPY(ss);
-	COPY(ds); COPY(es);
-	COPY(fs); COPY(gs);
+	regs->eflags &= ~0xCD5;
+	regs->eflags |= context.eflags & 0xCD5;
 	regs->orig_eax = -1;		/* disable syscall checks */
 	return context.eax;
+badframe:
+	do_exit(SIGSEGV);
 }
 
 /*
diff -u +recursive +new-file 0.99pl15/linux/kernel/sys.c linux/kernel/sys.c
--- 0.99pl15/linux/kernel/sys.c	Wed Jan 26 11:17:56 1994
+++ linux/kernel/sys.c	Fri Mar  4 17:10:58 1994
@@ -461,32 +461,49 @@
  * OK, I think I have the protection semantics right.... this is really
  * only important on a multi-user system anyway, to make sure one user
  * can't send a signal to a process owned by another.  -TYT, 12/12/91
+ *
+ * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
+ * LBT 04.03.94
  */
 asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
 {
-	int i; 
+	struct task_struct * p;
 
 	if (!pid)
 		pid = current->pid;
 	if (!pgid)
-		pgid = current->pid;
+		pgid = pid;
 	if (pgid < 0)
 		return -EINVAL;
-	for (i=0 ; i<NR_TASKS ; i++)
-		if (task[i] && (task[i]->pid == pid) &&
-		    ((task[i]->p_pptr == current) || 
-		     (task[i]->p_opptr == current) || 
-		     (task[i] == current))) {
-			if (task[i]->leader)
-				return -EPERM;
-			if ((task[i]->session != current->session) ||
-			    ((pgid != pid) && 
-			     (session_of_pgrp(pgid) != current->session)))
-				return -EPERM;
-			task[i]->pgrp = pgid;
-			return 0;
-		}
+	for_each_task(p) {
+		if (p->pid == pid)
+			goto found_task;
+	}
 	return -ESRCH;
+
+found_task:
+	if (p->p_pptr == current || p->p_opptr == current) {
+		if (p->session != current->session)
+			return -EPERM;
+		if (p->did_exec)
+			return -EACCES;
+	} else if (p != current)
+		return -ESRCH;
+	if (p->leader)
+		return -EPERM;
+	if (pgid != pid) {
+		struct task_struct * tmp;
+		for_each_task (tmp) {
+			if (tmp->pgrp == pgid &&
+			 tmp->session == current->session)
+				goto ok_pgid;
+		}
+		return -EPERM;
+	}
+
+ok_pgid:
+	p->pgrp = pgid;
+	return 0;
 }
 
 asmlinkage int sys_getpgid(pid_t pid)
diff -u +recursive +new-file 0.99pl15/linux/kernel/traps.c linux/kernel/traps.c
--- 0.99pl15/linux/kernel/traps.c	Thu Feb  3 12:06:12 1994
+++ linux/kernel/traps.c	Wed Mar  9 11:10:40 1994
@@ -80,21 +80,31 @@
 /*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
 {
 	int i;
+	unsigned long esp;
+	unsigned short ss;
 
+	esp = (unsigned long) &regs->esp;
+	ss = KERNEL_DS;
 	if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
 		return;
-
+	if (regs->cs & 3) {
+		esp = regs->esp;
+		ss = regs->ss;
+	}
 	console_verbose();
 	printk("%s: %04lx\n", str, err & 0xffff);
 	printk("EIP:    %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
-	printk("esi: %08lx   edi: %08lx   ebp: %08lx\n",
-		regs->esi, regs->edi, regs->ebp);
-	printk("ds: %04x   es: %04x   fs: %04x   gs: %04x\n",
-		regs->ds, regs->es, regs->fs, regs->gs);
+	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
+		regs->esi, regs->edi, regs->ebp, esp);
+	printk("ds: %04x   es: %04x   fs: %04x   gs: %04x   ss: %04x\n",
+		regs->ds, regs->es, regs->fs, regs->gs, ss);
 	store_TR(i);
-	printk("Pid: %d, process nr: %d (%s)\n", current->pid, 0xffff & i, current->comm);
+	printk("Pid: %d, process nr: %d (%s)\nStack: ", current->pid, 0xffff & i, current->comm);
+	for(i=0;i<5;i++)
+		printk("%08lx ", get_seg_long(ss,(i+(unsigned long *)esp)));
+	printk("\nCode: ");
 	for(i=0;i<20;i++)
 		printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
 	printk("\n");
diff -u +recursive +new-file 0.99pl15/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- 0.99pl15/linux/mm/kmalloc.c	Wed Dec  1 14:44:15 1993
+++ linux/mm/kmalloc.c	Thu Mar 10 19:54:34 1994
@@ -151,8 +151,14 @@
 	int order,tries,i,sz;
 	struct block_header *p;
 	struct page_descriptor *page;
+	extern unsigned long intr_count;
 
 /* Sanity check... */
+	if (intr_count && priority != GFP_ATOMIC) {
+		printk("kmalloc called nonatomically from interrupt %08lx\n",
+			((unsigned long *)&size)[-1]);
+		priority = GFP_ATOMIC;
+	}
 if (size > MAX_KMALLOC_K * 1024) 
      {
      printk ("kmalloc: I refuse to allocate %d bytes (for now max = %d).\n",
diff -u +recursive +new-file 0.99pl15/linux/mm/memory.c linux/mm/memory.c
--- 0.99pl15/linux/mm/memory.c	Tue Jan 25 11:03:02 1994
+++ linux/mm/memory.c	Wed Feb 23 10:36:51 1994
@@ -304,9 +304,9 @@
 			if ((page = *page_table) != 0) {
 				*page_table = 0;
 				if (1 & page) {
-					if (!(mem_map[MAP_NR(page)]
-					      & MAP_PAGE_RESERVED))
-						--current->rss;
+					if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+						if (current->rss > 0)
+							--current->rss;
 					free_page(PAGE_MASK & page);
 				} else
 					swap_free(page);
@@ -364,9 +364,9 @@
 			if ((page = *page_table) != 0) {
 				*page_table = 0;
 				if (page & PAGE_PRESENT) {
-					if (!(mem_map[MAP_NR(page)]
-					      & MAP_PAGE_RESERVED))
-						--current->rss;
+					if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+						if (current->rss > 0)
+							--current->rss;
 					free_page(PAGE_MASK & page);
 				} else
 					swap_free(page);
@@ -426,9 +426,9 @@
 			if ((page = *page_table) != 0) {
 				*page_table = 0;
 				if (PAGE_PRESENT & page) {
-					if (!(mem_map[MAP_NR(page)]
-					      & MAP_PAGE_RESERVED))
-						--current->rss;
+					if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+						if (current->rss > 0)
+							--current->rss;
 					free_page(PAGE_MASK & page);
 				} else
 					swap_free(page);
@@ -981,9 +981,6 @@
 	printk("Free pages:      %6dkB\n",nr_free_pages<<(PAGE_SHIFT-10));
 	printk("Secondary pages: %6dkB\n",nr_secondary_pages<<(PAGE_SHIFT-10));
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	printk("Buffer memory:   %6dkB\n",buffermem>>10);
-	printk("Buffer heads:    %6d\n",nr_buffer_heads);
-	printk("Buffer blocks:   %6d\n",nr_buffers);
 	i = high_memory >> PAGE_SHIFT;
 	while (i-- > 0) {
 		total++;
@@ -998,6 +995,7 @@
 	printk("%d free pages\n",free);
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
+	show_buffers();
 }
 
 /*
diff -u +recursive +new-file 0.99pl15/linux/mm/mmap.c linux/mm/mmap.c
--- 0.99pl15/linux/mm/mmap.c	Tue Jan 18 10:44:25 1994
+++ linux/mm/mmap.c	Fri Feb  4 11:59:35 1994
@@ -113,9 +113,9 @@
 		mask |= PAGE_READONLY;
 	if (prot & PROT_WRITE)
 		if ((flags & MAP_TYPE) == MAP_PRIVATE)
-			mask |= PAGE_COW;
+			mask |= PAGE_COPY;
 		else
-			mask |= PAGE_RW;
+			mask |= PAGE_SHARED;
 	if (!mask)
 		return -EINVAL;
 
diff -u +recursive +new-file 0.99pl15/linux/mm/swap.c linux/mm/swap.c
--- 0.99pl15/linux/mm/swap.c	Tue Feb  1 09:03:52 1994
+++ linux/mm/swap.c	Thu Mar 10 19:54:09 1994
@@ -585,6 +585,7 @@
  */
 unsigned long __get_free_page(int priority)
 {
+	extern unsigned long intr_count;
 	unsigned long result, flag;
 	static unsigned long index = 0;
 
@@ -593,6 +594,11 @@
 	   sections of code have interrupts disabled. -RAB
 	   Is this code reentrant? */
 
+	if (intr_count && priority != GFP_ATOMIC) {
+		printk("gfp called nonatomically from interrupt %08lx\n",
+			((unsigned long *)&priority)[-1]);
+		priority = GFP_ATOMIC;
+	}
 	save_flags(flag);
 repeat:
 	REMOVE_FROM_MEM_QUEUE(free_page_list,nr_free_pages);
diff -u +recursive +new-file 0.99pl15/linux/net/inet/arp.c linux/net/inet/arp.c
--- 0.99pl15/linux/net/inet/arp.c	Thu Feb  3 12:38:52 1994
+++ linux/net/inet/arp.c	Wed Mar  2 10:03:40 1994
@@ -17,10 +17,10 @@
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *		Stephen A. Wood, <saw@hallc1.cebaf.gov>
  *		Arnt Gulbrandsen, <agulbra@pvv.unit.no>
  *
  * Fixes:
+ *		Stephen A. Wood	:	arp problems
  *		'Mr Linux'	:	arp problems.
  *		Alan Cox	:	arp_ioctl now checks memory areas with verify_area.
  *		Alan Cox	:	Non IP arp message now only appears with debugging on.
@@ -39,6 +39,7 @@
  *		Dominik Kubla	:	Better checking
  *		Tegge		:	Assorted corrections on cross port stuff
  *		Alan Cox	:	ATF_PERM was backwards! - might be useful now (sigh)
+ *		Alan Cox	:	Arp timer added.
  *
  * To Fix:
  *				:	arp response allocates an skbuff to send. However there is a perfectly
@@ -60,6 +61,7 @@
 #include <linux/config.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
+#include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/if_arp.h>
 #include <linux/in.h>
@@ -250,6 +252,28 @@
 }
 
 
+static struct timer_list arp_timer;
+
+static void arp_queue_ticker(unsigned long data);
+
+static void arp_queue_kick(void)
+{
+	arp_timer.expires = 500;	/* 5 seconds */
+	arp_timer.data = 0;
+	arp_timer.function = arp_queue_ticker;
+	del_timer(&arp_timer);
+	add_timer(&arp_timer);
+}
+
+static void arp_queue_ticker(unsigned long data/*UNUSED*/)
+{
+	arp_send_q();
+	if (skb_peek(&arp_q))
+		arp_queue_kick();
+}
+
+
+
 /* Create and send our response to an ARP request. */
 static int
 arp_response(struct arphdr *arp1, struct device *dev,  int addrtype)
@@ -753,6 +777,8 @@
 	printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
 	return;
   }
+  if(arp_q==NULL)
+  	arp_queue_kick();
   skb_queue_tail(&arp_q,skb);
   skb->magic = ARP_QUEUE_MAGIC;
   sti();
diff -u +recursive +new-file 0.99pl15/linux/net/inet/datagram.c linux/net/inet/datagram.c
--- 0.99pl15/linux/net/inet/datagram.c	Thu Jan 13 20:56:24 1994
+++ linux/net/inet/datagram.c	Fri Feb 11 09:14:40 1994
@@ -186,7 +186,7 @@
 			return(0);
 
 		case SEL_OUT:
-			if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+			if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
 			{
 				return(1);
 			}
diff -u +recursive +new-file 0.99pl15/linux/net/inet/dev.c linux/net/inet/dev.c
--- 0.99pl15/linux/net/inet/dev.c	Fri Jan 21 15:31:25 1994
+++ linux/net/inet/dev.c	Tue Feb 22 10:00:56 1994
@@ -193,81 +193,49 @@
 
 
 /* Check the address for our address, broadcasts, etc. */
-int
-chk_addr(unsigned long addr)
+int chk_addr(unsigned long addr)
 {
-  struct device *dev;
-  unsigned long dst;
-
-  DPRINTF((DBG_DEV, "chk_addr(%s) --> ", in_ntoa(addr)));
-  dst = ntohl(addr);
-
-  /* Accept both `all ones' and `all zeros' as BROADCAST. */
-  if (dst == INADDR_ANY || dst == INADDR_BROADCAST) {
-	DPRINTF((DBG_DEV, "BROADCAST\n"));
-	return(IS_BROADCAST);
-  }
+	struct device *dev;
+	unsigned long mask;
 
-  /* Accept all of the `loopback' class A net. */
-  if ((dst & IN_CLASSA_NET) == 0x7F000000L) {
-	DPRINTF((DBG_DEV, "LOOPBACK\n"));
+	/* Accept both `all ones' and `all zeros' as BROADCAST. */
+	if (addr == INADDR_ANY || addr == INADDR_BROADCAST)
+		return IS_BROADCAST;
 
-	/*
-	 * We force `loopback' to be equal to MY_ADDR.
-	 */
-	return(IS_MYADDR);
-	/* return(IS_LOOPBACK); */
-  }
+	mask = get_mask(addr);
 
-  /* OK, now check the interface addresses. */
-  for (dev = dev_base; dev != NULL; dev = dev->next) {
-        if (!(dev->flags&IFF_UP))
-	        continue;
-	if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
-	        return(IS_MYADDR);
-	/* Is it the exact IP address? */
-	if (addr == dev->pa_addr) {
-		DPRINTF((DBG_DEV, "MYADDR\n"));
-		return(IS_MYADDR);
-	}
+	/* Accept all of the `loopback' class A net. */
+	if ((addr & mask) == htonl(0x7F000000L))
+		return IS_MYADDR;
 
-	/* Nope. Check for a subnetwork broadcast. */
-	if ((addr & dev->pa_mask) == (dev->pa_addr & dev->pa_mask)) {
-		if ((addr & ~dev->pa_mask) == 0) {
-			DPRINTF((DBG_DEV, "SUBBROADCAST-0\n"));
-			return(IS_BROADCAST);
+	/* OK, now check the interface addresses. */
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		if (!(dev->flags & IFF_UP))
+			continue;
+		if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
+			return IS_MYADDR;
+		/* Is it the exact IP address? */
+		if (addr == dev->pa_addr)
+			return IS_MYADDR;
+		/* Is it our broadcast address? */
+		if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr)
+			return IS_BROADCAST;
+		/* Nope. Check for a subnetwork broadcast. */
+		if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) {
+			if ((addr & ~dev->pa_mask) == 0)
+				return IS_BROADCAST;
+			if ((addr & ~dev->pa_mask) == ~dev->pa_mask)
+				return IS_BROADCAST;
 		}
-		if (((addr & ~dev->pa_mask) | dev->pa_mask)
-						== INADDR_BROADCAST) {
-			DPRINTF((DBG_DEV, "SUBBROADCAST-1\n"));
-			return(IS_BROADCAST);
+		/* Nope. Check for Network broadcast. */
+		if (((addr ^ dev->pa_addr) & mask) == 0) {
+			if ((addr & ~mask) == 0)
+				return IS_BROADCAST;
+			if ((addr & ~mask) == ~mask)
+				return IS_BROADCAST;
 		}
 	}
-
-	/* Nope. Check for Network broadcast. */
-	if(IN_CLASSA(dst)) {
-	  if( addr == (dev->pa_addr | 0xffffff00)) {
-	    DPRINTF((DBG_DEV, "CLASS A BROADCAST-1\n"));
-	    return(IS_BROADCAST);
-	  }
-	}
-	else if(IN_CLASSB(dst)) {
-	  if( addr == (dev->pa_addr | 0xffff0000)) {
-	    DPRINTF((DBG_DEV, "CLASS B BROADCAST-1\n"));
-	    return(IS_BROADCAST);
-	  }
-	}
-	else {   /* IN_CLASSC */
-	  if( addr == (dev->pa_addr | 0xff000000)) {
-	    DPRINTF((DBG_DEV, "CLASS C BROADCAST-1\n"));
-	    return(IS_BROADCAST);
-	  }
-	}
-  }
-
-  DPRINTF((DBG_DEV, "NONE\n"));
-  
-  return(0);		/* no match at all */
+	return 0;		/* no match at all */
 }
 
 
@@ -998,52 +966,55 @@
 {
   struct iflink iflink;
   struct ddi_device *dev;
-  int ret;
 
   switch(cmd) {
-	  case IP_SET_DEV:
-	      	  printk("Your network configuration program needs upgrading.\n");
-		  return -EINVAL;
+	case IP_SET_DEV:
+		printk("Your network configuration program needs upgrading.\n");
+		return -EINVAL;
+
 	case SIOCGIFCONF:
 		(void) dev_ifconf((char *) arg);
-		ret = 0;
-		break;
+		return 0;
+
 	case SIOCGIFFLAGS:
-	case SIOCSIFFLAGS:
 	case SIOCGIFADDR:
-	case SIOCSIFADDR:
 	case SIOCGIFDSTADDR:
-	case SIOCSIFDSTADDR:
 	case SIOCGIFBRDADDR:
-	case SIOCSIFBRDADDR:
 	case SIOCGIFNETMASK:
-	case SIOCSIFNETMASK:
 	case SIOCGIFMETRIC:
-	case SIOCSIFMETRIC:
 	case SIOCGIFMTU:
-	case SIOCSIFMTU:
 	case SIOCGIFMEM:
-	case SIOCSIFMEM:
 	case SIOCGIFHWADDR:
-		if (!suser()) return(-EPERM);
-		ret = dev_ifsioc(arg, cmd);
-		break;
+		return dev_ifsioc(arg, cmd);
+
+	case SIOCSIFFLAGS:
+	case SIOCSIFADDR:
+	case SIOCSIFDSTADDR:
+	case SIOCSIFBRDADDR:
+	case SIOCSIFNETMASK:
+	case SIOCSIFMETRIC:
+	case SIOCSIFMTU:
+	case SIOCSIFMEM:
+		if (!suser())
+			return -EPERM;
+		return dev_ifsioc(arg, cmd);
+
 	case SIOCSIFLINK:
-		if (!suser()) return(-EPERM);
+		if (!suser())
+			return -EPERM;
 		memcpy_fromfs(&iflink, arg, sizeof(iflink));
 		dev = ddi_map(iflink.id);
-		if (dev == NULL) return(-EINVAL);
+		if (dev == NULL)
+			return -EINVAL;
 
 		/* Now allocate an interface and connect it. */
 		printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n",
 						dev->name, iflink.stream);
-		ret = 0;
-		break;
+		return 0;
+
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
   }
-
-  return(ret);
 }
 
 
diff -u +recursive +new-file 0.99pl15/linux/net/inet/icmp.c linux/net/inet/icmp.c
--- 0.99pl15/linux/net/inet/icmp.c	Wed Jan 19 13:34:55 1994
+++ linux/net/inet/icmp.c	Tue Mar  1 18:51:41 1994
@@ -210,9 +210,11 @@
   ip = iph->daddr;
   switch(icmph->code & 7) {
 	case ICMP_REDIR_NET:
+#ifdef not_a_good_idea
 		rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
 			ip, 0, icmph->un.gateway, dev);
 		break;
+#endif
 	case ICMP_REDIR_HOST:
 		rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
 			ip, 0, icmph->un.gateway, dev);
diff -u +recursive +new-file 0.99pl15/linux/net/inet/ip.c linux/net/inet/ip.c
--- 0.99pl15/linux/net/inet/ip.c	Sat Jan 29 14:10:53 1994
+++ linux/net/inet/ip.c	Thu Mar 10 21:28:17 1994
@@ -34,6 +34,12 @@
  *		Alan Cox	:	Save IP header pointer for later
  *		Alan Cox	:	ip option setting
  *		Alan Cox	:	Use ip_tos/ip_ttl settings
+ *		Alan Cox	:	Fragmentation bogosity removed
+ *					(Thanks to Mark.Bush@prg.ox.ac.uk)
+ *		Dmitry Gorodchanin :	Send of a raw packet crash fix.
+ *		Alan Cox	:	Silly ip bug when an overlength
+ *					fragment turns up. Now frees the
+ *					queue.
  *
  * To Fix:
  *		IP option processing is mostly not needed. ip_forward needs to know about routing rules
@@ -764,7 +770,6 @@
    	skb->len = (len - qp->maclen);
    	skb->h.raw = skb->data;
    	skb->free = 1;
-   	skb->lock = 1;
  
    	/* Copy the original MAC and IP headers into the new buffer. */
    	ptr = (unsigned char *) skb->h.raw;
@@ -786,6 +791,7 @@
    		if(count+fp->len>skb->len)
    		{
    			printk("Invalid fragment list: Fragment over size.\n");
+   			ip_free(qp);
    			kfree_skb(skb,FREE_WRITE);
    			return NULL;
    		}
@@ -971,7 +977,9 @@
    	/* Point into the IP datagram header. */
    	raw = skb->data;
    	iph = (struct iphdr *) (raw + dev->hard_header_len);
- 	
+
+	skb->ip_hdr = iph;
+	 	
    	/* Setup starting values. */
    	hlen = (iph->ihl * sizeof(unsigned long));
    	left = ntohs(iph->tot_len) - hlen;
@@ -1009,6 +1017,7 @@
    	while(left > 0) 
    	{
  		len = left;
+#ifdef OLD 		
  		if (len+8 > mtu) 
  			len = (dev->mtu - hlen - 8);
  		if ((left - len) >= 8) 
@@ -1016,11 +1025,23 @@
  			len /= 8;
  			len *= 8;
  		}
+#else
+		/* IF: it doesn't fit, use 'mtu' - the data space left */
+		if (len > mtu)
+			len = mtu;
+		/* IF: we are not sending upto and including the packet end
+		   then align the next start on an eight byte boundary */
+		if (len < left)
+		{
+			len/=8;
+			len*=8;
+		}
+#endif		 		
  		DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
  							len, len + hlen));
  
  		/* Allocate buffer. */
- 		if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL) 
+ 		if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_ATOMIC)) == NULL) 
  		{
  			printk("IP: frag: no memory for new fragment!\n");
  			return;
@@ -1369,6 +1390,7 @@
   ptr = skb->data;
   ptr += dev->hard_header_len;
   iph = (struct iphdr *)ptr;
+  skb->ip_hdr = iph;
   iph->tot_len = ntohs(skb->len-dev->hard_header_len);
 
   if(skb->len > dev->mtu)
diff -u +recursive +new-file 0.99pl15/linux/net/inet/ip.h linux/net/inet/ip.h
--- 0.99pl15/linux/net/inet/ip.h	Thu Jan 13 21:00:05 1994
+++ linux/net/inet/ip.h	Sun Feb  6 12:17:40 1994
@@ -78,6 +78,7 @@
 				      struct device *dev, struct sk_buff *skb,
 				      int free);
 extern void		ip_retransmit(struct sock *sk, int all);
+extern void		ip_do_retransmit(struct sock *sk, int all);
 extern int 		ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
 extern int 		ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
 
diff -u +recursive +new-file 0.99pl15/linux/net/inet/proc.c linux/net/inet/proc.c
--- 0.99pl15/linux/net/inet/proc.c	Tue Dec 14 12:12:07 1993
+++ linux/net/inet/proc.c	Wed Mar  2 11:11:16 1994
@@ -88,7 +88,7 @@
 			sp->timer.expires = 0;
 		pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
 			i, src, srcp, dest, destp, sp->state, 
-			format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
+			format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
 			format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
 			timer_active, sp->timer.expires, (unsigned) sp->retransmits,
 			SOCK_INODE(sp->socket)->i_uid);
diff -u +recursive +new-file 0.99pl15/linux/net/inet/raw.c linux/net/inet/raw.c
--- 0.99pl15/linux/net/inet/raw.c	Tue Jan 25 08:52:22 1994
+++ linux/net/inet/raw.c	Sun Feb  6 12:17:40 1994
@@ -115,7 +115,7 @@
   /* Now we need to copy this into memory. */
   skb->sk = sk;
   skb->len = len + skb->ip_hdr->ihl*sizeof(long);
-  skb->h.raw = skb->ip_hdr;
+  skb->h.raw = (unsigned char *) skb->ip_hdr;
   skb->dev = dev;
   skb->saddr = daddr;
   skb->daddr = saddr;
diff -u +recursive +new-file 0.99pl15/linux/net/inet/route.c linux/net/inet/route.c
--- 0.99pl15/linux/net/inet/route.c	Tue Jan 25 08:26:20 1994
+++ linux/net/inet/route.c	Sun Mar 13 16:20:59 1994
@@ -253,18 +253,51 @@
 
 static int rt_new(struct rtentry *r)
 {
-	struct device *dev;
+	int err;
+	char * devname;
+	struct device * dev = NULL;
 	unsigned long flags, daddr, mask, gw;
 
+	if ((devname = r->rt_dev) != NULL) {
+		err = getname(devname, &devname);
+		if (err)
+			return err;
+		dev = dev_get(devname);
+		putname(devname);
+		if (!dev)
+			return -EINVAL;
+	}
+
 	if (r->rt_dst.sa_family != AF_INET)
 		return -EAFNOSUPPORT;
 
 	flags = r->rt_flags;
 	daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
-	mask = r->rt_genmask;
+	mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
 	gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
-	dev = (struct device *) r->rt_dev;
+
+/* BSD emulation: Permits route add someroute gw one-of-my-addresses
+   to indicate which iface. Not as clean as the nice Linux dev technique
+   but people keep using it... */
+	if (!dev && (flags & RTF_GATEWAY)) {
+		struct device *dev2;
+		for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) {
+			if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) {
+				flags &= ~RTF_GATEWAY;
+				dev = dev2;
+				break;
+			}
+		}
+	}
+
+	if (bad_mask(mask, daddr))
+		mask = 0;
 
+	if (flags & RTF_HOST)
+		mask = 0xffffffff;
+	else if (mask && r->rt_genmask.sa_family != AF_INET)
+		return -EAFNOSUPPORT;
+
 	if (flags & RTF_GATEWAY) {
 		if (r->rt_gateway.sa_family != AF_INET)
 			return -EAFNOSUPPORT;
@@ -276,9 +309,6 @@
 	if (dev == NULL)
 		return -ENETUNREACH;
 
-	if (bad_mask(mask, daddr))
-		mask = 0;
-
 	rt_add(flags, daddr, mask, gw, dev);
 	return 0;
 }
@@ -343,19 +373,41 @@
 	return NULL;
 }
 
+static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt)
+{
+	int err;
+	struct old_rtentry tmp;
+
+	err=verify_area(VERIFY_READ, src, sizeof(*src));
+	if (err)
+		return err;
+	memcpy_fromfs(&tmp, src, sizeof(*src));
+	memset(rt, 0, sizeof(*rt));
+	rt->rt_dst = tmp.rt_dst;
+	rt->rt_gateway = tmp.rt_gateway;
+	rt->rt_genmask.sa_family = AF_INET;
+	((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;
+	rt->rt_flags = tmp.rt_flags;
+	rt->rt_dev = tmp.rt_dev;
+	return 0;
+}
 
 int rt_ioctl(unsigned int cmd, void *arg)
 {
-	struct device *dev;
-	struct rtentry rt;
-	char *devname;
-	int ret;
 	int err;
+	struct rtentry rt;
 
 	switch(cmd) {
 	case DDIOCSDBG:
-		ret = dbg_ioctl(arg, DBG_RT);
-		break;
+		return dbg_ioctl(arg, DBG_RT);
+	case SIOCADDRTOLD:
+	case SIOCDELRTOLD:
+		if (!suser())
+			return -EPERM;
+		err = get_old_rtent((struct old_rtentry *) arg, &rt);
+		if (err)
+			return err;
+		return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);
 	case SIOCADDRT:
 	case SIOCDELRT:
 		if (!suser())
@@ -364,21 +416,8 @@
 		if (err)
 			return err;
 		memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
-		if ((devname = (char *) rt.rt_dev) != NULL) {
-			err = getname(devname, &devname);
-			if (err)
-				return err;
-			dev = dev_get(devname);
-			putname(devname);
-			if (!dev)
-				return -EINVAL;
-			rt.rt_dev = dev;
-		}
-		ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
-		break;
-	default:
-		ret = -EINVAL;
+		return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
 	}
 
-	return ret;
+	return -EINVAL;
 }
diff -u +recursive +new-file 0.99pl15/linux/net/inet/skbuff.c linux/net/inet/skbuff.c
--- 0.99pl15/linux/net/inet/skbuff.c	Thu Feb  3 12:44:45 1994
+++ linux/net/inet/skbuff.c	Thu Mar 10 21:15:09 1994
@@ -394,8 +394,8 @@
 	skb->magic = 0;
 	if (skb->sk)
 	{
-	      if(skb->sk->prot!=NULL)
-	{
+		if(skb->sk->prot!=NULL)
+		{
 			if (rw)
 				skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
 			else
@@ -425,7 +425,15 @@
 
 struct sk_buff *alloc_skb(unsigned int size,int priority)
 {
-	struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
+	struct sk_buff *skb;
+	extern unsigned long intr_count;
+
+	if (intr_count && priority != GFP_ATOMIC) {
+		printk("alloc_skb called nonatomically from interrupt %08lx\n",
+			((unsigned long *)&size)[-1]);
+		priority = GFP_ATOMIC;
+	}
+	skb=(struct sk_buff *)kmalloc(size,priority);
 	if(skb==NULL)
 		return NULL;
 	skb->free= 2;	/* Invalid so we pick up forgetful users */
diff -u +recursive +new-file 0.99pl15/linux/net/inet/skbuff.h linux/net/inet/skbuff.h
--- 0.99pl15/linux/net/inet/skbuff.h	Wed Jan 26 12:44:20 1994
+++ linux/net/inet/skbuff.h	Tue Mar  1 13:11:55 1994
@@ -72,8 +72,7 @@
   volatile char 		acked,
 				used,
 				free,
-				arp,
-				urg_used;
+				arp;
   unsigned char			tries,lock;	/* Lock is now unused */
   unsigned short		users;		/* User count - see datagram.c (and soon seqpacket.c/stream.c) */
   unsigned long			padding[0];
diff -u +recursive +new-file 0.99pl15/linux/net/inet/sock.c linux/net/inet/sock.c
--- 0.99pl15/linux/net/inet/sock.c	Wed Feb  2 17:07:01 1994
+++ linux/net/inet/sock.c	Fri Mar 11 16:27:03 1994
@@ -119,8 +119,8 @@
   printk("  daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr);
   printk("  num = %d", sk->num);
   printk(" next = %p\n", sk->next);
-  printk("  send_seq = %ld, acked_seq = %ld, copied_seq = %ld\n",
-	  sk->send_seq, sk->acked_seq, sk->copied_seq);
+  printk("  write_seq = %ld, acked_seq = %ld, copied_seq = %ld\n",
+	  sk->write_seq, sk->acked_seq, sk->copied_seq);
   printk("  rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n",
 	  sk->rcv_ack_seq, sk->window_seq, sk->fin_seq);
   printk("  prot = %p\n", sk->prot);
@@ -130,7 +130,7 @@
   printk("  retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout);
   printk("  cong_window = %d, packets_out = %d\n", sk->cong_window,
 	  sk->packets_out);
-  printk("  urg = %d shutdown=%d\n", sk->urg, sk->shutdown);
+  printk("  shutdown=%d\n", sk->shutdown);
 }
 
 
@@ -497,7 +497,7 @@
 static int inet_getsockopt(struct socket *sock, int level, int optname,
 		    char *optval, int *optlen)
 {
-  	struct sock *sk = sock->data;  	
+  	struct sock *sk = (struct sock *) sock->data;  	
   	if (level == SOL_SOCKET) 
   		return sock_getsockopt(sk,level,optname,optval,optlen);
   	if(sk->prot->getsockopt==NULL)  	
@@ -838,10 +838,12 @@
   sk->rcvbuf = SK_RMEM_MAX;
   sk->pair = NULL;
   sk->opt = NULL;
-  sk->send_seq = 0;
+  sk->write_seq = 0;
   sk->acked_seq = 0;
   sk->copied_seq = 0;
   sk->fin_seq = 0;
+  sk->urg_seq = 0;
+  sk->urg_data = 0;
   sk->proc = 0;
   sk->rtt = TCP_WRITE_TIME << 3;
   sk->rto = TCP_WRITE_TIME;
@@ -859,7 +861,6 @@
 
   sk->priority = 1;
   sk->shutdown = 0;
-  sk->urg = 0;
   sk->keepopen = 0;
   sk->zapped = 0;
   sk->done = 0;
@@ -981,9 +982,13 @@
 	while(sk->state != TCP_CLOSE && current->timeout>0) {
 		interruptible_sleep_on(sk->sleep);
 		if (current->signal & ~current->blocked) {
+			break;
+#if 0
+			/* not working now - closes can't be restarted */
 			sti();
 			current->timeout=0;
 			return(-ERESTARTSYS);
+#endif
 		}
 	}
 	current->timeout=0;
@@ -1531,8 +1536,8 @@
 	case DDIOCSDBG:
 		return(dbg_ioctl((void *) arg, DBG_INET));
 
-	case SIOCADDRT:
-	case SIOCDELRT:
+	case SIOCADDRT: case SIOCADDRTOLD:
+	case SIOCDELRT: case SIOCDELRTOLD:
 		return(rt_ioctl(cmd,(void *) arg));
 
 	case SIOCDARP:
@@ -1577,10 +1582,13 @@
 {
   if (sk) {
 	if (sk->wmem_alloc + size < sk->sndbuf || force) {
-		cli();
-		sk->wmem_alloc+= size;
-		sti();
-		return(alloc_skb(size, priority));
+		struct sk_buff * c = alloc_skb(size, priority);
+		if (c) {
+			cli();
+			sk->wmem_alloc+= size;
+			sti();
+		}
+		return c;
 	}
 	DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
 						sk, size, force, priority));
@@ -1595,10 +1603,12 @@
 {
   if (sk) {
 	if (sk->rmem_alloc + size < sk->rcvbuf || force) {
-		void *c = alloc_skb(size, priority);
-		cli();
-		if (c) sk->rmem_alloc += size;
-		sti();
+		struct sk_buff *c = alloc_skb(size, priority);
+		if (c) {
+			cli();
+			sk->rmem_alloc += size;
+			sti();
+		}
 		return(c);
 	}
 	DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n",
@@ -1849,7 +1859,7 @@
   struct inet_protocol *p;
   int i;
 
-  printk("Swansea University Computer Society Net2Debugged [1.27]\n");
+  printk("Swansea University Computer Society Net2Debugged [1.30]\n");
   /* Set up our UNIX VFS major device. */
   if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) {
 	printk("%s: cannot register major device %d!\n",
diff -u +recursive +new-file 0.99pl15/linux/net/inet/sock.h linux/net/inet/sock.h
--- 0.99pl15/linux/net/inet/sock.h	Wed Feb  2 17:06:44 1994
+++ linux/net/inet/sock.h	Wed Mar  2 11:29:06 1994
@@ -55,12 +55,15 @@
   struct options		*opt;
   volatile unsigned long	wmem_alloc;
   volatile unsigned long	rmem_alloc;
-  unsigned long			send_seq;
+  unsigned long			write_seq;
+  unsigned long			sent_seq;
   unsigned long			acked_seq;
   unsigned long			copied_seq;
   unsigned long			rcv_ack_seq;
   unsigned long			window_seq;
   unsigned long			fin_seq;
+  unsigned long			urg_seq;
+  unsigned long			urg_data;
 
   /*
    * Not all are volatile, but some are, so we
@@ -112,7 +115,6 @@
   volatile unsigned short	cong_count;
   volatile unsigned short	ssthresh;
   volatile unsigned short	packets_out;
-  volatile unsigned short	urg;
   volatile unsigned short	shutdown;
   volatile unsigned long	rtt;
   volatile unsigned long	mdev;
diff -u +recursive +new-file 0.99pl15/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- 0.99pl15/linux/net/inet/tcp.c	Thu Feb  3 12:55:16 1994
+++ linux/net/inet/tcp.c	Sun Mar 13 16:03:36 1994
@@ -59,6 +59,10 @@
  *		Alan Cox	:	Added a couple of small NET2E timer fixes
  *		Charles Hedrick :	TCP fixes
  *		Toomas Tamm	:	TCP window fixes
+ *		Alan Cox	:	Small URG fix to rlogin ^C ack fight
+ *		Charles Hedrick	:	Window fix
+ *		Linus		:	Rewrote tcp_read() and URG handling
+ *					completely
  *
  *
  * To Fix:
@@ -113,28 +117,29 @@
 }
 
 
-void
-print_th(struct tcphdr *th)
+static void __print_th(struct tcphdr *th)
 {
-  unsigned char *ptr;
-
-  if (inet_debug != DBG_TCP) return;
+	unsigned char *ptr;
 
-  printk("TCP header:\n");
-  ptr =(unsigned char *)(th + 1);
-  printk("    source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
-	ntohs(th->source), ntohs(th->dest),
-	ntohl(th->seq), ntohl(th->ack_seq));
-  printk("    fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
-	th->fin, th->syn, th->rst, th->psh, th->ack,
-	th->urg, th->res1, th->res2);
-  printk("    window = %d, check = %d urg_ptr = %d\n",
-	ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
-  printk("    doff = %d\n", th->doff);
-  printk("    options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
- }
-
+	printk("TCP header:\n");
+	printk("    source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
+		ntohs(th->source), ntohs(th->dest),
+		ntohl(th->seq), ntohl(th->ack_seq));
+	printk("    fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
+		th->fin, th->syn, th->rst, th->psh, th->ack,
+		th->urg, th->res1, th->res2);
+	printk("    window = %d, check = %d urg_ptr = %d\n",
+		ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
+	printk("    doff = %d\n", th->doff);
+	ptr =(unsigned char *)(th + 1);
+	printk("    options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
+}
 
+static inline void print_th(struct tcphdr *th)
+{
+	if (inet_debug == DBG_TCP)
+		__print_th(th);
+}
 
 /* This routine grabs the first thing off of a rcv queue. */
 static struct sk_buff *
@@ -339,10 +344,8 @@
 	if (before(counted, skb->h.th->seq)) 	/* Found a hole so stops here */
 		break;
 	sum = skb->len -(counted - skb->h.th->seq);	/* Length - header but start from where we are up to (avoid overlaps) */
-	if (skb->h.th->syn) sum++;
-	if (skb->h.th->urg) {
-		sum -= ntohs(skb->h.th->urg_ptr);	/* Dont count urg data */
-	}
+	if (skb->h.th->syn)
+		sum++;
 	if (sum >= 0) {					/* Add it up, move on */
 		amount += sum;
 		if (skb->h.th->syn) amount--;
@@ -351,6 +354,9 @@
 	if (amount && skb->h.th->psh) break;
 	skb =(struct sk_buff *)skb->next;		/* Move along */
   } while(skb != sk->rqueue);
+  if (amount && !sk->urginline && sk->urg_data &&
+      (sk->urg_seq - sk->copied_seq) <= (counted - sk->copied_seq))
+	amount--;		/* don't count urg data */
   restore_flags(flags);
   DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
   if(sk->debug)
@@ -431,16 +437,16 @@
 			"tcp_select: sleeping on write sk->wmem_alloc = %d, "
 			"sk->packets_out = %d\n"
 			"sk->wback = %X, sk->wfront = %X\n"
-			"sk->send_seq = %u, sk->window_seq=%u\n", 
+			"sk->write_seq = %u, sk->window_seq=%u\n", 
 				sk->wmem_alloc, sk->packets_out,
 				sk->wback, sk->wfront,
-				sk->send_seq, sk->window_seq));
+				sk->write_seq, sk->window_seq));
 
 		release_sock(sk);
 		return(0);
 	case SEL_EX:
 		select_wait(sk->sleep,wait);
-		if (sk->err) {
+		if (sk->err || sk->urg_data) {
 			release_sock(sk);
 			return(1);
 		}
@@ -484,23 +490,11 @@
 		}
 	case SIOCATMARK:
 		{
-			struct sk_buff *skb;
-			int answ = 0;
+			int answ = sk->urg_data && sk->urg_seq == sk->copied_seq+1;
 
-			/*
-			 * Try to figure out if we need to read
-			 * some urgent data.
-			 */
-			sk->inuse = 1;
-			if ((skb=skb_peek(&sk->rqueue)) != NULL) 
-			{
-				if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) 
-						answ = 1;
-			}
-			release_sock(sk);
-			err=verify_area(VERIFY_WRITE,(void *) arg,
+			err = verify_area(VERIFY_WRITE,(void *) arg,
 						  sizeof(unsigned long));
-			if(err)
+			if (err)
 				return err;
 			put_fs_long(answ,(int *) arg);
 			return(0);
@@ -598,14 +592,15 @@
 static void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
 {
 	int size;
+	struct tcphdr * th = skb->h.th;
 
 	/* length of packet (not counting length of pre-tcp headers) */
-	size = skb->len - ((unsigned char *) skb->h.th - skb->data);
+	size = skb->len - ((unsigned char *) th - skb->data);
 
 	/* sanity check it.. */
 	if (size < sizeof(struct tcphdr) || size > skb->len) {
 		printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n",
-			skb, skb->data, skb->h.th, skb->len);
+			skb, skb->data, th, skb->len);
 		kfree_skb(skb, FREE_WRITE);
 		return;
 	}
@@ -613,7 +608,7 @@
 	/* If we have queued a header size packet.. */
 	if (size == sizeof(struct tcphdr)) {
 		/* If its got a syn or fin its notionally included in the size..*/
-		if(!skb->h.th->syn && !skb->h.th->fin) {
+		if(!th->syn && !th->fin) {
 			printk("tcp_send_skb: attempt to queue a bogon.\n");
 			kfree_skb(skb,FREE_WRITE);
 			return;
@@ -621,16 +616,16 @@
 	}
   
 	/* We need to complete and send the packet. */
-	tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk);
+	tcp_send_check(th, sk->saddr, sk->daddr, size, sk);
 
-	skb->h.seq = sk->send_seq;
-	if (after(sk->send_seq , sk->window_seq) ||
+	skb->h.seq = ntohl(th->seq) + size - 4*th->doff;
+	if (after(skb->h.seq, sk->window_seq) ||
 	    (sk->retransmits && sk->timeout == TIME_WRITE) ||
 	     sk->packets_out >= sk->cong_window) {
 		DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
 					sk->cong_window, sk->packets_out));
-		DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
-					sk->send_seq, sk->window_seq));
+		DPRINTF((DBG_TCP, "sk->write_seq = %d, sk->window_seq = %d\n",
+					sk->write_seq, sk->window_seq));
 		skb->next = NULL;
 		skb->magic = TCP_WRITE_QUEUE_MAGIC;
 		if (sk->wback == NULL) {
@@ -644,6 +639,7 @@
 		    sk->ack_backlog == 0)
 		  reset_timer(sk, TIME_PROBE0, sk->rto);
 	} else {
+		sk->sent_seq = sk->write_seq;
 		sk->prot->queue_xmit(sk, skb->dev, skb, 0);
 	}
 }
@@ -786,7 +782,7 @@
 
   /* FIXME: want to get rid of this. */
   memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
-  th->seq = htonl(sk->send_seq);
+  th->seq = htonl(sk->write_seq);
   th->psh =(push == 0) ? 1 : 0;
   th->doff = sizeof(*th)/4;
   th->ack = 1;
@@ -927,7 +923,7 @@
 			from += copy;
 			copied += copy;
 			len -= copy;
-			sk->send_seq += copy;
+			sk->write_seq += copy;
 		      }
 		if ((skb->len - hdrlen) >= sk->mss ||
 		    (flags & MSG_OOB) ||
@@ -950,14 +946,11 @@
 	 *   be queued for later rather than sent.
 	 */
 
-	copy = diff(sk->window_seq, sk->send_seq);
-	/* what if max_window == 1?  In that case max_window >> 1 is 0.
-	 * however in that case copy == max_window, so it's OK to use 
-	 * the window */
-	if (copy < (sk->max_window >> 1))
-	  copy = sk->mss;
-	copy = min(copy, sk->mss);
-	copy = min(copy, len);
+	copy = sk->window_seq - sk->write_seq;
+	if (copy <= 0 || copy < (sk->max_window >> 1) || copy > sk->mss)
+		copy = sk->mss;
+	if (copy > len)
+		copy = len;
 
   /* We should really check the window here also. */
 	send_tmp = NULL;
@@ -1050,7 +1043,7 @@
 	len -= copy;
 	skb->len += copy;
 	skb->free = 0;
-	sk->send_seq += copy;
+	sk->write_seq += copy;
 
 	if (send_tmp != NULL && sk->packets_out) {
 		tcp_enqueue_partial(send_tmp, sk);
@@ -1071,7 +1064,7 @@
   if(sk->partial && 
      ((!sk->packets_out) 
      /* If not nagling we can send on the before case too.. */
-      || (sk->nonagle && before(sk->send_seq , sk->window_seq))
+      || (sk->nonagle && before(sk->write_seq , sk->window_seq))
       ))
   	tcp_send_partial(sk);
   /* -- */
@@ -1143,7 +1136,7 @@
   t1 =(struct tcphdr *)(buff->data +tmp);
 
   memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-  t1->seq = ntohl(sk->send_seq);
+  t1->seq = htonl(sk->sent_seq);
   t1->ack = 1;
   t1->res1 = 0;
   t1->res2 = 0;
@@ -1251,325 +1244,201 @@
 tcp_read_urg(struct sock * sk, int nonblock,
 	     unsigned char *to, int len, unsigned flags)
 {
-  int copied = 0;
-  struct sk_buff *skb;
+	struct wait_queue wait = { current, NULL };
 
-  DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
-					sk, to, len, flags));
+	while (len > 0) {
+		if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
+			return -EINVAL;
+		if (sk->urg_data & URG_VALID) {
+			char c = sk->urg_data;
+			if (!(flags & MSG_PEEK))
+				sk->urg_data = URG_READ;
+			put_fs_byte(c, to);
+			return 1;
+		}
 
-  while(len > 0) 
-  {
-	sk->inuse = 1;
-	while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) {
 		if (sk->err) {
-			int tmp;
-
-			release_sock(sk);
-			if (copied) return(copied);
-			tmp = -sk->err;
+			int tmp = -sk->err;
 			sk->err = 0;
-			return(tmp);
+			return tmp;
 		}
 
 		if (sk->state == TCP_CLOSE || sk->done) {
-			release_sock(sk);
-			if (copied) return(copied);
 			if (!sk->done) {
 				sk->done = 1;
-				return(0);
+				return 0;
 			}
-			return(-ENOTCONN);
-		}
-		 
-		if (sk->shutdown & RCV_SHUTDOWN) {
-			release_sock(sk);
-			if (copied == 0) 
-				sk->done = 1;
-			return(copied);
-		}
-
-		if (nonblock || copied) {
-			release_sock(sk);
-			if (copied) return(copied);
-			return(-EAGAIN);
+			return -ENOTCONN;
 		}
 
-		/* Now at this point, we may have gotten some data. */
-		release_sock(sk);
-		cli();
-		if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) &&
-		    sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) {
-			interruptible_sleep_on(sk->sleep);
-			if (current->signal & ~current->blocked) {
-				sti();
-				if (copied) return(copied);
-				return(-ERESTARTSYS);
-			}
+		if (sk->shutdown & RCV_SHUTDOWN) {
+			sk->done = 1;
+			return 0;
 		}
-		sk->inuse = 1;
-		sti();
-	}
 
-	skb = skb_peek(&sk->rqueue);
-	do {
-		int amt;
+		if (nonblock)
+			return -EAGAIN;
 
-		if (skb->h.th->urg && !skb->urg_used) {
-			if (skb->h.th->urg_ptr == 0) {
-				skb->h.th->urg_ptr = ntohs(skb->len);
-			}
-			amt = min(ntohs(skb->h.th->urg_ptr),len);
-			if(amt)
-			{
-				memcpy_tofs(to,(unsigned char *)(skb->h.th) +
-							skb->h.th->doff*4, amt);
-			}
+		if (current->signal & ~current->blocked)
+			return -ERESTARTSYS;
 
-			if (!(flags & MSG_PEEK)) {
-				skb->urg_used = 1;
-				sk->urg--;
-			}
-			release_sock(sk);
-			copied += amt;
-			return(copied);
-		}
-		skb =(struct sk_buff *)skb->next;
-	} while(skb != sk->rqueue);
-  }
-/*sk->urg = 0;*/
-  release_sock(sk);
-  return(0);
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(sk->sleep, &wait);
+		if ((sk->urg_data & URG_NOTYET) && sk->err == 0 &&
+		    !(sk->shutdown & RCV_SHUTDOWN))
+			schedule();
+		remove_wait_queue(sk->sleep, &wait);
+		current->state = TASK_RUNNING;
+	}
+	return 0;
 }
 
 
 /* This routine copies from a sock struct into the user buffer. */
-static int
-tcp_read(struct sock *sk, unsigned char *to,
-	 int len, int nonblock, unsigned flags)
+static int tcp_read(struct sock *sk, unsigned char *to,
+	int len, int nonblock, unsigned flags)
 {
-  int copied=0; /* will be used to say how much has been copied. */
-  struct sk_buff *skb;
-  unsigned long offset;
-  unsigned long used;
-  int err;
-
-  if (len == 0) return(0);
-  if (len < 0) {
-	return(-EINVAL);
-  }
-    
-  err=verify_area(VERIFY_WRITE,to,len);
-  if(err)
-  	return err;
-  	
-  /* This error should be checked. */
-  if (sk->state == TCP_LISTEN) return(-ENOTCONN);
+	struct wait_queue wait = { current, NULL };
+	int copied = 0;
+	unsigned long peek_seq;
+	unsigned long *seq;
+	unsigned long used;
+	int err;
+
+	if (len == 0)
+		return 0;
+
+	if (len < 0)
+		return -EINVAL;
+
+	err = verify_area(VERIFY_WRITE, to, len);
+	if (err)
+		return err;
+
+	/* This error should be checked. */
+	if (sk->state == TCP_LISTEN)
+		return -ENOTCONN;
+
+	/* Urgent data needs to be handled specially. */
+	if (flags & MSG_OOB)
+		return tcp_read_urg(sk, nonblock, to, len, flags);
+
+	peek_seq = sk->copied_seq;
+	seq = &sk->copied_seq;
+	if (flags & MSG_PEEK)
+		seq = &peek_seq;
 
-  /* Urgent data needs to be handled specially. */
-  if ((flags & MSG_OOB)) 
-  	return(tcp_read_urg(sk, nonblock, to, len, flags));
+	add_wait_queue(sk->sleep, &wait);
+	sk->inuse = 1;
+	while (len > 0) {
+		struct sk_buff * skb;
+		unsigned long offset;
+	
+		/*
+		 * are we at urgent data? Stop if we have read anything.
+		 */
+		if (copied && sk->urg_data && sk->urg_seq == 1+*seq)
+			break;
 
-  /* So no-one else will use this socket. */
-  sk->inuse = 1;
-  
-  skb=skb_peek(&sk->rqueue);
+		current->state = TASK_INTERRUPTIBLE;
 
-  DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
-						sk, to, len, nonblock, flags));
+		skb = sk->rqueue;
+		do {
+			if (!skb)
+				break;
+			if (before(1+*seq, skb->h.th->seq))
+				break;
+			offset = 1 + *seq - skb->h.th->seq;
+			if (skb->h.th->syn)
+				offset--;
+			if (offset < skb->len)
+				goto found_ok_skb;
+			if (!(flags & MSG_PEEK))
+				skb->used = 1;
+			skb = (struct sk_buff *)skb->next;
+		} while (skb != sk->rqueue);
 
-  while(len > 0) {
-	/* skb->used just checks to see if we've gone all the way around. */
-	
-	/* While no data, or first data indicates some is missing, or data is used */
-	while(skb == NULL ||
-	      before(sk->copied_seq+1, skb->h.th->seq) || skb->used) {
-		DPRINTF((DBG_TCP, "skb = %X:\n", skb));
-		cleanup_rbuf(sk);
-		if (sk->err) 
-		{
-			int tmp;
+		if (copied)
+			break;
 
-			release_sock(sk);
-			if (copied) 
-			{
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-									copied));
-				return(copied);
-			}
-			tmp = -sk->err;
+		if (sk->err) {
+			copied = -sk->err;
 			sk->err = 0;
-			return(tmp);
+			break;
 		}
 
-		if (sk->state == TCP_CLOSE) 
-		{
-			release_sock(sk);
-			if (copied) {
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-				return(copied);
-			}
+		if (sk->state == TCP_CLOSE) {
 			if (!sk->done) {
 				sk->done = 1;
-				return(0);
+				break;
 			}
-			return(-ENOTCONN);
+			copied = -ENOTCONN;
+			break;
 		}
 
-		if (sk->shutdown & RCV_SHUTDOWN) 
-		{
-			release_sock(sk);
-			if (copied == 0) sk->done = 1;
-			DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-			return(copied);
+		if (sk->shutdown & RCV_SHUTDOWN) {
+			sk->done = 1;
+			break;
 		}
 			
-		if (nonblock || copied) 
-		{
-			release_sock(sk);
-			if(sk->debug)
-				printk("read: EAGAIN\n");
-			if (copied) 
-			{
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-				return(copied);
-			}
-			return(-EAGAIN);
+		if (nonblock) {
+			copied = -EAGAIN;
+			break;
 		}
 
-		if ((flags & MSG_PEEK) && copied != 0) 
-		{
-			release_sock(sk);
-			DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-			return(copied);
-		}
-		 
-		DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
-								sk->state));
+		cleanup_rbuf(sk);
 		release_sock(sk);
-
-		/*
-		 * Now we may have some data waiting or we could
-		 * have changed state.
-		 */
-		cli();
-		if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) {
-			sk->inuse = 1;
-			sti();
-			continue;
-		}
-
-		if (skb_peek(&sk->rqueue) == NULL ||
-		    before(sk->copied_seq+1, sk->rqueue->h.th->seq)) {
-		        if(sk->debug)
-		        	printk("Read wait sleep\n");
-			interruptible_sleep_on(sk->sleep);
-			if(sk->debug)
-				printk("Read wait wakes\n");
-			if (current->signal & ~current->blocked) {
-				sti();
-				if (copied) {
-					DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-					return(copied);
-				}
-				return(-ERESTARTSYS);
-			}
-		}
+		schedule();
 		sk->inuse = 1;
-		sti();
-		DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
-
 
-		skb=skb_peek(&sk->rqueue);
-		/* That may have been null if we were beaten, if so we loop again */
-	}
+		if (current->signal & ~current->blocked) {
+			copied = -ERESTARTSYS;
+			break;
+		}
+		continue;
 
-	/*
-	 * Copy anything from the current block that needs
-	 * to go into the user buffer.
-	 */
-	 offset = sk->copied_seq+1 - skb->h.th->seq;
-  
-	 if (skb->h.th->syn) offset--;
-	 if (offset < skb->len) /* Some of the packet is useful */
-	 {
-		/*
-		 * If there is urgent data we must either
-		 * return or skip over it.
-		 */
-		if (skb->h.th->urg) 
-		{
-			if (skb->urg_used) 
-			{
-				sk->copied_seq += ntohs(skb->h.th->urg_ptr);
-				offset += ntohs(skb->h.th->urg_ptr);
-				if (offset >= skb->len) 
-				{
-					skb->used = 1;
-					skb =(struct sk_buff *)skb->next;
-					continue;
-				}
-			} 
-			else 
-			{
-				release_sock(sk);
-				if (copied) 
-					return(copied);
-				send_sig(SIGURG, current, 0);
-				return(-EINTR);
+	found_ok_skb:
+		/* Ok so how much can we use ? */
+		used = skb->len - offset;
+		if (len < used)
+			used = len;
+		/* do we have urgent data here? */
+		if (sk->urg_data) {
+			unsigned long urg_offset = sk->urg_seq - (1 + *seq);
+			if (urg_offset < used) {
+				if (!urg_offset) {
+					if (!sk->urginline) {
+						++*seq;
+						offset++;
+						used--;
+					}
+				} else
+					used = urg_offset;
 			}
 		}
-		/* Ok so how much can we use ? */
-		used = min(skb->len - offset, len);
 		/* Copy it */
 		memcpy_tofs(to,((unsigned char *)skb->h.th) +
-			    skb->h.th->doff*4 + offset, used);
+			skb->h.th->doff*4 + offset, used);
 		copied += used;
 		len -= used;
 		to += used;
-		
-		/* If we were reading the data is 'eaten' */
-		if (!(flags & MSG_PEEK)) 
-			sk->copied_seq += used;
-	      
-		/*
-		 * Mark this data used if we are really reading it,
-		 * and if it doesn't contain any urgent data. And we
-		 * have used all the data.
-		 */
-		if (!(flags & MSG_PEEK) &&
-		   (!skb->h.th->urg || skb->urg_used) &&
-		   (used + offset >= skb->len)) 
-		   	skb->used = 1;
-	      
-		/*
-		 * See if this is the end of a message or if the
-		 * remaining data is urgent.
-		 */
-		if (/*skb->h.th->psh || */skb->h.th->urg) 
-		{
-			break;
-		}
-	} 
-	else 
-	{	/* already used this data, must be a retransmit */
-		skb->used = 1;
+		*seq += used;
+		if (after(sk->copied_seq+1,sk->urg_seq))
+			sk->urg_data = 0;
+		if (!(flags & MSG_PEEK) && (used + offset >= skb->len))
+			skb->used = 1;
 	}
-	/* Move along a packet */
-	skb =(struct sk_buff *)skb->next;
-  }
-  /* Clean up data we have read: This will do ACK frames */
-  cleanup_rbuf(sk);
-  release_sock(sk);
-  DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-  if (copied == 0 && nonblock) 
-  	return(-EAGAIN);
-  return(copied);
+	remove_wait_queue(sk->sleep, &wait);
+	current->state = TASK_RUNNING;
+
+	/* Clean up data we have read: This will do ACK frames */
+	cleanup_rbuf(sk);
+	release_sock(sk);
+	DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+	return copied;
 }
 
-  
+ 
 /*
  * Send a FIN without closing the connection.
  * Not called at interrupt time.
@@ -1629,9 +1498,9 @@
   buff->len += tmp;
   buff->dev = dev;
   memcpy(t1, th, sizeof(*t1));
-  t1->seq = ntohl(sk->send_seq);
-  sk->send_seq++;
-  buff->h.seq = sk->send_seq;
+  t1->seq = ntohl(sk->write_seq);
+  sk->write_seq++;
+  buff->h.seq = sk->write_seq;
   t1->ack = 1;
   t1->ack_seq = ntohl(sk->acked_seq);
   t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
@@ -1651,6 +1520,7 @@
 	sk->wback = buff;
 	buff->magic = TCP_WRITE_QUEUE_MAGIC;
   } else {
+        sk->sent_seq = sk->write_seq;
 	sk->prot->queue_xmit(sk, dev, buff, 0);
   }
 
@@ -1744,13 +1614,13 @@
   
   if(th->ack)
   {
-  	t1->ack=0;
-  	t1->seq=th->ack_seq;
-  	t1->ack_seq=0;
+  	t1->ack = 0;
+  	t1->seq = th->ack_seq;
+  	t1->ack_seq = 0;
   }
   else
   {
-  	t1->ack=1;
+  	t1->ack = 1;
   	if(!th->syn)
   		t1->ack_seq=htonl(th->seq);
   	else
@@ -1925,10 +1795,10 @@
   newsk->copied_seq = skb->h.th->seq;
   newsk->state = TCP_SYN_RECV;
   newsk->timeout = 0;
-  newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
-  newsk->window_seq = newsk->send_seq;
-  newsk->rcv_ack_seq = newsk->send_seq;
-  newsk->urg =0;
+  newsk->write_seq = jiffies * SEQ_TICK - seq_offset;
+  newsk->window_seq = newsk->write_seq;
+  newsk->rcv_ack_seq = newsk->write_seq;
+  newsk->urg_data = 0;
   newsk->retransmits = 0;
   newsk->destroy = 0;
   newsk->timer.data = (unsigned long)newsk;
@@ -2013,14 +1883,15 @@
   t1 =(struct tcphdr *)((char *)t1 +tmp);
   
   memcpy(t1, skb->h.th, sizeof(*t1));
-  buff->h.seq = newsk->send_seq;
+  buff->h.seq = newsk->write_seq;
 
   /* Swap the send and the receive. */
   t1->dest = skb->h.th->source;
   t1->source = newsk->dummy_th.source;
-  t1->seq = ntohl(newsk->send_seq++);
+  t1->seq = ntohl(newsk->write_seq++);
   t1->ack = 1;
   newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/
+  newsk->sent_seq = newsk->write_seq;
   t1->window = ntohs(newsk->window);
   t1->res1 = 0;
   t1->res2 = 0;
@@ -2162,9 +2033,9 @@
 		buff->len += tmp;
 		buff->dev = dev;
 		memcpy(t1, th, sizeof(*t1));
-		t1->seq = ntohl(sk->send_seq);
-		sk->send_seq++;
-		buff->h.seq = sk->send_seq;
+		t1->seq = ntohl(sk->write_seq);
+		sk->write_seq++;
+		buff->h.seq = sk->write_seq;
 		t1->ack = 1;
 
 		/* Ack everything immediately from now on. */
@@ -2177,6 +2048,7 @@
 		tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
 
 		if (sk->wfront == NULL) {
+			sk->sent_seq = sk->write_seq;
 			prot->queue_xmit(sk, dev, buff, 0);
 		} else {
 			reset_timer(sk, TIME_WRITE, sk->rto);
@@ -2243,6 +2115,7 @@
 			kfree_skb(skb, FREE_WRITE);
 			if (!sk->dead) sk->write_space(sk);
 		} else {
+			sk->sent_seq = skb->h.seq;
 			sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
 		}
 	}
@@ -2310,8 +2183,9 @@
   if (sk->retransmits && sk->timeout == TIME_KEEPOPEN)
   	sk->retransmits = 0;
 
-  if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1)) {
-	if (after(ack, sk->send_seq) ||
+/* not quite clear why the +1 and -1 here, and why not +1 in next line */
+  if (after(ack, sk->sent_seq+1) || before(ack, sk->rcv_ack_seq-1)) {
+	if (after(ack, sk->sent_seq) ||
 	   (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) {
 		return(0);
 	}
@@ -2587,7 +2461,7 @@
   if (sk->state == TCP_TIME_WAIT) {
 	if (!sk->dead)
 		sk->state_change(sk);
-	if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) {
+	if (sk->rcv_ack_seq == sk->write_seq && sk->acked_seq == sk->fin_seq) {
 		flag |= 1;
 		sk->state = TCP_CLOSE;
 		sk->shutdown = SHUTDOWN_MASK;
@@ -2596,13 +2470,13 @@
 
   if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) {
 	if (!sk->dead) sk->state_change(sk);
-	if (sk->rcv_ack_seq == sk->send_seq) {
+	if (sk->rcv_ack_seq == sk->write_seq) {
 		flag |= 1;
 		if (sk->acked_seq != sk->fin_seq) {
 			tcp_time_wait(sk);
 		} else {
 			DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk));
-			tcp_send_ack(sk->send_seq, sk->acked_seq, sk,
+			tcp_send_ack(sk->sent_seq, sk->acked_seq, sk,
 				     th, sk->daddr);
 			sk->shutdown = SHUTDOWN_MASK;
 			sk->state = TCP_CLOSE;
@@ -2673,7 +2547,7 @@
   sk->bytes_rcv += skb->len;
   if (skb->len == 0 && !th->fin && !th->urg && !th->psh) {
 	/* Don't want to keep passing ack's back and forth. */
-	if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
+	if (!th->ack) tcp_send_ack(sk->sent_seq, sk->acked_seq,sk, th, saddr);
 	kfree_skb(skb, FREE_READ);
 	return(0);
   }
@@ -2777,8 +2651,16 @@
   /* Now figure out if we can ack anything. */
   if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) {
       if (before(th->seq, sk->acked_seq+1)) {
-		if (after(th->ack_seq, sk->acked_seq))
-					sk->acked_seq = th->ack_seq;
+		int newwindow;
+
+		if (after(th->ack_seq, sk->acked_seq)) {
+			newwindow = sk->window -
+				       (th->ack_seq - sk->acked_seq);
+			if (newwindow < 0)
+				newwindow = 0;	
+			sk->window = newwindow;
+			sk->acked_seq = th->ack_seq;
+		}
 		skb->acked = 1;
 
 		/* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
@@ -2793,16 +2675,12 @@
 			if (before(skb2->h.th->seq, sk->acked_seq+1)) {
 				if (after(skb2->h.th->ack_seq, sk->acked_seq))
 				{
-					long old_acked_seq = sk->acked_seq;
+					newwindow = sk->window -
+					 (skb2->h.th->ack_seq - sk->acked_seq);
+					if (newwindow < 0)
+						newwindow = 0;	
+					sk->window = newwindow;
 					sk->acked_seq = skb2->h.th->ack_seq;
-					if((int)(sk->acked_seq - old_acked_seq) >0)
-					{
-						int new_window=sk->window-sk->acked_seq+
-							old_acked_seq;
-						if(new_window<0)
-							new_window=0;
-						sk->window = new_window;
-					}
 				}
 				skb2->acked = 1;
 
@@ -2829,7 +2707,7 @@
 		if (!sk->delay_acks ||
 		    sk->ack_backlog >= sk->max_ack_backlog || 
 		    sk->bytes_rcv > sk->max_unacked || th->fin) {
-/*			tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
+/*			tcp_send_ack(sk->sent_seq, sk->acked_seq,sk,th, saddr); */
 		} else {
 			sk->ack_backlog++;
 			if(sk->debug)
@@ -2874,12 +2752,12 @@
 #endif		
 		kfree_skb(skb1, FREE_READ);
 	}
-	tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+	tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
 	sk->ack_backlog++;
 	reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
   } else {
 	/* We missed a packet.  Send an ack to try to resync things. */
-	tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+	tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
   }
 
   /* Now tell the user we may have some data. */
@@ -2892,10 +2770,10 @@
   }
 
   if (sk->state == TCP_FIN_WAIT2 &&
-      sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) {
+      sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->write_seq) {
 	DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
 
-/*	tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
+/*	tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr); */
 	sk->shutdown = SHUTDOWN_MASK;
 	sk->state = TCP_LAST_ACK;
 	if (!sk->dead) sk->state_change(sk);
@@ -2905,23 +2783,23 @@
 }
 
 
-static int
-tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
+static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
 {
-  extern int kill_pg(int pg, int sig, int priv);
-  extern int kill_proc(int pid, int sig, int priv);
-    
-  if (!sk->dead) 
-  	sk->data_ready(sk,0);
-    
-  if (sk->urginline) {
-	th->urg = 0;
-	th->psh = 1;
-	return(0);
-  }
+	unsigned long ptr = ntohs(th->urg_ptr);
+
+	if (ptr)
+		ptr--;
+	ptr += th->seq;
+
+	/* ignore urgent data that we've already seen and read */
+	if (after(sk->copied_seq+1, ptr))
+		return;
 
-  if (!sk->urg) {
-	/* So if we get more urgent data, we don't signal the user again. */
+	/* do we already have a newer (or duplicate) urgent pointer? */
+	if (sk->urg_data && !after(ptr, sk->urg_seq))
+		return;
+
+	/* tell the world about our new urgent pointer */
 	if (sk->proc != 0) {
 		if (sk->proc > 0) {
 			kill_proc(sk->proc, SIGURG, 1);
@@ -2929,9 +2807,33 @@
 			kill_pg(-sk->proc, SIGURG, 1);
 		}
 	}
-  }
-  sk->urg++;
-  return(0);
+	sk->urg_data = URG_NOTYET;
+	sk->urg_seq = ptr;
+}
+
+static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
+	unsigned long saddr, unsigned long len)
+{
+	unsigned long ptr;
+
+	/* check if we get a new urgent pointer */
+	if (th->urg)
+		tcp_check_urg(sk,th);
+
+	/* do we wait for any urgent data? */
+	if (sk->urg_data != URG_NOTYET)
+		return 0;
+
+	/* is the urgent pointer pointing into this packet? */
+	ptr = sk->urg_seq - th->seq + th->doff*4;
+	if (ptr >= len)
+		return 0;
+
+	/* ok, got the correct packet, update info */
+	sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
+	if (!sk->dead)
+		wake_up_interruptible(sk->sleep);
+	return 0;
 }
 
 
@@ -3069,9 +2971,9 @@
 
   sk->inuse = 1;
   sk->daddr = sin.sin_addr.s_addr;
-  sk->send_seq = jiffies * SEQ_TICK - seq_offset;
-  sk->window_seq = sk->send_seq;
-  sk->rcv_ack_seq = sk->send_seq -1;
+  sk->write_seq = jiffies * SEQ_TICK - seq_offset;
+  sk->window_seq = sk->write_seq;
+  sk->rcv_ack_seq = sk->write_seq -1;
   sk->err = 0;
   sk->dummy_th.dest = sin.sin_port;
   release_sock(sk);
@@ -3101,8 +3003,9 @@
   t1 = (struct tcphdr *)((char *)t1 +tmp);
 
   memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
-  t1->seq = ntohl(sk->send_seq++);
-  buff->h.seq = sk->send_seq;
+  t1->seq = ntohl(sk->write_seq++);
+  sk->sent_seq = sk->write_seq;
+  buff->h.seq = sk->write_seq;
   t1->ack = 0;
   t1->window = 2;
   t1->res1=0;
@@ -3152,75 +3055,60 @@
 }
 
 
-/* This functions checks to see if the tcp header is actually acceptible. */
+/* This functions checks to see if the tcp header is actually acceptable. */
 static int
 tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
 	     struct options *opt, unsigned long saddr, struct device *dev)
 {
-  /*
-   * This isn't quite right.  sk->acked_seq could be more recent
-   * than sk->window.  This is however close enough.  We will accept
-   * slightly more packets than we should, but it should not cause
-   * problems unless someone is trying to forge packets.
-   */
-  DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n",
-	  sk, th, len, opt, saddr));
+	unsigned long next_seq;
 
-  if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)||
-      between(th->seq + len-(th->doff*4), sk->acked_seq + 1,
-	      sk->acked_seq + sk->window) ||
-     (before(th->seq, sk->acked_seq) &&
-       after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window))) {
-       return(1);
-   }
-  DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
+	next_seq = len - 4*th->doff;
+	if (th->fin)
+		next_seq++;
+	/* if we have a zero window, we can't have any data in the packet.. */
+	if (next_seq && !sk->window)
+		goto ignore_it;
+	next_seq += th->seq;
 
-  /*
-   *	Send a reset if we get something not ours and we are
-   *	unsynchronized. Note: We don't do anything to our end. We
-   *	are just killing the bogus remote connection then we will
-   *	connect again and it will work (with luck).
-   */
-  	 
-  if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV)
-  {
-  	tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
-  	return(1);
-  }
+	/*
+	 * This isn't quite right.  sk->acked_seq could be more recent
+	 * than sk->window.  This is however close enough.  We will accept
+	 * slightly more packets than we should, but it should not cause
+	 * problems unless someone is trying to forge packets.
+	 */
 
-  /*
-   * If it's too far ahead, send an ack to let the
-   * other end know what we expect.
-   */
-  if (after(th->seq, sk->acked_seq + sk->window)) {
-	if(!th->rst)
-		tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
-	return(0);
-  }
+	/* have we already seen all of this packet? */
+	if (!after(next_seq+1, sk->acked_seq))
+		goto ignore_it;
+	/* or does it start beyond the window? */
+	if (!before(th->seq, sk->acked_seq + sk->window + 1))
+		goto ignore_it;
 
-#ifdef undef
-/*
- * if we do this, we won't respond to keepalive packets, since those
- * are slightly out of window, and we have to generate an ack
- * a late ack out still not to have a sequence number less than
- * one we've seen before.  Berkeley doesn't seem to do this, but it's
- * always hard to be sure.
- */
-  /* In case it's just a late ack, let it through. */
-  if (th->ack && len == (th->doff * 4) &&
-      after(th->seq, sk->acked_seq - 32767) &&
-      !th->fin && !th->syn) return(1);
-#endif
+	/* ok, at least part of this packet would seem interesting.. */
+	return 1;
 
-  if (!th->rst) {
-	/* Try to resync things. */
-	tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
-  }
-  return(0);
-}
+ignore_it:
+	DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
 
+	/*
+	 *	Send a reset if we get something not ours and we are
+	 *	unsynchronized. Note: We don't do anything to our end. We
+	 *	are just killing the bogus remote connection then we will
+	 *	connect again and it will work (with luck).
+	 */
+  	 
+	if (sk->state==TCP_SYN_SENT || sk->state==TCP_SYN_RECV) {
+		tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
+		return 1;
+	}
 
+	if (th->rst)
+		return 0;
 
+	/* Try to resync things. */
+	tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+	return 0;
+}
 
 
 int
@@ -3278,14 +3166,12 @@
 		return(0);
 	}
 
+	th->seq = ntohl(th->seq);
+
 	/* See if we know about the socket. */
 	if (sk == NULL) {
-		if (!th->rst) 
-		{	
-			th->seq = ntohl(th->seq);
-			/* So reset is always called with th->seq in host order */
+		if (!th->rst)
 			tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
-		}
 		skb->sk = NULL;
 		kfree_skb(skb, FREE_READ);
 		return(0);
@@ -3296,15 +3182,12 @@
 	skb->acked = 0;
 	skb->used = 0;
 	skb->free = 0;
-	skb->urg_used = 0;
 	skb->saddr = daddr;
 	skb->daddr = saddr;
 
-	th->seq = ntohl(th->seq);
-
-       /* We may need to add it to the backlog here. */
-       cli();
-       if (sk->inuse) {
+	/* We may need to add it to the backlog here. */
+	cli();
+	if (sk->inuse) {
 		if (sk->back_log == NULL) {
 			sk->back_log = skb;
 			skb->next = skb;
@@ -3374,7 +3257,7 @@
 #ifdef undef
 /* nice idea, but tcp_sequence already does this.  Maybe it shouldn't?? */
 			if(!th->rst)
-				tcp_send_ack(sk->send_seq, sk->acked_seq, 
+				tcp_send_ack(sk->sent_seq, sk->acked_seq, 
 				     sk, th, saddr);
 #endif
 			kfree_skb(skb, FREE_READ);
@@ -3421,19 +3304,17 @@
 			release_sock(sk);
 			return(0);
 		}
-		if (th->ack) {
-			if (!tcp_ack(sk, th, saddr, len)) {
-				kfree_skb(skb, FREE_READ);
-				release_sock(sk);
-				return(0);
-			}
+
+		if (th->ack && !tcp_ack(sk, th, saddr, len)) {
+			kfree_skb(skb, FREE_READ);
+			release_sock(sk);
+			return(0);
 		}
-		if (th->urg) {
-			if (tcp_urg(sk, th, saddr)) {
-				kfree_skb(skb, FREE_READ);
-				release_sock(sk);
-				return(0);
-			}
+
+		if (tcp_urg(sk, th, saddr, len)) {
+			kfree_skb(skb, FREE_READ);
+			release_sock(sk);
+			return(0);
 		}
 
 		if (tcp_data(skb, sk, saddr, len)) {
@@ -3573,7 +3454,7 @@
 				/* Ack the syn and fall through. */
 				sk->acked_seq = th->seq+1;
 				sk->fin_seq = th->seq;
-				tcp_send_ack(sk->send_seq, th->seq+1,
+				tcp_send_ack(sk->sent_seq, th->seq+1,
 							sk, th, sk->daddr);
 	
 			case TCP_SYN_RECV:
@@ -3617,7 +3498,7 @@
 				 * already in the established state.
 				 */
 				if (th->urg) {
-					if (tcp_urg(sk, th, saddr)) { 
+					if (tcp_urg(sk, th, saddr, len)) { 
 						kfree_skb(skb, FREE_READ);
 						release_sock(sk);
 						return(0);
@@ -3632,7 +3513,7 @@
 		}
 
 		if (th->urg) {
-			if (tcp_urg(sk, th, saddr)) {
+			if (tcp_urg(sk, th, saddr, len)) {
 				kfree_skb(skb, FREE_READ);
 				release_sock(sk);
 				return(0);
@@ -3671,7 +3552,9 @@
   if (sk->zapped)
 	return;	/* Afer a valid reset we can send no more */
 
-  if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return;
+  if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
+      sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2)
+	return;
 
   buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
   if (buff == NULL) return;
@@ -3701,7 +3584,7 @@
    * Use a previous sequence.
    * This should cause the other end to send an ack.
    */
-  t1->seq = ntohl(sk->send_seq-1);
+  t1->seq = htonl(sk->sent_seq-1);
   t1->ack = 1; 
   t1->res1= 0;
   t1->res2= 0;
@@ -3721,101 +3604,25 @@
   sk->prot->queue_xmit(sk, dev, buff, 1);
 }
 
-/*
- * This routine probes a zero window.  It makes a copy of the first
- * packet in the write queue, but with just one byte of data.
- */
 void
 tcp_send_probe0(struct sock *sk)
 {
-  unsigned char *raw;
-  struct iphdr *iph;
-  struct sk_buff *skb2, *skb;
-  int len, hlen, data;
-  struct tcphdr *t1;
-  struct device *dev;
+	if (sk->zapped)
+		return;		/* Afer a valid reset we can send no more */
 
-  if (sk->zapped)
-	return;	/* Afer a valid reset we can send no more */
-
-  if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT &&
-      sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2)
-  	return;
+	tcp_write_wakeup(sk);
 
-  skb = sk->wfront;
-  if (skb == NULL)
-        return;
-
-  dev = skb->dev;
-  /* I know this can't happen but as it does.. */
-  if(dev==NULL)
-    {
-      printk("tcp_send_probe0: NULL device bug!\n");
-      return;
-    }
-  IS_SKB(skb);
-
-  raw = skb->data;
-  iph = (struct iphdr *) (raw + dev->hard_header_len);
-
-  hlen = (iph->ihl * sizeof(unsigned long)) + dev->hard_header_len;
-  data = skb->len - hlen - sizeof(struct tcphdr);
-  len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0);
- 	
-  /* Allocate buffer. */
-  if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) {
-/*    printk("alloc failed raw %x th %x hlen %d data %d len %d\n",
-	   raw, skb->h.th, hlen, data, len); */
-    reset_timer (sk, TIME_PROBE0, 10);  /* try again real soon */
-    return;
-  }
-
-  skb2->arp = skb->arp;
-  skb2->len = len;
-  skb2->h.raw = (char *)(skb2->data);
- 
-  sk->wmem_alloc += skb2->mem_len;
- 
-  /* Copy the packet header into the new buffer. */
-  memcpy(skb2->h.raw, raw, len);
- 
-  skb2->h.raw += hlen;  /* it's now h.th -- pointer to the tcp header */
-  t1 = skb2->h.th;
- 
-/* source, dest, seq, from existing packet */
-  t1->ack_seq = ntohl(sk->acked_seq);
-  t1->res1 = 0;
-/* doff, fin, from existing packet.  Fin is safe because Linux always
- * sends fin in a separate packet
- * syn, rst, had better be zero in original */
-  t1->ack = 1;
-  t1->urg = 0;  /* urgent pointer might be beyond this fragment */
-  t1->res2 = 0;
-  t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
-  t1->urg_ptr = 0;
-  tcp_send_check(t1, sk->saddr, sk->daddr, len - hlen, sk);
-  /* Send it and free it.
-   * This will prevent the timer from automatically being restarted.
-   */
-  sk->prot->queue_xmit(sk, dev, skb2, 1);
-  sk->backoff++;
-  /*
-   * in the case of retransmissions, there's good reason to limit
-   * rto to 120 sec, as that's the maximum legal RTT on the Internet.
-   * For probes it could reasonably be longer.  However making it
-   * much longer could cause unacceptable delays in some situation,
-   * so we might as well use the same value
-   */
-  sk->rto = min(sk->rto << 1, 120*HZ);
-  reset_timer (sk, TIME_PROBE0, sk->rto);
-  sk->retransmits++;
-  sk->prot->retransmits ++;
+	sk->backoff++;
+	sk->rto = min(sk->rto << 1, 120*HZ);
+	reset_timer (sk, TIME_PROBE0, sk->rto);
+	sk->retransmits++;
+	sk->prot->retransmits ++;
 }
 
+
 /*
  *	Socket option code for TCP. 
- */
-  
+ */  
 int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
 {
 	int val,err;
diff -u +recursive +new-file 0.99pl15/linux/net/inet/tcp.h linux/net/inet/tcp.h
--- 0.99pl15/linux/net/inet/tcp.h	Wed Feb  2 17:02:02 1994
+++ linux/net/inet/tcp.h	Wed Mar  2 11:09:52 1994
@@ -30,6 +30,11 @@
 #define MIN_WRITE_SPACE	2048
 #define TCP_WINDOW_DIFF	2048
 
+/* urg_data states */
+#define URG_VALID	0x0100
+#define URG_NOTYET	0x0200
+#define URG_READ	0x0400
+
 #define TCP_RETR1	7	/*
 				 * This is howmany retries it does before it
 				 * tries to figure out if the gateway is
@@ -75,16 +80,12 @@
  */
 static inline int before(unsigned long seq1, unsigned long seq2)
 {
-	/* this inequality is strict. */
-	if (seq1 == seq2)
-		return 0;
-	seq2 -= seq1;
-	return (seq2 < 65536);
+        return (long)(seq1-seq2) < 0;
 }
 
 static inline int after(unsigned long seq1, unsigned long seq2)
 {
-	return before(seq2, seq1);
+	return (long)(seq1-seq2) > 0;
 }
 
 
@@ -113,7 +114,6 @@
 extern struct proto tcp_prot;
 
 
-extern void	print_th(struct tcphdr *);
 extern void	tcp_err(int err, unsigned char *header, unsigned long daddr,
 			unsigned long saddr, struct inet_protocol *protocol);
 extern void	tcp_shutdown (struct sock *sk, int how);
@@ -124,6 +124,7 @@
 
 extern int	tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 
+extern void tcp_send_probe0(struct sock *sk);
 extern void tcp_enqueue_partial(struct sk_buff *, struct sock *);
 extern struct sk_buff * tcp_dequeue_partial(struct sock *);
 
diff -u +recursive +new-file 0.99pl15/linux/net/unix/proc.c linux/net/unix/proc.c
--- 0.99pl15/linux/net/unix/proc.c	Mon Jan  3 08:51:33 1994
+++ linux/net/unix/proc.c	Fri Mar  4 09:25:21 1994
@@ -16,6 +16,7 @@
  *		Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
  *
  * Fixes:
+ *		Dmitry Gorodchanin	:	/proc locking fix
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -43,7 +44,7 @@
   pos += sprintf(pos, "Num RefCount Protocol Flags    Type St Path\n");
 
   for(i = 0; i < NSOCKETS; i++) {
-	if (unix_datas[i].refcnt) {
+	if (unix_datas[i].refcnt>0) {
 		pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
 			unix_datas[i].refcnt,
 			unix_datas[i].protocol,
diff -u +recursive +new-file 0.99pl15/linux/net/unix/sock.c linux/net/unix/sock.c
--- 0.99pl15/linux/net/unix/sock.c	Mon Jan 31 16:48:28 1994
+++ linux/net/unix/sock.c	Fri Mar  4 09:25:20 1994
@@ -13,13 +13,14 @@
  * Fixes:
  *		Alan Cox	:	Verify Area
  *		NET2E Team	:	Page fault locks
+ *	Dmitry Gorodchanin	:	/proc locking
  *
  * To Do:
+ *	Some nice person is looking into Unix sockets done properly. NET3
+ *	will replace all of this and include datagram sockets and socket
+ *	options - so please stop asking me for them 8-)
  *
- *	Change to the NET2E3 code for Unix domain sockets in general. The
- *	read/write logic is much better and cleaner.
  *
- *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
@@ -237,7 +238,7 @@
   struct unix_proto_data *upd;
 
   for(upd = unix_datas; upd <= last_unix_data; ++upd) {
-	if (upd->refcnt && upd->socket &&
+	if (upd->refcnt > 0 && upd->socket &&
 	    upd->socket->state == SS_UNCONNECTED &&
 	    upd->sockaddr_un.sun_family == sockun->sun_family &&
 	    upd->inode == inode) return(upd);
@@ -254,7 +255,7 @@
   cli();
   for(upd = unix_datas; upd <= last_unix_data; ++upd) {
 	if (!upd->refcnt) {
-		upd->refcnt = 1;
+		upd->refcnt = -1;	/* unix domain socket not yet initialised - bgm */
 		sti();
 		upd->socket = NULL;
 		upd->sockaddr_len = 0;
@@ -328,6 +329,7 @@
   upd->protocol = protocol;
   upd->socket = sock;
   UN_DATA(sock) = upd;
+  upd->refcnt = 1;	/* Now its complete - bgm */
   dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
   return(0);
 }
diff -u +recursive +new-file 0.99pl15/linux/net/unix/unix.h linux/net/unix/unix.h
--- 0.99pl15/linux/net/unix/unix.h	Thu Jan 13 22:56:02 1994
+++ linux/net/unix/unix.h	Fri Mar  4 09:25:21 1994
@@ -15,6 +15,9 @@
  *		Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
+ * Fixes:
+ *		Dmitry Gorodchanin	-	proc locking
+ *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
@@ -27,6 +30,7 @@
 
 struct unix_proto_data {
 	int		refcnt;		/* cnt of reference 0=free	*/
+					/* -1=not initialised	-bgm	*/
 	struct socket	*socket;	/* socket we're bound to	*/
 	int		protocol;
 	struct sockaddr_un	sockaddr_un;
diff -u +recursive +new-file 0.99pl15/linux/zBoot/Makefile linux/zBoot/Makefile
--- 0.99pl15/linux/zBoot/Makefile	Wed Dec  1 14:44:15 1993
+++ linux/zBoot/Makefile	Wed Mar  9 11:11:16 1994
@@ -6,7 +6,7 @@
 
 zOBJECTS = $(HEAD) inflate.o unzip.o misc.o
 
-CFLAGS = -O6 -DSTDC_HEADERS $(TEST)
+CFLAGS = -O2 -DSTDC_HEADERS $(TEST)
 
 .c.s:
 	$(CC) $(CFLAGS) -S -o $*.s $<
@@ -18,7 +18,7 @@
 all:	zSystem
 
 zSystem:	piggy.o $(zOBJECTS)
-		$(LD) $(LDFLAGS) -o zSystem -T 1000 $(zOBJECTS) piggy.o
+		$(LD) $(LDFLAGS) -o zSystem -Ttext 1000 $(zOBJECTS) piggy.o
 
 head.o:	head.s
 
