diff -u --recursive --new-file v1.1.71/linux/CREDITS linux/CREDITS
--- v1.1.71/linux/CREDITS	Tue Nov 29 18:51:23 1994
+++ linux/CREDITS	Tue Dec  6 11:23:54 1994
@@ -710,9 +710,8 @@
 D: NFS mmap()
 D: XF86_S3
 D: Kernel modules
-S: C/ Teodosio 43
-S: Portal 6 1-A
-S: Sevilla 41002
+S: C/ Carlos de Cepeda 36 2-5
+S: Sevilla 41005
 S: Spain
 
 N: Linus Torvalds
diff -u --recursive --new-file v1.1.71/linux/Makefile linux/Makefile
--- v1.1.71/linux/Makefile	Mon Dec  5 18:47:54 1994
+++ linux/Makefile	Tue Dec  6 12:34:20 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 71
+SUBLEVEL = 72
 
 ARCH = i386
 
@@ -102,7 +102,7 @@
 	$(CC) $(CFLAGS) -c -o $*.o $<
 
 Version: dummy
-	rm -f tools/version.h
+	rm -f include/linux/version.h
 
 boot:
 	ln -sf arch/$(ARCH)/boot boot
@@ -127,25 +127,25 @@
 linuxsubdirs: dummy
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
 
-tools/./version.h: tools/version.h
+$(TOPDIR)/include/linux/version.h: include/linux/version.h
 
-tools/version.h: $(CONFIGURE) Makefile
+include/linux/version.h: $(CONFIGURE) Makefile
 	@./makever.sh
-	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > tools/version.h
+	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > include/linux/version.h
 	@if [ -f .name ]; then \
 	   echo \#define UTS_VERSION \"\#`cat .version`-`cat .name` `date`\"; \
 	 else \
 	   echo \#define UTS_VERSION \"\#`cat .version` `date`\";  \
-	 fi >> tools/version.h 
-	@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
-	@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
-	@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
+	 fi >> include/linux/version.h 
+	@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> include/linux/version.h
+	@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> include/linux/version.h
+	@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> include/linux/version.h
 	@if [ -x /bin/dnsdomainname ]; then \
 	   echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \
 	 else \
 	   echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"; \
-	 fi >> tools/version.h
-	@echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> tools/version.h
+	 fi >> include/linux/version.h
+	@echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> include/linux/version.h
 
 tools/build: tools/build.c $(CONFIGURE)
 	$(HOSTCC) $(CFLAGS) -o $@ $<
@@ -155,7 +155,7 @@
 boot/head.s: boot/head.S $(CONFIGURE) include/linux/tasks.h
 	$(CPP) -traditional $< -o $@
 
-tools/version.o: tools/version.c tools/version.h
+tools/version.o: tools/version.c include/linux/version.h
 
 init/main.o: $(CONFIGURE) init/main.c
 	$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
@@ -191,7 +191,7 @@
 	rm -f .tmp* drivers/sound/configure
 
 mrproper: clean
-	rm -f include/linux/autoconf.h tools/version.h
+	rm -f include/linux/autoconf.h include/linux/version.h
 	rm -f drivers/sound/local.h
 	rm -f .version .config* config.in config.old
 	rm -f boot include/asm kernel/entry.S
@@ -204,11 +204,11 @@
 	sync
 
 depend dep:
-	touch tools/version.h
+	touch include/linux/version.h
 	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
+	rm -f include/linux/version.h
 	mv .tmpdepend .depend
 
 ifdef CONFIGURATION
diff -u --recursive --new-file v1.1.71/linux/arch/sparc/boot/boot.S linux/arch/sparc/boot/boot.S
--- v1.1.71/linux/arch/sparc/boot/boot.S	Mon Dec  5 18:47:54 1994
+++ linux/arch/sparc/boot/boot.S	Tue Dec  6 11:15:28 1994
@@ -1,9 +1,44 @@
+/* boot.S: The initial boot code for the Sparc port of Linux.
+
+   Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+
+           This file has to serve three purposes.
+
+	   1) determine the prom-version and cpu/architecture
+	   2) print enough useful info before we start to execute
+	      c-code that I can possibly begin to debug things
+	   3) Hold the vector of trap entry points
+
+   The Sparc offers many challenges to kernel design. Here I will
+   document those I have come across thus far. Upon bootup the boot
+   prom loads your a.out image into memory. This memory the prom has
+   already mapped for you, however as far as I can tell the virtual
+   adress cache is not turned on although the MMU is translating 
+   things. You get loaded at 0xf8004000 exactly. So, when you link
+   a boot-loadable object you want to do something like:
+
+        ld -e start -T f8004000 -o mykernel myobj1.o myobj2.o ....
+
+   to produce a proper image.
+
+   At boot time you are given (as far as I can tell at this time)
+   one key to figure out what machine you are one and what devices
+   are available. The prom when it loads you leaves a pointer to
+   the 'rom vector' in register %o0 right before it jumps to your
+   starting address. This is a pointer to a struct that is full of
+   pointer to functions (ie. printf, halt, reboot), pointers to
+   linked lists (ie. memory mappings), and pointer to imperical
+   constants (ie. stdin and stdout magic cookies + rom version).
+   Starting with this piece of information you can figure out 
+   just about anything you want about the machine you are on.
+*/
+
 #include "boot.h"
 #include "version.h"
 
 	.data
 
-/* First thing to go in the data segment is the interrupt stack */
+/* First thing to go in the data segment is the interrupt stack. */
 
         .globl  _intstack
         .globl  _eintstack
@@ -32,6 +67,12 @@
 
 _cputypvallen = _cputypvar - _cputypval
 
+/* This hold the prom-interface-version number for either v0 or v2. */
+
+	.align 4
+	.globl 	_prom_iface_vers
+
+_prom_iface_vers:	.skip 4
 
 /* WARNING: evil messages follow */
 
@@ -49,14 +90,10 @@
         .asciz  "Sparc-Linux: sun4d support does not exist\n\n"
 	.align 4
 
-
-/* The following will disappear real soon as the implementation is easy */
-
-v2_prom_notyet:
-	.asciz  "Sparc-Linux: v2 boot-prom support not implemented\n\n"
+you_lose:
+	.asciz	"You lose..... Thanks for playing...\n"
 	.align 4
 
-
 /*
    Fill up the prom vector, note in particular the kind first element,
    no joke.
@@ -67,7 +104,7 @@
 _prom_vector_p:		.skip 4
 prom_magic:  		.skip 4			! magic mushroom, beware...
 prom_rom_vers: 		.skip 4			! interface version (v0 or v2)
-prom_pluginvers:	.skip 4			! XXX help help help
+prom_pluginvers:	.skip 4			! XXX help help help ???
 prom_revision:		.skip 4			! PROM revision (ie. 1.4)
 prom_bootstr:		.skip 4			! what we are invoked with
 prom_putchar:		.skip 4			! void putchar(int ch)  BLOCKING.
@@ -82,9 +119,23 @@
 prom_putstring:		.skip 4			! prom putstring()
 prom_bootme:		.skip 4			! reset()
 prom_printf:		.skip 4			! minimal printf()
+
+/* The prom_abort pointer MUST be mapped in all contexts, because if you
+   don't then if a user process is running when you press the abort key
+   sequence, all sorts of bad things can happen
+*/
+
 prom_abort:		.skip 4			! "L1-A" magic cookie
 						! must be mapped in ALL contexts
 prom_ticks:		.skip 4			! number of ticks since reset
+
+/* prom_sync is a place where the kernel should place a pointer to a kernel
+   function that when called will sync all pending information to the drives
+   and then promptly return. If the kernel gets aborted with 'L1-A' one can
+   give the 'sync' command to the boot prompt and this magic cookie gets
+   executed. Nice feature eh?
+*/
+
 prom_sync:		.skip 4			! hook in prom for "sync" func
 prom_v0bootarg:		.skip 4			! v0 prom boot arguements
 prom_v2bootarg:		.skip 4			! same as above for v2 proms
@@ -100,13 +151,37 @@
 
 	.globl boot_msg
 
-/*
-   This gets forth eval'd, just 'cause I think forth is neat to have in a boot
-   monitor :-) We may not need no steenkin BIOS but we do need the prom!
-*/
+/* memory descriptor property strings, v2 = yuk yuk yuk  */
+/* XXX how to figure out vm mapped by prom? May have to scan magic addresses */
+
+mem_prop_physavail:	.asciz "available"
+mem_prop_phystot:	.asciz "reg"
+
+/* v2_memory descriptor struct kludged here for assembly, if it ain't broke */
+
+		.align 4
+v2_mem_struct: 	.skip 0xff
+
+			.align 4
+v2_printf_physavail:	.asciz "Physical Memory Available: 0x%x bytes"
+v2_printf_phystot:	.asciz "Physical Memory: 0x%x bytes"
+
+/* A place to store property strings returned from the prom 'node' funcs */
+
+			.align 4
+prop_string_buf:	.skip 32
+
+prop_name:	.asciz "name"
+		.align 4
+
+current_node:	.skip 4
+		.align 4
+
+
+/* nice little boot message */
 
 boot_msg:	
-	.ascii "Booting Sparc-Linux V0.00PRE-ALPHA (SUN4C) "
+	.ascii "Booting Sparc-Linux V0.00PRE-ALPHA "
 	.ascii WHO_COMPILED_ME 
 	.asciz " \n"
 	.align 4
@@ -155,12 +230,42 @@
    get them in the right place for load time
 */
 
-whereis_bootmsg = boot_msg-KERNBASE
-whereis_kernbase = KERNBASE
+whereis_kernbase      = KERNBASE
 whereis_prom_vector_p = _prom_vector_p-KERNBASE
-whereis_prom_eval = prom_eval-KERNBASE
-whereis_prom_halt = prom_halt-KERNBASE
 	
+/* Ok, things start to get interesting. We get linked such that 'start'
+   is the entry symbol. However, it is real low in kernel address space
+   and as such a nifty place to place the trap table. We achieve this goal
+   by just jumping to 'dostart' for the first trap's entry as the sparc
+   never receives the zero trap as it is real special.
+
+   Each trap entry point is the size of 4 sparc instructions (or 4 bytes
+   * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
+   or unimplemented) and 128 software traps (ditto).
+
+   One of the instructions must be a branch. More often than not this
+   will be to a trap handler entry point becuase it is completely
+   impossible to handle any trap in 4 insns. I welcome anyone to 
+   challenge this theory. :-)
+
+   On entry into this table the hardware has loaded the program counter
+   at which the trap occurred into register %l1 and the next program
+   counter into %l2, this way we can return from the trap with a simple
+
+           jmp %l1; rett %l2
+
+   after properly servicing the trap. It wouldn't be a bad idea to load
+   some more information into the local regs since we have technically
+   2 or 3 instructions to play with besides the jmp to the 'real' trap
+   handler (one can even go in the delay slot). For now I am going to put
+   the %psr (processor status register) and the trap-type value in %l0
+   and %l3 respectively.
+
+   TODO: Write cheesy macros to make this table more manageable.
+         Ugh, this shit is long...
+
+*/
+
 	.globl	start
 	.globl  _trapbase
 start:
@@ -172,51 +277,96 @@
         .word   1
 
 
-        .data
-        .skip   32                      ! alignment byte & negative indicies
-uwtab:  .skip   32                      ! u_char uwtab[-31..31];
-wmask:  .skip   32                      ! u_char wmask[0..31];
+/* The following two things point to window management tables. The first
+   one is used to quickly look up how many user windows there are from
+   trap-land. The second is used in a trap handler to determine if a rett
+   instruction will land us smack inside the invalid window that possibly
+   the trap was called to fix-up.
+*/
+
+          .data
+          .skip   32                      ! alignment byte & negative indicies
+lnx_uw:       .skip   32                      ! u_char uwtab[-31..31];
+lnx_winmask:  .skip   32                      ! u_char wmask[0..31];
 
         .text
 	
-
 	
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+   %g7 and at _prom_vector_p. And also quickly check whether we are on
+   a v0 or v2 prom.
+*/
+
 dostart:	mov	%o0, %g7
 		st	%o0, [_prom_vector_p]   ! we will need it later
 		ld	[%g7 + 0x4], %o2
 		cmp	%o2, 2			! a v2 prom?
-		be	_no_v2_here
+		be	found_v2
 		nop
 
+/* Old sun4's pass our load address into %o0 instead of the prom
+   pointer. On sun4's you have to hard code the romvec pointer into
+   your code. Sun probably still does that because they don't even
+   trust their own "OpenBoot" specifications.
+*/
+
 		set	0x4000, %g6
 		cmp	%o0, %g6		! an old sun4?
 		beq	no_sun4_here
 		nop
 
+		st	%g0, [_prom_iface_vers] ! useless, disappear soon
+		b	not_v2
+		nop
+
+found_v2:
+		set	0x2, %o5
+		st	%o5, [_prom_iface_vers]
+
+not_v2:
+
+/* Get the machine type via the mysterious romvec node operations.
+   Here we can find out whether we are on a sun4 sun4c, sun4m, or
+   a sun4m. The "nodes" are set up as a bunch of n-ary trees which
+   you can traverse to get information about devices and such. The
+   information acquisition happens via the node-ops which are defined
+   in the linux_openprom.h header file. Of particular interest is the
+   'nextnode(int node)' function as it does the smart thing when
+   presented with a value of '0', it gives you the first node in the
+   tree. These node integers probably offset into some internal prom
+   pointer table the openboot has. It's completely undocumented, so
+   I'm not about to go sifting through the prom address space, but may
+   do so if I get suspicious enough. :-)
+*/
+
+		mov	0, %o0			! next_node(0) = first_node
 		ld	[%g7 + 0x1c], %o4
 		ld	[%o4], %o4
 		call 	%o4
-		mov	0, %o0
-		set	_cputypvar, %o1
-		set	_cputypval, %o2
-		ld	[%g7 + 0x1c], %o4
-		ld	[%o4 + 0x0c], %o4
-		call	%o4
 		nop
 
+		set	_cputypvar, %o1		! first node has cpu-arch
+		set	_cputypval, %o2		! information, the string
+		ld	[%g7 + 0x1c], %o4	! 'compatability' tells
+		ld	[%o4 + 0x0c], %o4	! that we want 'sun4x' where
+		call	%o4			! x is one of '', 'c', 'm',
+		nop				! 'd' or 'e'. %o2 holds pointer
+						! to a buf where above string
+						! will get stored by the prom.
 		set	_cputypval, %o2
 		ldub	[%o2 + 4], %o0
-		cmp	%o0, 'c'
-		beq	is_sun4c
-		nop
-		cmp	%o0, 'm'
-		beq	no_sun4m_here
-		nop
-		b	no_sun4d_here
+		cmp	%o0, 'c'		! we already know we are not
+		beq	is_sun4c		! on a plain sun4 because of
+		nop				! the check for 0x4000 in %o0
+		cmp	%o0, 'm'		! at start:
+		beq	is_sun4m
 		nop
+		b	no_sun4d_here		! god bless the person who
+		nop				! tried to run this on sun4d
 
+is_sun4m:
 is_sun4c:					! OK, this is a sun4c, yippie
-		mov 	%g7, %g6		! load up them promvec offsets
+		mov 	%g7, %g6		! load up the promvec offsets
 		st	%g6, [prom_magic]     	! magic mushroom :>
 		add	%g7, 0x4, %g6
 		st	%g6, [prom_rom_vers]
@@ -273,21 +423,29 @@
 		add	%g7, 0x104, %g6
 		st	%g6, [prom_setcontext]
 
+/* That was easy, now lets try to print some message on the screen.
+   We have to be careful because the prom addressed things weird and
+   we aren't really mapped into memory as far as the rom routines are
+   concerned. So all addresses we have ourselves and would like the
+   prom to actually use must be calculated as (addr - KERNBASE) in order
+   for anything to work at all. We will map ourselves later before we
+   call any c-code to avoid this hassle.
+*/
 
 		set	boot_msg-KERNBASE, %o0	
 		ld	[prom_printf-KERNBASE], %o2
 		ld	[%o2], %o1
 		call	%o1  			! print boot message #1
 		nop
-		set	newline-KERNBASE, %o0
+
+_newline:	set	newline-KERNBASE, %o0
 		ld	[prom_printf-KERNBASE], %o2
 		ld	[%o2], %o1
 		call	%o1
 		nop
 
 		b	0f
-		nop
-
+		nop				! damn delay slots...
 
 0:		nop				! duh	
 		set	pstring1-KERNBASE, %o0
@@ -301,29 +459,45 @@
 		set	pstring2-KERNBASE, %o0
 		ld	[prom_printf-KERNBASE], %o3
 		ld	[%o3], %o2
-		ld	[prom_rom_vers-KERNBASE], %o3
+		ld	[_prom_iface_vers], %o3
 		ld	[%o3], %o1
 		call 	%o2
 		nop; nop; nop
 
+/* Print out various bits of memory information. At this point
+   I just cycle through the documented v0_prom memory lists for
+   the values. They are linked lists and allow for description of
+   non-contiguous physical memory configurations, thus the 'memloop'
+   things to traverse the linked lists.
+*/
+
+/* Things are different for v0 and v2. v2 requires traversing the node trees
+   and that really sucks.
+*/
+
+/* Another Note:
+	The prom printf() function can take up to 5 arguements in registers
+	%o1 -- %o5 , the format string goes in %o0. It is your usual libc
+	printf() believe it or not.
+*/
+
+		cmp	%o0, 0x2
+		be	v2_mem_probe
+		nop
+
 		set	pstring4-KERNBASE, %o0
 		ld	[prom_printf-KERNBASE], %o5
 		ld	[%o5], %o4
 		ld	[_prom_vector_p], %l1
 		ld	[%l1+16], %l2
 		ld	[%l2], %l3
-		ld	[%l3 + 8], %o1
+		ld	[%l3 + 8], %o1		! 'nbytes' memory accumulator
 
-/*
-		ld	[%l1], %l2
-		ld	[%l2 + 0x8], %o1    ! physical memory accumulator
-*/
 		ld 	[_prom_vector_p], %l1
 		ld	[%l1 + 16], %l2
 		ld	[%l2], %l3
 		ld	[%l3], %l4
 
-/* 		ld	[%l3], %l4  */
 memloop:
 		cmp	%l4, 0
 		be 	mv_to_vmprom		! is there more?
@@ -391,31 +565,98 @@
 		b	halt_me
 		nop
 
-		.globl _no_v2_here
-_no_v2_here:
-		ld	[%g7 + 0x68], %o1
-		set	v2_prom_notyet-KERNBASE, %o0
-		call    %o1
-		nop
-		b	halt_me
-		nop
-
 no_sun4_here:
 		ld	[%g7 + 0x68], %o1
 		set	sun4_notsup, %o0
 		call	%o1
 		nop
-		b	halt_me
+		b	rest_of_boot			! next stage...
 		nop
 
-no_sun4m_here:
-		ld	[%g7 + 0x68], %o1
-		set	sun4m_notsup, %o0
+v2_mem_probe:
+		set	you_lose-KERNBASE, %o0		! I just print this
+		ld	[prom_printf-KERNBASE], %o1	! crap to debug my node
+		ld	[%o1], %o2			! routines :-)
+		call 	%o2
+		nop
+
+		st	%g0, [current_node]
+		set	prop_string_buf, %o2
+		or	%g0, %g0, %o0
+		ld	[prop_name], %o1
+		or	%g0, 31, %o3		
+
+node_find_loop:
+		ld	[prom_nodefuncs], %o4
+		ld	[%o4 + 0xc], %o4
+		call	%o4
+		nop
+		ld	[prop_string_buf], %l3
+		cmp	%l3, 'm'
+		bne	node_find_loop2
+		ld	[prop_string_buf + 1], %l3
+		cmp	%l3, 'e'
+		bne	node_find_loop2
+		ld	[prop_string_buf + 2], %l3
+		cmp	%l3, 'm'
+		bne	node_find_loop2
+		nop
+		b	found_mem_node
+		nop
+
+node_find_loop2:
+		ld	[current_node], %o0		! get next node
+		ld	[prom_nodefuncs], %o1
+		ld	[%o1], %o1
 		call	%o1
 		nop
-		b	halt_me
+		st	%o0, [current_node]
+		set	prop_string_buf, %o2
+		set	prop_name, %o1
+		b	node_find_loop
+		or	%g0, 31, %o3		
+						
+found_mem_node:
+		set	v2_mem_struct-KERNBASE, %o2
+		set	0xff, %o3
+		set	mem_prop_physavail-KERNBASE, %o1
+		ld	[current_node], %o0
+		ld	[prom_nodefuncs], %o4
+		ld	[%o4 + 0xc], %o4
+		call	%o4
+		nop
+
+		set	v2_printf_physavail-KERNBASE, %o0
+		ld	[v2_mem_struct + 0x8], %o1
+		ld	[prom_printf], %o4
+		ld	[%o4], %o4		
+		call	%o4
+		
+		set	v2_mem_struct-KERNBASE, %o2
+		set	0xff, %o3
+		set	mem_prop_phystot-KERNBASE, %o1
+		ld	[current_node], %o0
+		ld	[prom_nodefuncs], %o4
+		ld	[%o4 + 0xc], %o4
+		call	%o4
 		nop
 
+		set	v2_printf_physavail-KERNBASE, %o0
+		ld	[v2_mem_struct + 0x8], %o1
+		ld	[prom_printf], %o4
+		ld	[%o4], %o4		
+		call	%o4
+		nop
+
+		b	rest_of_boot
+		nop
+
+rest_of_boot:
+		call	halt_me
+		nop				! who cares at this point
+
+/* There, happy now adrian? */
+
 no_sun4d_here:
 		ld	[%g7 + 0x68], %o1
 		set	sun4d_notsup, %o0
@@ -452,3 +693,7 @@
 		ret
 		nop
 		
+
+
+
+
diff -u --recursive --new-file v1.1.71/linux/arch/sparc/string.S linux/arch/sparc/string.S
--- v1.1.71/linux/arch/sparc/string.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/string.S	Tue Dec  6 11:15:01 1994
@@ -0,0 +1,115 @@
+/*  string.h:  Efficient string functions in sparc-assembly for
+               the linux kernel.
+
+    Copyright 1994 (c) David S. Miller (davem@caip.rutgers.edu)
+*/
+
+
+/* If we are smart we will use only the output and global registers 
+   as that will allow us to avoid a window save which would be nice.
+*/
+
+/* Believe it or not the following strlen is not optimized enough!
+   In the future I may play games with doing word reads and reducing
+   the per-word comparisons to *one*, yes I have seen it done.
+*/
+	.align 4
+	.globl _strlen
+_strlen:
+	mov	%o0, %g3	! leaf-proceedure optimization, here
+	ldsb	[%g3], %g2	! I only use the register sent to me
+	cmp	%g2, 0		! and the globals. Now, this routine
+	be	1f		! is callable from boot code.
+	nop
+	add	%o0, 1, %o0
+0:	ldsb	[%o0], %g2
+	cmp	%g2, 0
+	bne,a	0b		! annuling branch, yuck
+	add	%o0, 1, %o0
+
+1:	retl
+	sub	%o0, %g3, %o0	! since %g3 holds the origional pointer
+				! and %o0 is at the end byte, we can
+				! subtract and the result is strlen.
+
+/* String concatenate function. I am too lazy to honor the third count
+   arguement at this time. Once again, this could be optimized so much
+   more to use word accesses instead of slooow byte loads.
+*/
+	.align 4
+	.globl _strcat
+_strcat:
+	mov	%o0, %g4
+	ldsb	[%g4], %g3
+	cmp	%g3, 0
+	be,a	2f
+	ldub	[%o1], %g3
+	add	%o0, 1, %o0
+	
+0:	ldsb	[%o0], %g3
+	cmp	%g3, 0
+	bne,a	0b
+	add	%o0, 1, %o0
+
+1:	ldub	[%o1], %g3
+
+2:	add	%o1, 1, %o1
+	stb	%g3, [%o0]
+	cmp	%g3, 0
+	bne	1b
+	add	%o0, 1, %o0
+	retl
+	mov	%g4, %o0
+
+/* Aieee, this code is starting to give me a headache. I shouldn't
+   have tried to do this in one sitting :-(
+*/
+
+	.align 4
+	.globl _strcmp
+_strcmp:	b	2f
+		ldsb	[%o1], %g4
+
+0:		sll	%o2, 24, %g3
+		cmp	%g3, 0
+		bne	1f
+		add	%o0, 1, %o0
+		b	3f
+		or	%g0, %g0, %o0
+
+1:		ldsb	[%o1], %g4
+
+2:		ldsb	[%o0], %g3
+		add	%o1, 1, %o1
+		cmp	%g3, %g4
+		be	0b
+		mov	%g3, %o2
+		ldub	[%o2], %g3
+		ldub	[%o1-1], %o0		! oh man, no joke
+		sub	%g2, %o0, %o0
+
+3:		retl
+		nop
+
+/* Ok, strcpy() should be easy enough. Maybe I catch some sleep after 
+   this one....
+*/
+	.align 4
+	.globl _strcpy
+_strcpy:	ldub	[%o1], %g3
+		mov	%o0, %g4
+		cmp	%g3, 0
+		be	1f
+		stb	%g3, [%g4]
+
+0:		add	%o1, 1, %o1
+		ldub	[%o1], %g3
+		add	%o0, 1, %o0
+		cmp	%g3, 0
+		bne	0b
+		stb	%g3, [%o0]
+
+1:		retl
+		mov	%g4, %o0
+
+	
\ No newline at end of file
diff -u --recursive --new-file v1.1.71/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.71/linux/drivers/block/floppy.c	Sat Nov 26 18:36:04 1994
+++ linux/drivers/block/floppy.c	Tue Dec  6 11:44:59 1994
@@ -82,8 +82,7 @@
  */
 
 #define CONFIG_FLOPPY_SANITY
-#undef  CONFIG_FLOPPY_23
-#undef  CONFIG_FLOPPY_2_FDC
+#define  CONFIG_FLOPPY_2_FDC
 #undef  CONFIG_FLOPPY_SILENT_DCL_CLEAR
 
 #define REALLY_SLOW_IO
@@ -99,16 +98,12 @@
  * motor of these drives causes system hangs on some PCI computers. drive
  * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
  * a drive is allowed. */
-#ifdef CONFIG_FLOPPY_23
-#define ALLOWED_DRIVE_MASK 0xff
-#else
-#define ALLOWED_DRIVE_MASK 0x33
-#endif
+static int ALLOWED_DRIVE_MASK=0x33;
 
 #define FLOPPY_IRQ 6
 #define FLOPPY_DMA 2
 #define FDC1 0x3f0
-#define FDC2 0x370
+static int FDC2=-1;
 #endif
 
 #define MODULE_AWARE_DRIVER
@@ -236,6 +231,7 @@
 #define R_SECTOR (reply_buffer[5])
 #define R_SIZECODE (reply_buffer[6])
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof( (x)[0] ))
 /*
  * this struct defines the different floppy drive types.
  */
@@ -1500,9 +1496,11 @@
 	printk("floppy driver state\n");
 	printk("-------------------\n");
 	for(i=0; i<N_FDC; i++){
-		printk("dor %d = %x\n", i, fdc_state[i].dor );
-		outb_p(fdc_state[i].address+2, fdc_state[i].dor);
-		udelay(1000); /* maybe we'll catch an interrupt... */
+		if(FDCS->address != -1){
+			printk("dor %d = %x\n", i, fdc_state[i].dor );
+			outb_p(fdc_state[i].address+2, fdc_state[i].dor);
+			udelay(1000); /* maybe we'll catch an interrupt... */
+		}
 	}
 	printk("status=%x\n", inb_p(FD_STATUS));
 	printk("fdc_busy=%d\n", fdc_busy);
@@ -3163,6 +3161,57 @@
 	return FDC_82077;	/* Revised 82077AA passes all the tests */
 } /* get_fdc_version */
 
+#ifndef FD_MODULE
+/* lilo configuration */
+static void invert_dcl(int *ints)
+{
+	int i;
+	
+	for (i=0; i < ARRAY_SIZE(default_drive_params); i++)
+		default_drive_params[i].params.flags |= 0x80;
+	DPRINT("Configuring drives for inverted dcl\n");
+}
+
+static void allow_drives(int *ints)
+{
+	if (ints[1] >= 1 ){
+		ALLOWED_DRIVE_MASK=ints[1];
+		DPRINT1("setting allowed_drive_mask to 0x%x\n", ints[1]);
+	} else
+		DPRINT("allowed_drive_mask needs a parameter\n");
+}
+
+#ifdef  CONFIG_FLOPPY_2_FDC
+static void twofdc(int *ints)
+{
+	FDC2 = 0x370;
+	DPRINT("enabling second fdc at address 0x370\n");
+}
+#endif
+
+static struct param_table {
+	char *name;
+	void (*fn)(int *ints);
+} config_params[]={
+{ "allowed_drive_mask", allow_drives },
+#ifdef  CONFIG_FLOPPY_2_FDC
+{ "two_fdc", twofdc },
+#endif
+{ "thinkpad", invert_dcl } };
+
+void floppy_setup(char *str, int *ints)
+{
+	int i;
+	for(i=0; i< ARRAY_SIZE(config_params); i++){
+		if (strcmp(str,config_params[i].name) == 0 ){
+			config_params[i].fn(ints);
+			return;
+		}
+	}
+	printk("unknown floppy paramter %s\n", str);
+}
+#endif
+
 #ifdef FD_MODULE
 static
 #endif
@@ -3230,12 +3279,16 @@
 		if (FDCS->address == -1 )
 			continue;
 		FDCS->rawcmd = 2;
-		if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
+		if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)){
+			FDCS->address = -1;
 			continue;
+		}
 		/* Try to determine the floppy controller type */
 		FDCS->version = get_fdc_version();
-		if (FDCS->version == FDC_NONE)
+		if (FDCS->version == FDC_NONE){
+			FDCS->address = -1;
 			continue;
+		}
 
 		have_no_fdc = 0;
 		/* Not all FDCs seem to be able to handle the version command
@@ -3272,10 +3325,12 @@
 #ifdef FD_MODULE
 	MOD_INC_USE_COUNT;
 #endif
-	for(i=0; i< N_FDC; i++){		
-		fdc = i;
-		reset_fdc_info(1);
-		outb_p(FDCS->dor, FD_DOR);
+	for(i=0; i< N_FDC; i++){
+		if(FDCS->address != -1){	
+			fdc = i;
+			reset_fdc_info(1);
+			outb_p(FDCS->dor, FD_DOR);
+		}
 	}
 	set_dor(0, ~0, 8);  /* avoid immediate interrupt */
 
diff -u --recursive --new-file v1.1.71/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.1.71/linux/drivers/char/lp.c	Thu Dec  1 19:15:03 1994
+++ linux/drivers/char/lp.c	Tue Dec  6 12:38:25 1994
@@ -34,7 +34,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 /* 
@@ -467,7 +467,7 @@
 		if (testvalue == LP_DUMMY) {
 			LP_F(offset) |= LP_EXIST;
 			lp_reset(offset);
-			printk("lp_init: lp%d exists, ", offset);
+			printk("lp%d at 0x%04x, ", offset,LP_B(offset));
 			snarf_region(LP_B(offset), 3);
 			if (LP_IRQ(offset))
 				printk("using IRQ%d\n", LP_IRQ(offset));
@@ -505,7 +505,8 @@
 		if (testvalue == LP_DUMMY) {
 			LP_F(offset) |= LP_EXIST;
 			lp_reset(offset);
-			printk("lp_init: lp%d exists, ", offset);
+			printk("lp%d at 0x%04x, ", offset,LP_B(offset));
+			snarf_region(LP_B(offset),3);
 			if (LP_IRQ(offset))
 				printk("using IRQ%d\n", LP_IRQ(offset));
 			else
@@ -520,10 +521,14 @@
 
 void cleanup_module(void)
 {
-       if(MOD_IN_USE)
+        int offset;
+	if(MOD_IN_USE)
                printk("lp: busy - remove delayed\n");
-       else
+        else
                unregister_chrdev(LP_MAJOR,"lp");
+	       for (offset = 0; offset < LP_NO; offset++) 
+			if(LP_F(offset) && LP_EXIST) 
+		 		release_region(LP_B(offset),3);
 }
 
 #endif
diff -u --recursive --new-file v1.1.71/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v1.1.71/linux/drivers/net/3c501.c	Mon Nov 28 14:21:44 1994
+++ linux/drivers/net/3c501.c	Tue Dec  6 12:37:33 1994
@@ -45,7 +45,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 extern struct device *init_etherdev(struct device *dev, int sizeof_private,
diff -u --recursive --new-file v1.1.71/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v1.1.71/linux/drivers/net/3c509.c	Thu Dec  1 19:15:03 1994
+++ linux/drivers/net/3c509.c	Tue Dec  6 12:37:33 1994
@@ -44,7 +44,7 @@
 #include <linux/skbuff.h>
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 
diff -u --recursive --new-file v1.1.71/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v1.1.71/linux/drivers/net/8390.c	Mon Nov 28 14:21:44 1994
+++ linux/drivers/net/8390.c	Tue Dec  6 12:37:33 1994
@@ -54,7 +54,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 /* These are the operational function interfaces to board-specific
diff -u --recursive --new-file v1.1.71/linux/drivers/net/MODULES linux/drivers/net/MODULES
--- v1.1.71/linux/drivers/net/MODULES	Tue Nov 29 18:51:24 1994
+++ linux/drivers/net/MODULES	Tue Dec  6 11:41:30 1994
@@ -3,6 +3,7 @@
 	de600.o \
 	de620.o \
 	3c501.o \
+	apricot.o \
 	eexpress.o \
 	plip.o \
 	8390.o
diff -u --recursive --new-file v1.1.71/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.71/linux/drivers/net/Space.c	Thu Nov  3 17:53:29 1994
+++ linux/drivers/net/Space.c	Tue Dec  6 13:09:02 1994
@@ -28,8 +28,6 @@
 #include <linux/netdevice.h>
 #include <linux/errno.h>
 
-#define LOOPBACK			/* always present, right?	*/
-
 #define	NEXT_DEV	NULL
 
 
@@ -49,6 +47,7 @@
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
 extern int depca_probe(struct device *);
+extern int apricot_probe(struct device *);
 extern int ewrk3_probe(struct device *);
 extern int el1_probe(struct device *);
 extern int el16_probe(struct device *);
@@ -112,6 +111,9 @@
 #ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
         && ewrk3_probe(dev)
 #endif
+#ifdef CONFIG_APRICOT		/* Apricot I82596 */
+	&& apricot_probe(dev)
+#endif
 #ifdef CONFIG_EL1		/* 3c501 */
 	&& el1_probe(dev)
 #endif
@@ -289,9 +291,8 @@
 #   define	NEXT_DEV	(&dummy_dev)
 #endif
 
-#ifdef LOOPBACK
-    extern int loopback_init(struct device *dev);
-    static struct device loopback_dev = {
+extern int loopback_init(struct device *dev);
+struct device loopback_dev = {
 	"lo",			/* Software Loopback interface		*/
 	0x0,			/* recv memory end			*/
 	0x0,			/* recv memory start			*/
@@ -302,10 +303,6 @@
 	0, 0, 0,		/* flags				*/
 	NEXT_DEV,		/* next device				*/
 	loopback_init		/* loopback_init should set up the rest	*/
-    };
-#   undef	NEXT_DEV
-#   define	NEXT_DEV	(&loopback_dev)
-#endif
-
+};
 
-struct device *dev_base = NEXT_DEV;
+struct device *dev_base = &loopback_dev;
diff -u --recursive --new-file v1.1.71/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v1.1.71/linux/drivers/net/apricot.c	Mon Nov 28 14:21:44 1994
+++ linux/drivers/net/apricot.c	Tue Dec  6 12:37:33 1994
@@ -3,6 +3,8 @@
     Apricot
     	Written 1994 by Mark Evans.
 	This driver is for the Apricot 82596 bus-master interface
+
+        Modularised 12/94 Mark Evans
     
     Driver skeleton 
 	Written 1993 by Donald Becker.
@@ -17,7 +19,7 @@
 
 */
 
-static char *version = "apricot.c:v0.02 19/05/94\n";
+static char *version = "apricot.c:v0.2 05/12/94\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -36,6 +38,11 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
 #ifndef HAVE_PORTRESERVE
 #define check_region(addr, size)	0
 #define snarf_region(addr, size)	do ; while(0)
@@ -46,9 +53,6 @@
 #define kfree_skbmem(buff, size) kfree_s(buff,size)
 #endif
 
-struct device *init_etherdev(struct device *dev, int sizeof_private,
-			     unsigned long *mem_start);
-
 #define APRICOT_DEBUG 1
 
 #ifdef APRICOT_DEBUG
@@ -59,6 +63,8 @@
 
 #define APRICOT_TOTAL_SIZE 17
 
+#define I596_NULL -1
+
 #define CMD_EOL		0x8000	/* The last command of the list, stop. */
 #define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
 #define CMD_INTR	0x2000	/* Interrupt after doing cmd. */
@@ -116,7 +122,7 @@
     char data[1532];
 };
 
-#define RX_RING_SIZE 16
+#define RX_RING_SIZE 8
 
 struct i596_scb {
     unsigned short status;
@@ -154,7 +160,6 @@
     char i596_config[16];
     struct i596_cmd tdr;
     unsigned long stat;
-    struct i596_rfd rx[RX_RING_SIZE];
     int last_restart;
     struct i596_rfd *rx_tail;
     struct i596_cmd *cmd_tail;
@@ -180,8 +185,6 @@
 	0x00,
 	0x7f	/*  *multi IA */ };
 
-char adds[] = {0x00, 0x00, 0x49, 0x20, 0x54, 0xDA, 0x80, 0x00, 0x4e, 0x02, 0xb7, 0xb8};
-
 static int i596_open(struct device *dev);
 static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
 static void i596_interrupt(int reg_ptr);
@@ -194,52 +197,59 @@
 #endif
 
 
-static inline void
-init_rx_bufs(struct device *dev)
+static inline int
+init_rx_bufs(struct device *dev, int num)
 {
     struct i596_private *lp = (struct i596_private *)dev->priv;
     int i;
-    int boguscnt = 100;
-    short ioaddr = dev->base_addr;
+    struct i596_rfd *rfd;
+
+    lp->scb.rfd = (struct i596_rfd *)I596_NULL;
 
-    if (i596_debug > 1) printk ("%s: init_rx_bufs.\n", dev->name);
+    if (i596_debug > 1) printk ("%s: init_rx_bufs %d.\n", dev->name, num);
 
-    for (i = 0; i < RX_RING_SIZE; i++)
+    for (i = 0; i < num; i++)
     {
-	if (i == 0)
-	{
-	    lp->scb.rfd = &lp->rx[0];
-	}
-	if (i == (RX_RING_SIZE - 1))
-	{
-	    lp->rx_tail = &(lp->rx[i]);
-	    lp->rx[i].next = &lp->rx[0];
-	    lp->rx[i].cmd = CMD_EOL;
-	}
-	else
-	{
-	    lp->rx[i].next = &lp->rx[i+1];
-	    lp->rx[i].cmd = 0x0000;
-	}
-	lp->rx[i].stat = 0x0000;
-	lp->rx[i].rbd = 0xffffffff;
-	lp->rx[i].count = 0;
-	lp->rx[i].size = 1532;
+	if (!(rfd = (struct i596_rfd *)kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
+            break;
+
+	rfd->stat = 0x0000;
+	rfd->rbd = I596_NULL;
+	rfd->count = 0;
+	rfd->size = 1532;
+        if (i == 0)
+        {
+	    rfd->cmd = CMD_EOL;
+            lp->rx_tail = rfd;
+        }
+        else
+	    rfd->cmd = 0x0000;
+
+        rfd->next = lp->scb.rfd;
+        lp->scb.rfd = rfd;
     }
 
-    while (lp->scb.status, lp->scb.command)
-	if (--boguscnt == 0)
-	{
-	    printk("%s: init_rx_bufs timed out with status %4.4x, cmd %4.4x.\n",
-		   dev->name, lp->scb.status, lp->scb.command);
-	    break;
-    	}
+    if (i != 0)
+      lp->rx_tail->next = lp->scb.rfd;
 
-    lp->scb.command = RX_START;
-    outw(0, ioaddr+4);
+    return (i);
+}
 
-    return;
+static inline void
+remove_rx_bufs(struct device *dev)
+{
+    struct i596_private *lp = (struct i596_private *)dev->priv;
+    struct i596_rfd *rfd = lp->scb.rfd;
+
+    lp->rx_tail->next = (struct i596_rfd *)I596_NULL;
 
+    do
+    {
+        lp->scb.rfd = rfd->next;
+        kfree_s(rfd, sizeof(struct i596_rfd));
+        rfd = lp->scb.rfd;
+    }
+    while (rfd != lp->rx_tail);
 }
 
 static inline void
@@ -256,7 +266,7 @@
     outw(((((int)&lp->scp) & 0xffff) | 2), ioaddr);
     outw((((int)&lp->scp)>>16) & 0xffff, ioaddr);
 
-    lp->last_cmd=jiffies;
+    lp->last_cmd = jiffies;
 
     lp->scp.sysbus = 0x00440000;
     lp->scp.iscp = &(lp->iscp);
@@ -264,7 +274,7 @@
     lp->iscp.stat = 0x0001;
     lp->cmd_backlog = 0;
 
-    lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) -1;
+    lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
 
     if (i596_debug > 2) printk("%s: starting i82596.\n", dev->name);
 
@@ -280,6 +290,8 @@
 	    break;
     	}
 
+    lp->scb.command = 0;
+
     memcpy (lp->i596_config, init_setup, 14);
     lp->set_conf.command = CmdConfigure;
     i596_add_cmd(dev, &lp->set_conf);
@@ -291,9 +303,19 @@
     lp->tdr.command = CmdTDR;
     i596_add_cmd(dev, &lp->tdr);
 
-    init_rx_bufs(dev);
+    boguscnt = 200;
+    while (lp->scb.status, lp->scb.command)
+	if (--boguscnt == 0)
+	{
+	    printk("%s: recieve unit start timed out with status %4.4x, cmd %4.4x.\n",
+		   dev->name, lp->scb.status, lp->scb.command);
+	    break;
+    	}
+
+    lp->scb.command = RX_START;
+    outw(0, ioaddr+4);
 
-    boguscnt=200;
+    boguscnt = 200;
     while (lp->scb.status, lp->scb.command)
         if (--boguscnt == 0)
 	{
@@ -309,7 +331,7 @@
 i596_rx(struct device *dev)
 {
     struct i596_private *lp = (struct i596_private *)dev->priv;
-    int frames=0;
+    int frames = 0;
 
     if (i596_debug > 3) printk ("i596_rx()\n");
 
@@ -333,7 +355,7 @@
 	    }
 
 	    skb->len = pkt_len;
-  	    skb->dev=dev;		
+  	    skb->dev = dev;		
 	    memcpy(skb->data, lp->scb.rfd->data, pkt_len);
 
 	    netif_rx(skb);
@@ -353,12 +375,12 @@
 	    if ((lp->scb.rfd->stat) & 0x1000) lp->stats.rx_length_errors++;
 	}
 
-	lp->scb.rfd->stat=0;
-	lp->rx_tail->cmd=0;
-	lp->rx_tail=lp->scb.rfd;
-	lp->scb.rfd=lp->scb.rfd->next;
-	lp->rx_tail->count=0;
-	lp->rx_tail->cmd=CMD_EOL;
+	lp->scb.rfd->stat = 0;
+	lp->rx_tail->cmd = 0;
+	lp->rx_tail = lp->scb.rfd;
+	lp->scb.rfd = lp->scb.rfd->next;
+	lp->rx_tail->count = 0;
+	lp->rx_tail->cmd = CMD_EOL;
 
     }
 
@@ -375,7 +397,7 @@
 
     if (i596_debug > 4) printk ("i596_cleanup_cmd\n");
 
-    while (lp->cmd_head != (struct i596_cmd *) -1)
+    while (lp->cmd_head != (struct i596_cmd *) I596_NULL)
     {
 	ptr = lp->cmd_head;
 
@@ -394,7 +416,7 @@
 		lp->stats.tx_errors++;
 		lp->stats.tx_aborted_errors++;
 
-		ptr->next = (struct i596_cmd * ) -1;
+		ptr->next = (struct i596_cmd * ) I596_NULL;
 		kfree_s((unsigned char *)tx_cmd, (sizeof (struct tx_cmd) + sizeof (struct i596_tbd)));
 		break;
 	    }
@@ -402,12 +424,12 @@
 	    {
 		unsigned short count = *((unsigned short *) (ptr + 1));
 
-		ptr->next = (struct i596_cmd * ) -1;
+		ptr->next = (struct i596_cmd * ) I596_NULL;
 		kfree_s((unsigned char *)ptr, (sizeof (struct i596_cmd) + count + 2));
 		break;
 	    }
 	    default:
-		ptr->next = (struct i596_cmd * ) -1;
+		ptr->next = (struct i596_cmd * ) I596_NULL;
 	}
     }
 
@@ -437,10 +459,10 @@
 	    break;
 	}
 
-    dev->start=0;
-    dev->tbusy=1;
+    dev->start = 0;
+    dev->tbusy = 1;
 
-    lp->scb.command=CUC_ABORT|RX_ABORT;
+    lp->scb.command = CUC_ABORT|RX_ABORT;
     outw(0, ioaddr+4);
 
     /* wait for shutdown */
@@ -457,9 +479,9 @@
     i596_cleanup_cmd(lp);
     i596_rx(dev);
 
-    dev->start=1;
-    dev->tbusy=0;
-    dev->interrupt=0;
+    dev->start = 1;
+    dev->tbusy = 0;
+    dev->interrupt = 0;
     init_i596_mem(dev);
 }
 
@@ -474,15 +496,15 @@
 
     cmd->status = 0;
     cmd->command |= (CMD_EOL|CMD_INTR);
-    cmd->next = (struct i596_cmd *) -1;
+    cmd->next = (struct i596_cmd *) I596_NULL;
 
     save_flags(flags);
     cli();
-    if (lp->cmd_head != (struct i596_cmd *) -1)
+    if (lp->cmd_head != (struct i596_cmd *) I596_NULL)
 	lp->cmd_tail->next = cmd;
     else 
     {
-	lp->cmd_head=cmd;
+	lp->cmd_head = cmd;
 	while (lp->scb.status, lp->scb.command)
 	    if (--boguscnt == 0)
 	    {
@@ -495,10 +517,10 @@
 	lp->scb.command = CUC_START;
         outw (0, ioaddr+4);
     }
-    lp->cmd_tail=cmd;
+    lp->cmd_tail = cmd;
     lp->cmd_backlog++;
 
-    lp->cmd_head=lp->scb.cmd;
+    lp->cmd_head = lp->scb.cmd;
     restore_flags(flags);
 
     if (lp->cmd_backlog > 16) 
@@ -516,19 +538,34 @@
 static int
 i596_open(struct device *dev)
 {
-    if (request_irq(dev->irq, &i596_interrupt, 0, "apricot")) {
+    int i;
+
+    if (i596_debug > 1)
+	printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+
+    if (request_irq(dev->irq, &i596_interrupt, 0, "apricot"))
 	return -EAGAIN;
-    }
 
     irq2dev_map[dev->irq] = dev;
 
-    if (i596_debug > 1)
-	printk("%s: i596_open() irq %d.\n",
-	       dev->name, dev->irq);
+     i = init_rx_bufs(dev, RX_RING_SIZE);
+
+    if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+        printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
+
+    if (i < 4)
+    {
+        free_irq(dev->irq);
+        irq2dev_map[dev->irq] = 0;
+        return -EAGAIN;
+    }
 
     dev->tbusy = 0;
     dev->interrupt = 0;
     dev->start = 1;
+#ifdef MODULE
+    MOD_INC_USE_COUNT;
+#endif
 
     /* Initialize the 82596 memory */
     init_i596_mem(dev);
@@ -563,7 +600,7 @@
 	    /* Issue a channel attention signal */
 	    if (i596_debug > 1) printk ("Kicking board.\n");
 
-	    lp->scb.command=CUC_START|RX_START;
+	    lp->scb.command = CUC_START|RX_START;
 	    outw(0, ioaddr+4);
 
 	    lp->last_restart = lp->stats.tx_packets;
@@ -592,7 +629,7 @@
     else
     {
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	dev->trans_start=jiffies;
+	dev->trans_start = jiffies;
 
 	tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
 	if (tx_cmd == NULL)
@@ -605,7 +642,7 @@
 	else
 	{
 	    tx_cmd->tbd = (struct i596_tbd *) (tx_cmd + 1);
-	    tx_cmd->tbd->next = (struct i596_tbd *) -1;
+	    tx_cmd->tbd->next = (struct i596_tbd *) I596_NULL;
 
 	    tx_cmd->cmd.command = CMD_FLEX|CmdTx;
 
@@ -646,10 +683,10 @@
     printk ("type %2.2X%2.2X\n", (unsigned char)add[12], (unsigned char)add[13]);
 }
 
-unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end)
+int apricot_probe(struct device *dev)
 {
-    struct device *dev;
     int i;
+    struct i596_private *lp;
     int checksum = 0;
     int ioaddr = 0x300;
     char eth_addr[6];
@@ -658,28 +695,30 @@
     /* first check nothing is already registered here */
 
     if (check_region(ioaddr, APRICOT_TOTAL_SIZE))
-	return mem_start;
+	return ENODEV;
 
     for (i = 0; i < 8; i++)
-	checksum += inb(ioaddr + 8 + i);
+    {
+    	eth_addr[i] = inb(ioaddr+8+i);
+	checksum += eth_addr[i];
+     }
 
     /* checksum is a multiple of 0x100, got this wrong first time
        some machines have 0x100, some 0x200. The DOS driver doesn't
        even bother with the checksum */
 
-    if (checksum % 0x100) return mem_start;
-
+    if (checksum % 0x100) return ENODEV;
 
-    for(i = 0; i < 6 ; i++)
-    	eth_addr[i] = inb(ioaddr +8 +i);
-    
     /* Some other boards trip the checksum.. but then appear as ether
        address 0. Trap these - AC */
        
-    if(memcmp(eth_addr,"\x00\x00\x00\x00\x00\x00",6)==0)
-    	return mem_start;
+    if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0)
+    	return ENODEV;
+
+    snarf_region(ioaddr, APRICOT_TOTAL_SIZE);
 
-    dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start);
+    dev->base_addr = ioaddr;
+    ether_setup(dev);
     printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr);
 
     for (i = 0; i < 6; i++)
@@ -689,10 +728,7 @@
     dev->irq = 10;
     printk(" IRQ %d.\n", dev->irq);
 
-    snarf_region(ioaddr, APRICOT_TOTAL_SIZE);
-
-    if (i596_debug > 0)
-	printk(version);
+    if (i596_debug > 0) printk(version);
 
     /* The APRICOT-specific entries in the device structure. */
     dev->open = &i596_open;
@@ -703,10 +739,16 @@
     dev->set_multicast_list = &set_multicast_list;
 #endif
 
+    dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL);
     /* align for scp */
-    dev->priv = (void *)(((int) dev->priv + 0xf) & 0xfffffff0);
+    dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
+
+    lp = (struct i596_private *)dev->priv;
+    lp->scb.command = 0;
+    lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+    lp->scb.rfd = (struct i596_rfd *)I596_NULL;
 
-    return mem_start;
+    return 0;
 }
 
 static void
@@ -717,7 +759,7 @@
     struct i596_private *lp;
     short ioaddr;
     int boguscnt = 200;
-    unsigned short status, ack_cmd=0;
+    unsigned short status, ack_cmd = 0;
 
     if (dev == NULL) {
 	printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
@@ -757,7 +799,7 @@
 	if ((i596_debug > 4) && (status & 0x2000))
 	    printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
 
-	while ((lp->cmd_head != (struct i596_cmd *) -1) && (lp->cmd_head->status & STAT_C))
+	while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C))
 	{
 	    ptr = lp->cmd_head;
 
@@ -788,7 +830,7 @@
 		    }
 
 
-		    ptr->next = (struct i596_cmd * ) -1;
+		    ptr->next = (struct i596_cmd * ) I596_NULL;
 		    kfree_s((unsigned char *)tx_cmd, (sizeof (struct tx_cmd) + sizeof (struct i596_tbd)));
 		    break;
 		}
@@ -796,7 +838,7 @@
 		{
 		    unsigned short count = *((unsigned short *) (ptr + 1));
 
-		    ptr->next = (struct i596_cmd * ) -1;
+		    ptr->next = (struct i596_cmd * ) I596_NULL;
 		    kfree_s((unsigned char *)ptr, (sizeof (struct i596_cmd) + count + 2));
 		    break;
 		}
@@ -822,20 +864,20 @@
 		    }
 		}
 		default:
-		    ptr->next = (struct i596_cmd * ) -1;
+		    ptr->next = (struct i596_cmd * ) I596_NULL;
 
-		lp->last_cmd=jiffies;
+		lp->last_cmd = jiffies;
  	    }
 	}
 
 	ptr = lp->cmd_head;
-	while ((ptr != (struct i596_cmd *) -1) && (ptr != lp->cmd_tail))
+	while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail))
 	{
 	    ptr->command &= 0x1fff;
 	    ptr = ptr->next;
 	}
 
-	if ((lp->cmd_head != (struct i596_cmd *) -1) && (dev->start)) ack_cmd |= CUC_START;
+	if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd |= CUC_START;
 	lp->scb.cmd = lp->cmd_head;
     }
 
@@ -854,7 +896,7 @@
     /* acknowledge the interrupt */
 
 /*
-    if ((lp->scb.cmd != (struct i596_cmd *) -1) && (dev->start)) ack_cmd |= CUC_START;
+    if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START;
 */
     boguscnt = 100;
     while (lp->scb.status, lp->scb.command)
@@ -881,6 +923,7 @@
 {
     int ioaddr = dev->base_addr;
     struct i596_private *lp = (struct i596_private *)dev->priv;
+    int boguscnt = 200;
 
     dev->start = 0;
     dev->tbusy = 1;
@@ -894,8 +937,20 @@
 
     i596_cleanup_cmd(lp);
 
+    while (lp->scb.status, lp->scb.command)
+	if (--boguscnt == 0)
+	{
+	    printk("%s: close timed timed out with status %4.4x, cmd %4.4x.\n",
+		   dev->name, lp->scb.status, lp->scb.command);
+	    break;
+    	}
     free_irq(dev->irq);
     irq2dev_map[dev->irq] = 0;
+    remove_rx_bufs(dev);
+#ifdef MODULE
+    MOD_DEC_USE_COUNT;
+#endif
+
 
     return 0;
 }
@@ -940,7 +995,7 @@
 	    i596_add_cmd(dev, cmd);
     } else
     {
-	if (lp->set_conf.next != (struct i596_cmd * ) -1) return;
+	if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL) return;
 	if (num_addrs == 0)
 	    lp->i596_config[8] &= ~0x01;
 	else
@@ -954,9 +1009,39 @@
 
 #ifdef HAVE_DEVLIST
 static unsigned int apricot_portlist[] = {0x300, 0};
-struct netdev_entry apricot_drv =
-{"apricot", apricot_init, APRICOT_TOTAL_SIZE, apricot_portlist};
+struct netdev_entry apricot_drv = 
+{"apricot", apricot_probe, APRICOT_TOTAL_SIZE, apricot_portlist};
 #endif
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_apricot = {
+  "        ", /* device name inservted by /linux/drivers/net/net_init.c */
+  0, 0, 0, 0,
+  0x300, 10,
+  0, 0, 0, NULL, apricot_probe };
+
+int
+init_module(void)
+{
+  if (register_netdev(&dev_apricot) != 0)
+    return -EIO;
+  return 0;
+}
+
+void
+cleanup_module(void)
+{
+  if (MOD_IN_USE)
+    printk("%s: device busy, remove delayed\n", dev_apricot.name);
+  else
+  {
+    unregister_netdev(&dev_apricot);
+    kfree_s((void *)dev_apricot.mem_start, sizeof(struct i596_private) + 0xf);
+    dev_apricot.priv = NULL;
+  }
+}
+#endif /* MODULE */
 
 /*
  * Local variables:
diff -u --recursive --new-file v1.1.71/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v1.1.71/linux/drivers/net/de600.c	Mon Nov 28 14:21:44 1994
+++ linux/drivers/net/de600.c	Tue Dec  6 12:37:33 1994
@@ -110,7 +110,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 #ifdef FAKE_SMALL_MAX
diff -u --recursive --new-file v1.1.71/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v1.1.71/linux/drivers/net/de620.c	Mon Nov 28 14:21:44 1994
+++ linux/drivers/net/de620.c	Tue Dec  6 12:37:33 1994
@@ -121,7 +121,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 /* Constant definitions for the DE-620 registers, commands and bits */
diff -u --recursive --new-file v1.1.71/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v1.1.71/linux/drivers/net/depca.c	Wed Oct 12 15:00:25 1994
+++ linux/drivers/net/depca.c	Tue Dec  6 12:37:33 1994
@@ -188,7 +188,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "/linux/tools/version.h"
+#include <linux/version.h>
 #endif /* MODULE */
 
 #include "depca.h"
diff -u --recursive --new-file v1.1.71/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.1.71/linux/drivers/net/eexpress.c	Thu Dec  1 19:15:03 1994
+++ linux/drivers/net/eexpress.c	Tue Dec  6 12:37:34 1994
@@ -57,7 +57,7 @@
 #include <linux/skbuff.h>
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 #include <linux/malloc.h>
diff -u --recursive --new-file v1.1.71/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v1.1.71/linux/drivers/net/ewrk3.c	Sat Nov 26 18:36:05 1994
+++ linux/drivers/net/ewrk3.c	Tue Dec  6 12:37:34 1994
@@ -149,7 +149,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "/linux/tools/version.h"
+#include <linux/version.h>
 #endif /* MODULE */
 
 #include "ewrk3.h"
diff -u --recursive --new-file v1.1.71/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.1.71/linux/drivers/net/net_init.c	Thu Dec  1 19:15:04 1994
+++ linux/drivers/net/net_init.c	Tue Dec  6 11:41:30 1994
@@ -68,9 +68,6 @@
 #if defined(CONFIG_PI)
 	mem_start = pi_init(mem_start, mem_end);
 #endif	
-#if defined(CONFIG_APRICOT)
-	mem_start = apricot_init(mem_start, mem_end);
-#endif	
 	return mem_start;
 }
 
diff -u --recursive --new-file v1.1.71/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.71/linux/drivers/net/plip.c	Thu Dec  1 19:15:04 1994
+++ linux/drivers/net/plip.c	Tue Dec  6 12:37:34 1994
@@ -92,7 +92,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 /* use 0 for production, 1 for verification, >2 for debug */
diff -u --recursive --new-file v1.1.71/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v1.1.71/linux/drivers/net/znet.c	Sun Oct  9 19:28:50 1994
+++ linux/drivers/net/znet.c	Tue Dec  6 16:44:09 1994
@@ -548,18 +548,15 @@
 			lp->stats.rx_length_errors++;
 		} else {
 			/* Malloc up new buffer. */
-			int sksize = sizeof(struct sk_buff) + pkt_len;
 			struct sk_buff *skb;
 
-			skb = alloc_skb(sksize, GFP_ATOMIC);
+			skb = alloc_skb(pkt_len, GFP_ATOMIC);
 			if (skb == NULL) {
 				if (znet_debug)
 				  printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
 				lp->stats.rx_dropped++;
 				break;
 			}
-			skb->mem_len = sksize;
-			skb->mem_addr = skb;
 			skb->len = pkt_len;
 			skb->dev = dev;
 
diff -u --recursive --new-file v1.1.71/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.1.71/linux/drivers/scsi/sg.c	Mon Dec  5 18:47:55 1994
+++ linux/drivers/scsi/sg.c	Tue Dec  6 12:24:26 1994
@@ -58,6 +58,7 @@
  };
 
 static struct scsi_generic *scsi_generics=NULL;
+static void sg_free(char *buff,int size);
 
 static int sg_ioctl(struct inode * inode,struct file * file,
 	     unsigned int cmd_in, unsigned long arg)
@@ -109,7 +110,7 @@
   if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
    {
     if (scsi_generics[dev].buff != NULL)
-      scsi_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
+      sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
     scsi_generics[dev].buff=NULL;
     scsi_generics[dev].pending=0;
    }
diff -u --recursive --new-file v1.1.71/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.1.71/linux/fs/binfmt_elf.c	Thu Dec  1 19:15:04 1994
+++ linux/fs/binfmt_elf.c	Tue Dec  6 12:40:18 1994
@@ -29,7 +29,7 @@
 
 #ifndef CONFIG_BINFMT_ELF
 #include <linux/module.h>
-#include "../tools/version.h"
+#include <linux/version.h>
 #endif
 
 #include <linux/unistd.h>
diff -u --recursive --new-file v1.1.71/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.1.71/linux/fs/isofs/inode.c	Thu Dec  1 19:15:05 1994
+++ linux/fs/isofs/inode.c	Tue Dec  6 12:39:35 1994
@@ -22,7 +22,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #endif
 
 #ifdef LEAK_CHECK
diff -u --recursive --new-file v1.1.71/linux/fs/msdos/inode.c linux/fs/msdos/inode.c
--- v1.1.71/linux/fs/msdos/inode.c	Tue Nov 22 15:41:13 1994
+++ linux/fs/msdos/inode.c	Tue Dec  6 12:39:35 1994
@@ -17,7 +17,7 @@
 
 #ifdef MODULE
 	#include <linux/module.h>
-	#include "../../tools/version.h"
+	#include <linux/version.h>
 #endif
 
 #include <asm/segment.h>
diff -u --recursive --new-file v1.1.71/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.1.71/linux/fs/proc/array.c	Mon Dec  5 18:47:55 1994
+++ linux/fs/proc/array.c	Tue Dec  6 11:25:08 1994
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/mman.h>
 #include <linux/proc_fs.h>
+#include <linux/ioport.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
@@ -529,6 +530,8 @@
 		case PROC_DMA:
 			return get_dma_list(page);
 
+		case PROC_IOPORTS:
+			return get_ioport_list(page);
 	}
 	return -EBADF;
 }
diff -u --recursive --new-file v1.1.71/linux/fs/proc/root.c linux/fs/proc/root.c
--- v1.1.71/linux/fs/proc/root.c	Mon Dec  5 18:47:55 1994
+++ linux/fs/proc/root.c	Tue Dec  6 11:23:54 1994
@@ -73,6 +73,7 @@
    	{ PROC_FILESYSTEMS,	11,"filesystems" },
    	{ PROC_KSYMS,		5, "ksyms" },
    	{ PROC_DMA,		3, "dma" },
+	{ PROC_IOPORTS,		7, "ioports"},
 };
 
 #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
diff -u --recursive --new-file v1.1.71/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v1.1.71/linux/fs/sysv/inode.c	Mon Dec  5 18:47:55 1994
+++ linux/fs/sysv/inode.c	Tue Dec  6 12:39:35 1994
@@ -32,7 +32,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
diff -u --recursive --new-file v1.1.71/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v1.1.71/linux/fs/umsdos/inode.c	Mon Nov 28 14:21:46 1994
+++ linux/fs/umsdos/inode.c	Tue Dec  6 12:40:18 1994
@@ -19,7 +19,7 @@
 
 #ifdef MODULE
 	#include <linux/module.h>
-	#include "../../tools/version.h"
+	#include <linux/version.h>
 #endif
 
 struct inode *pseudo_root=NULL;		/* Useful to simulate the pseudo DOS */
diff -u --recursive --new-file v1.1.71/linux/fs/xiafs/inode.c linux/fs/xiafs/inode.c
--- v1.1.71/linux/fs/xiafs/inode.c	Mon Dec  5 18:47:55 1994
+++ linux/fs/xiafs/inode.c	Tue Dec  6 12:39:35 1994
@@ -21,7 +21,7 @@
 
 #ifdef MODULE
 #include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
diff -u --recursive --new-file v1.1.71/linux/include/asm-m68k/system.h linux/include/asm-m68k/system.h
--- v1.1.71/linux/include/asm-m68k/system.h	Mon Dec  5 18:47:56 1994
+++ linux/include/asm-m68k/system.h	Tue Dec  6 11:46:21 1994
@@ -15,7 +15,7 @@
 #ifndef _M68K_SYSTEM_H
 #define _M68K_SYSTEM_H
 
-#include <linux/autoconf.h> /* get configuration makros */
+#include <linux/autoconf.h> /* get configuration macros */
 
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
 /* block out HSYNC on the atari */
diff -u --recursive --new-file v1.1.71/linux/include/linux/fd.h linux/include/linux/fd.h
--- v1.1.71/linux/include/linux/fd.h	Mon Nov 28 14:21:46 1994
+++ linux/include/linux/fd.h	Tue Dec  6 11:44:59 1994
@@ -127,6 +127,7 @@
 #define FD_BROKEN_DCL 0x20
 #define FD_DEBUG 0x02
 #define FD_SILENT_DCL_CLEAR 0x4
+#define FD_INVERTED_DCL 0x80
 
   char read_track;		/* use readtrack during probing? */
 
diff -u --recursive --new-file v1.1.71/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v1.1.71/linux/include/linux/ioport.h	Tue Nov 29 18:51:28 1994
+++ linux/include/linux/ioport.h	Tue Dec  6 11:23:54 1994
@@ -20,6 +20,7 @@
 extern int check_region(unsigned int from, unsigned int extent);
 extern void snarf_region(unsigned int from, unsigned int extent);
 extern void release_region(unsigned int from, unsigned int extent);
+extern int get_ioport_list(char *);
 
 
 #define HAVE_AUTOIRQ
diff -u --recursive --new-file v1.1.71/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.1.71/linux/include/linux/netdevice.h	Thu Dec  1 19:15:05 1994
+++ linux/include/linux/netdevice.h	Tue Dec  6 13:10:22 1994
@@ -180,6 +180,7 @@
 
 extern volatile char in_bh;
 
+extern struct device	loopback_dev;
 extern struct device	*dev_base;
 extern struct packet_type *ptype_base;
 
diff -u --recursive --new-file v1.1.71/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.1.71/linux/include/linux/proc_fs.h	Mon Dec  5 18:47:56 1994
+++ linux/include/linux/proc_fs.h	Tue Dec  6 11:23:54 1994
@@ -25,7 +25,8 @@
 	PROC_INTERRUPTS,
 	PROC_FILESYSTEMS,
 	PROC_KSYMS,
-	PROC_DMA
+	PROC_DMA,	
+	PROC_IOPORTS
 };
 
 enum pid_directory_inos {
diff -u --recursive --new-file v1.1.71/linux/init/main.c linux/init/main.c
--- v1.1.71/linux/init/main.c	Mon Dec  5 18:47:56 1994
+++ linux/init/main.c	Tue Dec  6 11:45:00 1994
@@ -84,6 +84,7 @@
 extern void bmouse_setup(char *str, int *ints);
 extern void eth_setup(char *str, int *ints);
 extern void xd_setup(char *str, int *ints);
+extern void floppy_setup(char *str, int *ints);
 extern void mcd_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
 extern void st0x_setup(char *str, int *ints);
@@ -220,6 +221,9 @@
 #endif
 #ifdef CONFIG_BLK_DEV_XD
 	{ "xd=", xd_setup },
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+	{ "floppy=", floppy_setup },
 #endif
 #ifdef CONFIG_MCD
 	{ "mcd=", mcd_setup },
diff -u --recursive --new-file v1.1.71/linux/kernel/ioport.c linux/kernel/ioport.c
--- v1.1.71/linux/kernel/ioport.c	Tue Nov 29 18:51:29 1994
+++ linux/kernel/ioport.c	Tue Dec  6 11:23:54 1994
@@ -108,6 +108,26 @@
 	return 0;
 }
 
+int get_ioport_list(char *buf)
+{       int len=0,num,from;
+        for(num=0;num<IO_BITMAP_SIZE*32;num++)
+         if(check_bitmap(ioport_registrar,num,1)) {
+	   from=num;
+	   while(check_bitmap(ioport_registrar,num+1,1) 
+			&& num+1<IO_BITMAP_SIZE*32 )
+		num++;
+	   if(from==num) 
+            len+=sprintf(buf+len,"%04x\n",num);
+	   else
+	    len+=sprintf(buf+len,"%04x-%04x\n",from,num);
+           if(len>4000) {
+                len+=sprintf((buf+len),"4k-Limit reached!\n");
+                return len;
+           }
+         }
+        return len;
+}
+
 /*
  * this changes the io permissions bitmap in the current task.
  */
diff -u --recursive --new-file v1.1.71/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.71/linux/kernel/ksyms.c	Mon Dec  5 18:47:56 1994
+++ linux/kernel/ksyms.c	Tue Dec  6 11:45:00 1994
@@ -76,6 +76,7 @@
 
 #ifdef CONFIG_PCI
 	/* PCI BIOS support */
+	X(pcibios_present),
 	X(pcibios_find_class),
 	X(pcibios_find_device),
 	X(pcibios_read_config_byte),
@@ -235,6 +236,7 @@
 	X(ftape_big_buffer),
 	X(do_floppy),
 #endif
+	X(floppy_track_buffer),
 #ifdef CONFIG_INET
 	/* support for loadable net drivers */
 	X(register_netdev),
@@ -244,6 +246,7 @@
 	X(kfree_skb),
 	X(dev_kfree_skb),
 	X(snarf_region),
+	X(release_region),
 	X(netif_rx),
 	X(dev_rint),
 	X(dev_tint),
diff -u --recursive --new-file v1.1.71/linux/mm/filemap.c linux/mm/filemap.c
--- v1.1.71/linux/mm/filemap.c	Thu Dec  1 19:15:05 1994
+++ linux/mm/filemap.c	Tue Dec  6 11:38:44 1994
@@ -213,8 +213,13 @@
 		return -ENOEXEC;
 	ops = &file_private_mmap;
 	if (vma->vm_flags & VM_SHARED) {
-		if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+		if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) {
+			static int nr = 0;
 			ops = &file_shared_mmap;
+			if (nr++ < 5)
+				printk("%s tried to do a shared writeable mapping\n", current->comm);
+			return -EINVAL;
+		}
 	}
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
diff -u --recursive --new-file v1.1.71/linux/mm/swap.c linux/mm/swap.c
--- v1.1.71/linux/mm/swap.c	Thu Dec  1 19:15:05 1994
+++ linux/mm/swap.c	Tue Dec  6 11:45:00 1994
@@ -804,6 +804,7 @@
 	struct swap_info_struct * p;
 	struct inode * inode;
 	unsigned int type;
+	struct file filp;
 	int i;
 
 	if (!suser())
@@ -825,15 +826,32 @@
 				break;
 		}
 	}
-	iput(inode);
-	if (type >= nr_swapfiles)
+
+	if (type >= nr_swapfiles){
+		iput(inode);
 		return -EINVAL;
+	}
 	p->flags = SWP_USED;
 	i = try_to_unuse(type);
 	if (i) {
+		iput(inode);
 		p->flags = SWP_WRITEOK;
 		return i;
 	}
+
+	if(p->swap_device){
+		memset(&filp, 0, sizeof(filp));		
+		filp.f_inode = inode;
+		filp.f_mode = 3; /* read write */
+		/* open it again to get fops */
+		if( !blkdev_open(inode, &filp) &&
+		   filp.f_op && filp.f_op->release){
+			filp.f_op->release(inode,&filp);
+			filp.f_op->release(inode,&filp);
+		}
+	}
+	iput(inode);
+
 	nr_swap_pages -= p->pages;
 	iput(p->swap_file);
 	p->swap_file = NULL;
@@ -858,7 +876,9 @@
 	unsigned int type;
 	int i,j;
 	int error;
+	struct file filp;
 
+	memset(&filp, 0, sizeof(filp));
 	if (!suser())
 		return -EPERM;
 	p = swap_info;
@@ -879,16 +899,23 @@
 	p->max = 1;
 	error = namei(specialfile,&swap_inode);
 	if (error)
-		goto bad_swap;
+		goto bad_swap_2;
 	p->swap_file = swap_inode;
 	error = -EBUSY;
 	if (swap_inode->i_count != 1)
-		goto bad_swap;
+		goto bad_swap_2;
 	error = -EINVAL;
+
 	if (S_ISBLK(swap_inode->i_mode)) {
 		p->swap_device = swap_inode->i_rdev;
+
+		filp.f_inode = swap_inode;
+		filp.f_mode = 3; /* read write */
+		error = blkdev_open(swap_inode, &filp);
 		p->swap_file = NULL;
 		iput(swap_inode);
+		if(error)
+			goto bad_swap_2;
 		error = -ENODEV;
 		if (!p->swap_device)
 			goto bad_swap;
@@ -950,6 +977,9 @@
 	printk("Adding Swap: %dk swap-space\n",j<<2);
 	return 0;
 bad_swap:
+	if(filp.f_op && filp.f_op->release)
+		filp.f_op->release(filp.f_inode,&filp);
+bad_swap_2:
 	free_page((long) p->swap_lockmap);
 	vfree(p->swap_map);
 	iput(p->swap_file);
diff -u --recursive --new-file v1.1.71/linux/modules/NET_MODULES linux/modules/NET_MODULES
--- v1.1.71/linux/modules/NET_MODULES	Tue Nov 29 18:51:29 1994
+++ linux/modules/NET_MODULES	Tue Dec  6 16:44:51 1994
@@ -1 +1 @@
-3c509.o de600.o de620.o 3c501.o eexpress.o plip.o 8390.o
+3c509.o de600.o de620.o 3c501.o apricot.o eexpress.o plip.o 8390.o
diff -u --recursive --new-file v1.1.71/linux/net/inet/igmp.c linux/net/inet/igmp.c
--- v1.1.71/linux/net/inet/igmp.c	Sat Dec  3 13:05:43 1994
+++ linux/net/inet/igmp.c	Tue Dec  6 11:23:54 1994
@@ -232,6 +232,7 @@
 		return;
 	i->users=1;
 	i->interface=dev;
+	i->multiaddr=addr;
 	i->next=dev->ip_mc_list;
 	igmp_group_added(i);
 	dev->ip_mc_list=i;
diff -u --recursive --new-file v1.1.71/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.71/linux/net/inet/ip.c	Sat Dec  3 13:05:43 1994
+++ linux/net/inet/ip.c	Tue Dec  6 13:10:49 1994
@@ -224,6 +224,10 @@
 	 *	See if we need to look up the device.
 	 */
 
+#ifdef CONFIG_INET_MULTICAST	
+	if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
+		*dev=dev_get(skb->sk->ip_mc_name);
+#endif
 	if (*dev == NULL)
 	{
 		if(skb->localroute)
@@ -316,6 +320,7 @@
 	iph->saddr    = saddr;
 	iph->protocol = type;
 	iph->ihl      = 5;
+	skb->ip_hdr   = iph;
 
 	/* Setup the IP options. */
 #ifdef Not_Yet_Avail
@@ -1591,7 +1596,28 @@
 		kfree_skb(skb, FREE_WRITE);
 		return(0);
 	}
-
+	
+#ifdef CONFIG_IP_MULTICAST	
+	if(brd==IS_MULTICAST)
+	{
+		/*
+		 *	Check it is for one of our groups
+		 */
+		struct ip_mc_list *ip_mc=dev->ip_mc_list;
+		do
+		{
+			if(ip_mc==NULL)
+			{	
+				kfree_skb(skb, FREE_WRITE);
+				return 0;
+			}
+			if(ip_mc->multiaddr==iph->daddr)
+				break;
+			ip_mc=ip_mc->next;
+		}
+		while(1);
+	}
+#endif
 	/*
 	 *	Account for the packet
 	 */
@@ -1714,6 +1740,41 @@
 	return(0);
 }
 
+/*
+ *	Loop a packet back to the sender.
+ */
+ 
+static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
+{
+	struct device *dev=&loopback_dev;
+	int len=skb->len-old_dev->hard_header_len;
+	struct sk_buff *newskb=alloc_skb(len+dev->hard_header_len, GFP_ATOMIC);
+	
+	if(newskb==NULL)
+		return;
+		
+	newskb->link3=NULL;
+	newskb->sk=NULL;
+	newskb->dev=dev;
+	newskb->saddr=skb->saddr;
+	newskb->daddr=skb->daddr;
+	newskb->raddr=skb->raddr;
+	newskb->free=1;
+	newskb->lock=0;
+	newskb->users=0;
+	newskb->pkt_type=skb->pkt_type;
+	newskb->len=len+dev->hard_header_len;
+	
+	
+	newskb->ip_hdr=(struct iphdr *)(newskb->data+ip_send(newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr));
+	memcpy(newskb->ip_hdr,skb->ip_hdr,len);
+
+	/* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */
+		
+	/*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/
+	ip_queue_xmit(NULL, dev, newskb, 1);
+}
+
 
 /*
  * Queues a packet to be sent, and starts the transmitter
@@ -1858,11 +1919,46 @@
 	/*
 	 *	If the indicated interface is up and running, send the packet.
 	 */
+	 
 	ip_statistics.IpOutRequests++;
 #ifdef CONFIG_IP_ACCT
 	ip_acct_cnt(iph,ip_acct_chain,1);
 #endif	
+	
+#ifdef CONFIG_IP_MULTICAST	
 
+	/*
+	 *	Multicasts are looped back for other local users
+	 */
+	 
+	if (MULTICAST(skb->daddr) && !(dev->flags&IFF_LOOPBACK))
+	{
+		if(sk==NULL || sk->ip_mc_loop)
+		{
+			struct ip_mc_list *imc=dev->ip_mc_list;
+			while(imc!=NULL)
+			{
+				if(imc->multiaddr==skb->daddr)
+				{
+					ip_loopback(dev,skb);
+					break;
+				}
+				imc=imc->next;
+			}
+		}
+		
+		/* Multicasts with ttl 0 must not go beyond the host */
+		
+		if(skb->ip_hdr->ttl==0)
+		{
+			kfree_skb(skb, FREE_READ);
+			return;
+		}
+	}
+#endif
+	if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))
+		ip_loopback(dev,skb);
+		
 	if (dev->flags & IFF_UP)
 	{
 		/*
diff -u --recursive --new-file v1.1.71/linux/net/inet/ip_fw.c linux/net/inet/ip_fw.c
--- v1.1.71/linux/net/inet/ip_fw.c	Sat Dec  3 13:05:43 1994
+++ linux/net/inet/ip_fw.c	Mon Dec  5 18:12:27 1994
@@ -450,10 +450,6 @@
 	restore_flags(flags);
 }
 
-#endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
-
-#ifdef CONFIG_IP_FIREWALL
-
 static int add_to_chain(struct ip_fw **chainptr, struct ip_fw *frwl)
 {
 	struct ip_fw *ftmp;
@@ -706,7 +702,7 @@
 		return(EINVAL);
 }
 
-#endif /* CONFIG_IP_FIREWALL */
+#endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
 
 struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
 {
diff -u --recursive --new-file v1.1.71/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.71/linux/net/inet/tcp.c	Mon Dec  5 18:47:57 1994
+++ linux/net/inet/tcp.c	Tue Dec  6 16:30:52 1994
@@ -262,7 +262,7 @@
 			return p;
 		p=p->next;
 	}
-	while(p!=skb_peek(&s->receive_queue));
+	while(p!=(struct sk_buff *)&s->receive_queue);
 	return NULL;
 }
 
@@ -907,7 +907,7 @@
  *	This routine builds a generic TCP header. 
  */
  
-extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
+int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
 {
 
 	/* FIXME: want to get rid of this. */
@@ -4027,22 +4027,19 @@
 
 			if (th->rst) 
 			{
-				if(sk->state!=TCP_TIME_WAIT)	/* RFC 1337 recommendation re RST in time wait */
+				tcp_statistics.TcpEstabResets++;
+				sk->zapped=1;
+				/* This means the thing should really be closed. */
+				sk->err = ECONNRESET;
+				if (sk->state == TCP_CLOSE_WAIT) 
 				{
-					tcp_statistics.TcpEstabResets++;
-					sk->zapped=1;
-					/* This means the thing should really be closed. */
-					sk->err = ECONNRESET;
-					if (sk->state == TCP_CLOSE_WAIT) 
-					{
-						sk->err = EPIPE;
-					}
-					tcp_set_state(sk,TCP_CLOSE);
-					sk->shutdown = SHUTDOWN_MASK;
-					if (!sk->dead) 
-					{
-						sk->state_change(sk);
-					}
+					sk->err = EPIPE;
+				}
+				tcp_set_state(sk,TCP_CLOSE);
+				sk->shutdown = SHUTDOWN_MASK;
+				if (!sk->dead) 
+				{
+					sk->state_change(sk);
 				}
 				kfree_skb(skb, FREE_READ);
 				release_sock(sk);
diff -u --recursive --new-file v1.1.71/linux/tools/version.c linux/tools/version.c
--- v1.1.71/linux/tools/version.c	Tue Aug  2 11:29:23 1994
+++ linux/tools/version.c	Tue Dec  6 11:11:18 1994
@@ -8,8 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/utsname.h>
-
-#include "./version.h"
+#include <linux/version.h>
 
 struct new_utsname system_utsname = {
 	UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION,
