diff -u --recursive --new-file v1.3.18/linux/CREDITS linux/CREDITS
--- v1.3.18/linux/CREDITS	Sun Aug 13 14:45:27 1995
+++ linux/CREDITS	Tue Aug 15 07:39:03 1995
@@ -708,7 +708,6 @@
 
 N: David C. Niemi
 E: niemidc@clark.net
-E: niemidc@slma.com
 D: FSSTND, The XFree86 Project
 D: DMA memory support, floppy driver
 S: 2364 Old Trail Drive
@@ -943,6 +942,10 @@
 S: Schleiermacherstrasse 12
 S: 90491 Nuernberg
 S: Germany
+
+N: Dirk Verworner
+D: Co-author of german book ``Linux-Kernel-Programmierung''
+D: Co-founder of Berlin Linux User Group
 
 N: Patrick Volkerding
 E: volkerdi@ftp.cdrom.com
diff -u --recursive --new-file v1.3.18/linux/Configure linux/Configure
--- v1.3.18/linux/Configure	Thu Dec 29 19:58:40 1994
+++ linux/Configure	Thu Jan  1 02:00:00 1970
@@ -1,147 +0,0 @@
-#! /bin/sh
-#
-# This script is used to configure the linux kernel.
-#
-# It was inspired by the challenge in the original Configure script
-# to ``do something better'', combined with the actual need to ``do
-# something better'' because the old configure script wasn't flexible
-# enough.
-#
-# Please send comments / questions / bug fixes to raymondc@microsoft.com.
-#
-# Each line in the config file is a command.
-#
-# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
-# with an empty IFS.
-
-#
-# Make sure we're really running bash.
-#
-# I would really have preferred to write this script in a language with
-# better string handling, but alas, bash is the only scripting language
-# that I can be reasonable sure everybody has on their linux machine.
-#
-[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
-
-# Disable filename globbing once and for all.
-# Enable function cacheing.
-set -f -h
-
-#
-# readln reads a line into $ans.
-#
-#	readln prompt default
-#
-function readln () {
-	if [ "$DEFAULT" = "-d" ]; then
-		echo "$1"
-		ans=$2
-	else
-		echo -n "$1"
-		IFS='@' read ans </dev/tty || exit 1
-		[ -z "$ans" ] && ans=$2
-	fi
-}
-
-#
-# comment does some pretty-printing
-#
-#	comment 'xxx'
-# 
-function comment () {
-	echo "*"; echo "* $1" ; echo "*"
-	(echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG
-	(echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H
-}
-
-#
-# bool processes a boolean argument
-#
-#	bool question define default
-#
-function bool () {
-	ans=""
-	def=$(eval echo "\${$2:-$3}")
-	while [ "$ans" != "y" -a "$ans" != "n" ]; do
-		readln "$1 ($2) [$def] " "$def"
-	done
-	if [ "$ans" = "y" ]; then
-		echo "$2=y" >>$CONFIG
-		echo "#define $2 1" >>$CONFIG_H
-	else
-		echo "# $2 is not set" >>$CONFIG
-		echo "#undef  $2" >>$CONFIG_H
-	fi
-	eval "$2=$ans"
-}
-
-#
-# int processes an integer argument
-#
-#	int question define default
-#
-function int () {
-	# Slimier hack to get bash to rescan a line.
-	ans="x"
-	def=$(eval echo "\${$2:-$3}")
-	while [ $[$ans+0] != "$ans" ]; do
-		readln "$1 ($2) [$def] " "$def"
-	done
-	echo "$2=$ans" >>$CONFIG
-	echo "#define $2 ($ans)" >>$CONFIG_H
-	eval "$2=$ans"
-}
-
-CONFIG=.tmpconfig
-CONFIG_H=.tmpconfig.h
-trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
-
-#
-# Make sure we start out with a clean slate.
-#
-echo "#" > $CONFIG
-echo "# Automatically generated make config: don't edit" >> $CONFIG
-echo "#" >> $CONFIG
-
-echo "/*" > $CONFIG_H
-echo " * Automatically generated C config: don't edit" >> $CONFIG_H
-echo " */" >> $CONFIG_H
-
-DEFAULT=""
-if [ "$1" = "-d" ] ; then
-	DEFAULT="-d"
-	shift
-fi
-
-CONFIG_IN=./config.in
-if [ "$1" != "" ] ; then
-	CONFIG_IN=$1
-fi
-
-if [ -f ./.config ] ; then
-	. ./.config
-	sed -e 's/# \(.*\) is not.*/\1=n/' <./.config >/tmp/conf.$$
-	. /tmp/conf.$$
-	rm /tmp/conf.$$
-fi
-. $CONFIG_IN
-
-if [ "$CONFIG_SOUND" = "y" ] ; then
-	$MAKE -C drivers/sound config || exit 1
-fi
-
-rm -f .config.old
-if [ -f .config ]; then
-	mv .config .config.old
-fi
-mv .tmpconfig .config
-mv .tmpconfig.h include/linux/autoconf.h
-
-echo
-echo "The linux kernel is now hopefully configured for your setup."
-echo "Check the top-level Makefile for additional configuration,"
-echo "and do a 'make dep ; make clean' if you want to be sure all"
-echo "the files are correctly re-made"
-echo
-
-exit 0
diff -u --recursive --new-file v1.3.18/linux/Makefile linux/Makefile
--- v1.3.18/linux/Makefile	Sun Aug 13 14:45:27 1995
+++ linux/Makefile	Tue Aug 15 19:33:16 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 18
+SUBLEVEL = 19
 
 ARCH = i386
 
@@ -11,10 +11,11 @@
 	  else echo sh; fi ; fi)
 TOPDIR	:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
 
+HPATH   = $(TOPDIR)/include
 AS	=as
 LD	=ld
-HOSTCC	=gcc -I$(TOPDIR)/include
-CC	=gcc -D__KERNEL__ -I$(TOPDIR)/include
+HOSTCC	=gcc -I$(HPATH)
+CC	=gcc -D__KERNEL__ -I$(HPATH)
 MAKE	=make
 CPP	=$(CC) -E
 AR	=ar
@@ -106,10 +107,6 @@
 
 include arch/$(ARCH)/Makefile
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c -o $*.o $<
 .S.s:
 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.s $<
 .S.o:
@@ -134,10 +131,10 @@
 	( cd include ; ln -sf asm-$(ARCH) asm)
 
 oldconfig: symlinks
-	$(CONFIG_SHELL) Configure -d arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
 
 config: symlinks
-	$(CONFIG_SHELL) Configure arch/$(ARCH)/config.in
+	$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
 
 linuxsubdirs: dummy
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
@@ -152,22 +149,25 @@
 	fi
 
 include/linux/version.h: $(CONFIGURATION) Makefile newversion
-	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > include/linux/version.h
+	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver
 	@if [ -f .name ]; then \
 	   echo \#define UTS_VERSION \"\#`cat .version`-`cat .name` `date`\"; \
 	 else \
 	   echo \#define UTS_VERSION \"\#`cat .version` `date`\";  \
-	 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
+	 fi >> .ver
+	@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
+	@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> .ver
+	@echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> .ver
 	@if [ -x /bin/dnsdomainname ]; then \
 	   echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \
-	 else \
+	 elif [ -x /bin/domainname ]; then \
 	   echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"; \
-	 fi >> include/linux/version.h
-	@echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> include/linux/version.h
-	@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> include/linux/version.h
+	 else \
+	   echo \#define LINUX_COMPILE_DOMAIN ; \
+	 fi >> .ver
+	@echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> .ver
+	@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
+	if [ ! -f $@ ]; then mv .ver $@; fi
 
 init/version.o: init/version.c include/linux/version.h
 	$(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c
@@ -236,10 +236,11 @@
 	rm -f include/linux/autoconf.h include/linux/version.h
 	rm -f drivers/sound/local.h
 	rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
-	rm -f drivers/char/uni_hash_tbl.h drivers/char/conmakehash
+	rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash
 	rm -f .version .config* config.in config.old
 	rm -f include/asm
 	rm -f .depend `find . -name .depend -print`
+	rm -f .hdepend
 	rm -f $(TOPDIR)/include/linux/modversions.h
 	rm -f $(TOPDIR)/include/linux/modules/*
 
@@ -251,10 +252,11 @@
 	cd .. && tar cf - linux | gzip -9 > backup.gz
 	sync
 
-depend dep: archdep
+#depend dep: .hdepend
+depend dep: archdep .hdepend
 	touch include/linux/version.h
-	for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .tmpdepend
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
+	awk -f scripts/depend.awk init/*.c > .tmpdepend
+	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
 	rm -f include/linux/version.h
 	mv .tmpdepend .depend
 ifdef CONFIG_MODVERSIONS
@@ -275,7 +277,8 @@
 	@echo
 	exit 1
 
-dummy: ..$(CONFIGURATION)
+#dummy: ..$(CONFIGURATION)
+dummy:
 
 else
 
@@ -284,3 +287,12 @@
 endif
 
 include Rules.make
+
+#
+# This generates dependencies for the .h files.
+#
+
+.hdepend: dummy
+	rm -f $@
+	awk -f scripts/depend.awk `find $(HPATH) -name \*.h -print` > .$@
+	mv .$@ $@
diff -u --recursive --new-file v1.3.18/linux/Rules.make linux/Rules.make
--- v1.3.18/linux/Rules.make	Thu Jul 13 16:20:19 1995
+++ linux/Rules.make	Tue Aug 15 15:07:01 1995
@@ -3,10 +3,105 @@
 #
 
 #
+# False targets.
+#
+.PHONY: dummy
+
+#
+# Special variables which should not be exported
+#
+unexport EXTRA_ASFLAGS
+unexport EXTRA_CFLAGS
+unexport EXTRA_LDFLAGS
+unexport EXTRA_ARFLAGS
+unexport SUBDIRS
+unexport SUB_DIRS
+unexport ALL_SUB_DIRS
+unexport MOD_SUB_DIRS
+unexport O_TARGET
+unexport O_OBJS
+unexport L_OBJS
+unexport M_OBJS
+unexport MOD_LIST_NAME
+
+#
+# Get things started.
+#
+first_rule: sub_dirs $(O_TARGET) $(L_TARGET)
+
+#
 # Common rules
 #
 .c.s:
-	$(CC) $(CFLAGS) -S $< -o $@
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o $@
+
+.c.o:
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+.s.o:
+	$(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef O_TARGET
+$(O_TARGET): $(O_OBJS)
+ifdef O_OBJS
+	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(O_OBJS)
+else
+	$(AR) rcs $@
+endif
+endif
+
+#
+# Rule to compile a set of .o files into one .a file
+#
+ifdef L_TARGET
+$(L_TARGET): $(L_OBJS)
+	rm -f $@
+	$(AR) $(EXTRA_ARFLAGS) rcs $@ $(L_OBJS)
+endif
+
+#
+# This make dependencies quickly
+#
+fastdep: dummy
+	if [ -n "$(wildcard *.[chS])" ]; then \
+	awk -f $(TOPDIR)/scripts/depend.awk *.[chS] > .depend; fi
+	set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done
+
+#
+# A rule to make subdirectories
+#
+sub_dirs: dummy
+ifdef SUB_DIRS
+	set -e; for i in $(SUB_DIRS); do $(MAKE) -C $$i; done
+endif
+
+#
+# A rule to make modules
+#
+ifdef M_OBJS
+PDWN=$(shell /bin/sh $(TOPDIR)/scripts/pathdown.sh)
+endif
+modules: $(M_OBJS) dummy
+ifdef MOD_SUB_DIRS
+	set -e; for i in $(MOD_SUB_DIRS); do $(MAKE) -C $$i modules; done
+endif
+ifneq "$(strip $(MOD_LIST_NAME))" ""
+ifndef M_OBJS # Hack for fs subdirectories
+	rm -f $$TOPDIR/modules/$(MOD_LIST_NAME)
+	for i in $(MOD_SUB_DIRS); do \
+	    echo `basename $$i`.o >> $$TOPDIR/modules/$(MOD_LIST_NAME); done
+else
+	echo $(M_OBJS) > $$TOPDIR/modules/$(MOD_LIST_NAME)
+endif
+endif
+ifdef M_OBJS
+	echo $(PDWN)
+	cd $$TOPDIR/modules; for i in $(M_OBJS); do \
+	    ln -sf ../$(PDWN)/$$i .; done
+endif
 
 #
 # A rule to do nothing
@@ -14,8 +109,17 @@
 dummy:
 
 #
-# include a dependency file if one exists
+# This is useful for testing
+#
+script:
+	$(SCRIPT)
+#
+# include dependency files they exist
 #
 ifeq (.depend,$(wildcard .depend))
 include .depend
+endif
+
+ifeq ($(TOPDIR)/.hdepend,$(wildcard $(TOPDIR)/.hdepend))
+include $(TOPDIR)/.hdepend
 endif
diff -u --recursive --new-file v1.3.18/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v1.3.18/linux/arch/alpha/boot/Makefile	Tue Jul 11 10:02:47 1995
+++ linux/arch/alpha/boot/Makefile	Tue Aug 15 15:07:01 1995
@@ -8,10 +8,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c -o $*.o $<
 .S.s:
 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
 .S.o:
diff -u --recursive --new-file v1.3.18/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v1.3.18/linux/arch/alpha/kernel/Makefile	Thu Jul 13 16:20:19 1995
+++ linux/arch/alpha/kernel/Makefile	Tue Aug 15 15:07:01 1995
@@ -7,10 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
 .S.s:
 	$(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
 .S.o:
diff -u --recursive --new-file v1.3.18/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile
--- v1.3.18/linux/arch/alpha/lib/Makefile	Tue Jul 18 16:28:56 1995
+++ linux/arch/alpha/lib/Makefile	Tue Aug 15 15:07:02 1995
@@ -2,11 +2,6 @@
 # Makefile for alpha-specific library files..
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 OBJS  = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \
 	checksum.o strlen.o
 
diff -u --recursive --new-file v1.3.18/linux/arch/alpha/mm/Makefile linux/arch/alpha/mm/Makefile
--- v1.3.18/linux/arch/alpha/mm/Makefile	Tue Jul 11 10:02:47 1995
+++ linux/arch/alpha/mm/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,19 +7,9 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
 OBJS	= init.o fault.o
 
 mm.o: $(OBJS)
 	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-	$(CPP) -M *.c > .depend
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v1.3.18/linux/arch/i386/boot/compressed/Makefile	Tue Jul 11 10:02:47 1995
+++ linux/arch/i386/boot/compressed/Makefile	Tue Aug 15 15:07:02 1995
@@ -17,11 +17,6 @@
 INPUT_LEN=input_len
 endif
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 all: vmlinux
 
 vmlinux: piggy.o $(OBJECTS)
diff -u --recursive --new-file v1.3.18/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.18/linux/arch/i386/config.in	Tue Aug  8 12:31:32 1995
+++ linux/arch/i386/config.in	Sun Aug 13 19:39:38 1995
@@ -72,7 +72,7 @@
 
 comment 'SCSI support'
 
-bool 'SCSI support?' CONFIG_SCSI y
+bool 'SCSI support' CONFIG_SCSI y
 
 if [ "$CONFIG_SCSI" = "n" ]; then
 
@@ -122,7 +122,7 @@
 
 comment 'Network device support'
 
-bool 'Network device support?' CONFIG_NETDEVICES y
+bool 'Network device support' CONFIG_NETDEVICES y
 if [ "$CONFIG_NETDEVICES" = "n" ]; then
 
 comment 'Skipping network driver configuration options...'
diff -u --recursive --new-file v1.3.18/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v1.3.18/linux/arch/i386/kernel/Makefile	Tue Jul 11 10:02:47 1995
+++ linux/arch/i386/kernel/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,33 +7,21 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
 #.S.s:
 #	$(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
-OBJS  = process.o signal.o entry.o traps.o irq.o vm86.o bios32.o ptrace.o \
-	ioport.o ldt.o setup.o sys_i386.o
-
 all: kernel.o head.o
+O_TARGET := kernel.o
+O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o bios32.o \
+            ptrace.o ioport.o ldt.o setup.o sys_i386.o
+
 
 #head.o: head.s
 
 head.o: head.S $(TOPDIR)/include/linux/tasks.h
 	$(CC) -D__ASSEMBLY__ -traditional -c $*.S -o $*.o
 #	$(CPP) -traditional -o $*.s $<
-
-kernel.o: $(OBJS)
-	$(LD) -r -o kernel.o $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules:
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v1.3.18/linux/arch/i386/lib/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/i386/lib/Makefile	Tue Aug 15 15:07:02 1995
@@ -2,19 +2,7 @@
 # Makefile for i386-specific library files..
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-OBJS  = checksum.o
-
-lib.a: $(OBJS)
-	$(AR) rcs lib.a $(OBJS)
-	sync
-
-dep:
-
-modules:
+L_TARGET = lib.a
+L_OBJS  = checksum.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/i386/math-emu/Makefile linux/arch/i386/math-emu/Makefile
--- v1.3.18/linux/arch/i386/math-emu/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/i386/math-emu/Makefile	Tue Aug 15 15:07:02 1995
@@ -2,21 +2,17 @@
 #               Makefile for wm-FPU-emu
 #
 
+L_TARGET := math.a
+
 #DEBUG	= -DDEBUGGING
 DEBUG	=
 PARANOID = -DPARANOID
-CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
-
-.c.o:
-	$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
+CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
 
 .S.o:
 	$(CC) -D__ASSEMBLY__ $(PARANOID) -c $<
 
-.s.o:
-	$(CC) -c $<
-
-OBJS =	fpu_entry.o div_small.o errors.o \
+L_OBJS =fpu_entry.o div_small.o errors.o \
 	fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
 	load_store.o get_address.o \
 	poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
@@ -28,18 +24,7 @@
 	div_Xsig.o polynom_Xsig.o round_Xsig.o \
 	shr_Xsig.o mul_Xsig.o
 
-math.a: $(OBJS)
-	rm -f math.a
-	$(AR) rcs math.a $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M *.c > .depend
-	$(CPP) -D__ASSEMBLY__ -M *.S >> .depend
+include $(TOPDIR)/Rules.make
 
 proto:
 	cproto -e -DMAKING_PROTO *.c >fpu_proto.h
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile
--- v1.3.18/linux/arch/i386/mm/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/i386/mm/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,19 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	= init.o fault.o
-
-mm.o: $(OBJS)
-	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := mm.o
+O_OBJS	 := init.o fault.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/mips/Makefile linux/arch/mips/Makefile
--- v1.3.18/linux/arch/mips/Makefile	Wed Jan 25 08:54:22 1995
+++ linux/arch/mips/Makefile	Tue Aug 15 15:07:02 1995
@@ -15,7 +15,7 @@
 #
 
 AS		= mips-linux-as
-ASFLAGS		= -mips3 -mcpu=r4000
+#ASFLAGS		= -mips3 -mcpu=r4000
 LD		= mips-linux-ld
 LINKFLAGS	= -Ttext 0xa0000000
 #HOSTCC		= gcc
diff -u --recursive --new-file v1.3.18/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile
--- v1.3.18/linux/arch/mips/kernel/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/mips/kernel/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,15 +7,12 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.s.o:
-	$(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
 .S.s:
 	$(CPP) $(CFLAGS) -D__ASSEMBLY__ -traditional $< -o $*.s
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
+EXTRA_ASFLAGS = -mips3 -mcpu=r4000
 OBJS  = process.o signal.o entry.o traps.o irq.o ptrace.o cache.o resume.o \
 	ioport.o setup.o bios32.o tynedma.o
 
@@ -52,10 +49,5 @@
 kernel.o: $(OBJS)
 	$(LD) -r -o kernel.o $(OBJS)
 	sync
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules:
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- v1.3.18/linux/arch/mips/mm/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/mips/mm/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,19 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	= fault.o init.o
-
-mm.o: $(OBJS)
-	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := mm.o
+O_OBJS	 := fault.o init.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile
--- v1.3.18/linux/arch/sparc/boot/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/sparc/boot/Makefile	Tue Aug 15 15:07:02 1995
@@ -5,10 +5,6 @@
 OBJS	=bare.o init_me.o ../kernel/promops.o ../lib/lib.a
 BOOTLINKFLAGS = -N -Ttext 0x200000 -e _first_adr_in_text
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c -o $*.o $<
 .S.s:
 	$(CC) -D__ASSEMBLY__ -D__KERNEL__ -ansi -E -o $*.o $<
 .S.o:
diff -u --recursive --new-file v1.3.18/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v1.3.18/linux/arch/sparc/kernel/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/sparc/kernel/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,10 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
 .S.s:
 	$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
 .S.o:
diff -u --recursive --new-file v1.3.18/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v1.3.18/linux/arch/sparc/lib/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/sparc/lib/Makefile	Tue Aug 15 15:07:02 1995
@@ -4,11 +4,6 @@
 
 CFLAGS := $(CFLAGS) -ansi
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o
 
 lib.a: $(OBJS)
diff -u --recursive --new-file v1.3.18/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v1.3.18/linux/arch/sparc/mm/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/sparc/mm/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,19 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	= fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o
-
-mm.o: $(OBJS)
-	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := mm.o
+O_OBJS   := fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/arch/sparc/prom/Makefile linux/arch/sparc/prom/Makefile
--- v1.3.18/linux/arch/sparc/prom/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/arch/sparc/prom/Makefile	Tue Aug 15 15:07:02 1995
@@ -8,9 +8,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 OBJS  = bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
         palloc.o ranges.o segment.o tree.o console.o printf.o
 
diff -u --recursive --new-file v1.3.18/linux/drivers/Makefile linux/drivers/Makefile
--- v1.3.18/linux/drivers/Makefile	Tue Jul 18 16:28:56 1995
+++ linux/drivers/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,36 +7,24 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.S.s:
-	$(CPP) -traditional $< -o $*.s
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-SUBDIRS	= block char net #streams
+SUB_DIRS     := block char net #streams
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sound
 
 ifdef CONFIG_PCI
-SUBDIRS := $(SUBDIRS) pci
+SUB_DIRS += pci
 endif
 
 ifdef CONFIG_SCSI
-SUBDIRS := $(SUBDIRS) scsi
+SUB_DIRS += scsi
+MOD_SUB_DIRS += scsi
 endif
 
+# I think this should have an else clause for modules, but the original
+# makefile did not, so I am not adding it.
+# -jln 12 Aug 1995
 ifdef CONFIG_SOUND
-SUBDIRS := $(SUBDIRS) sound
+SUB_DIRS += sound
 endif
-
-all: driversubdirs
-
-driversubdirs: dummy
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
-
-modules: dummy
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i modules; done
-
-dep:
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/drivers/block/MAKEDEV.ide linux/drivers/block/MAKEDEV.ide
--- v1.3.18/linux/drivers/block/MAKEDEV.ide	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/MAKEDEV.ide	Tue Aug 15 15:17:37 1995
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# This script creates the proper /dev/ entries for IDE devices
+#
+makedev () {
+	rm -f /dev/$1
+	echo mknod /dev/$1 b $2 $3
+	     mknod /dev/$1 b $2 $3
+	chown root:disk /dev/$1
+	chmod 660 /dev/$1
+}
+
+makedevs () {
+	rm -f /dev/$1*
+	makedev $1 $2 $3
+	for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+	do
+		makedev $1$part $2 `expr $3 + $part`
+	done
+}
+
+makedevs hda  3 0
+makedevs hdb  3 64
+makedevs hdc 22 0
+makedevs hdd 22 64
+makedevs hde 33 0
+makedevs hdf 33 64
+makedevs hdg 34 0
+makedevs hdh 34 64
diff -u --recursive --new-file v1.3.18/linux/drivers/block/MAKEDEV.ide1 linux/drivers/block/MAKEDEV.ide1
--- v1.3.18/linux/drivers/block/MAKEDEV.ide1	Sun Jan  1 16:28:19 1995
+++ linux/drivers/block/MAKEDEV.ide1	Thu Jan  1 02:00:00 1970
@@ -1,24 +0,0 @@
-#!/bin/sh
-makedev () {
-        rm -f /dev/$1
-        echo mknod /dev/$1 $2 $3 $4 &&
-             mknod /dev/$1 $2 $3 $4 &&
-        chown $5 /dev/$1 &&
-        chmod $6 /dev/$1
-}
-
-# Create /dev/hdc*
-makedev hdc b 22 0 root:$disk 660
-for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-do
-	makedev hdc$part b 22 `expr 0 + $part` root:$disk 660
-done
-echo " "
-
-# Create /dev/hdd*
-makedev hdd b 22 64 root:$disk 660
-for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-do
-	makedev hdd$part b 22 `expr 64 + $part` root:$disk 660
-done
-
diff -u --recursive --new-file v1.3.18/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.18/linux/drivers/block/Makefile	Wed Aug  9 14:55:38 1995
+++ linux/drivers/block/Makefile	Tue Aug 15 15:13:57 1995
@@ -9,145 +9,109 @@
 # parent makefile.
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 #
 # Note : at this point, these files are compiled on all systems. 
 # In the future, some of these should be built conditionally.
 #
 
-OBJS := ll_rw_blk.o ramdisk.o genhd.o 
-SRCS := ll_rw_blk.c ramdisk.c genhd.c 
-BLOCK_MODULE_OBJS =
+
+L_TARGET := block.a
+L_OBJS   := ll_rw_blk.o ramdisk.o genhd.o 
+M_OBJS   :=
+MOD_LIST_NAME := BLOCK_MODULES
 
 ifdef CONFIG_BLK_DEV_FD
-OBJS := $(OBJS) floppy.o
-SRCS := $(SRCS) floppy.c
+L_OBJS += floppy.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) floppy.o
+M_OBJS += floppy.o
 endif
 
 ifdef CONFIG_AZTCD
-OBJS := $(OBJS) aztcd.o
-SRCS := $(SRCS) aztcd.c
+L_OBJS += aztcd.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o
+M_OBJS += aztcd.o
 endif #CONFIG_AZTCD
 
 ifdef CONFIG_CDU31A
-OBJS := $(OBJS) cdu31a.o
-SRCS := $(SRCS) cdu31a.c
+L_OBJS += cdu31a.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) cdu31a.o
+M_OBJS += cdu31a.o
 endif #CONFIG_CDU31A
 
 ifdef CONFIG_MCD
-OBJS := $(OBJS) mcd.o
-SRCS := $(SRCS) mcd.c
+L_OBJS += mcd.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) mcd.o
+M_OBJS += mcd.o
 endif #CONFIG_MCD
 
 ifdef CONFIG_MCDX
-OBJS := $(OBJS) mcdx.o
-SRCS := $(SRCS) mcdx.c
+L_OBJS += mcdx.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) mcdx.o
+M_OBJS += mcdx.o
 endif #CONFIG_MCDX
 
 ifdef CONFIG_SBPCD
-OBJS := $(OBJS) sbpcd.o
-SRCS := $(SRCS) sbpcd.c
+L_OBJS += sbpcd.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sbpcd.o
+M_OBJS += sbpcd.o
 endif #CONFIG_SBPCD
 
 ifdef CONFIG_SBPCD2
-OBJS := $(OBJS) sbpcd2.o
-SRCS := $(SRCS) sbpcd2.c
+L_OBJS += sbpcd2.o
 endif #CONFIG_SBPCD2
 
 ifdef CONFIG_SBPCD3
-OBJS := $(OBJS) sbpcd3.o
-SRCS := $(SRCS) sbpcd3.c
+L_OBJS += sbpcd3.o
 endif #CONFIG_SBPCD3
 
 ifdef CONFIG_SBPCD4
-OBJS := $(OBJS) sbpcd4.o
-SRCS := $(SRCS) sbpcd4.c
+L_OBJS += sbpcd4.o
 endif #CONFIG_SBPCD4
 
 ifdef CONFIG_CDU535
-OBJS := $(OBJS) sonycd535.o
-SRCS := $(SRCS) sonycd535.c
+L_OBJS += sonycd535.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sonycd535.o
+M_OBJS += sonycd535.o
 endif #CONFIG_CDU535
 
 ifdef CONFIG_GSCD
-OBJS := $(OBJS) gscd.o
-SRCS := $(SRCS) gscd.c
+L_OBJS += gscd.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) gscd.o
+M_OBJS += gscd.o
 endif #CONFIG_GSCD
 
 ifdef CONFIG_CM206
-OBJS := $(OBJS) cm206.o
-SRCS := $(SRCS) cm206.c
+L_OBJS += cm206.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) cm206.o
+M_OBJS += cm206.o
 endif #CONFIG_CM206
 
 ifdef CONFIG_OPTCD
-OBJS := $(OBJS) optcd.o
-SRCS := $(SRCS) optcd.c
+L_OBJS += optcd.o
 else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) optcd.o
+M_OBJS += optcd.o
 endif #CONFIG_OPTCD
 
 ifdef CONFIG_SJCD
-OBJS := $(OBJS) sjcd.o
-SRCS := $(SRCS) sjcd.c
+L_OBJS += sjcd.o
 #else
-#BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sjcd.o
+#M_OBJS += sjcd.o
 endif #CONFIG_SJCD
 
 ifdef CONFIG_BLK_DEV_HD
-OBJS := $(OBJS) hd.o
-SRCS := $(SRCS) hd.c
+L_OBJS += hd.o
 endif
 
 ifdef CONFIG_BLK_DEV_IDE
-OBJS := ide.o $(OBJS)
-SRCS := ide.c $(SRCS)
+L_OBJS += ide.o
 endif
 
-ifdef CONFIG_BLK_DEV_XD
-OBJS := $(OBJS) xd.o
-SRCS := $(SRCS) xd.c
+ifdef CONFIG_BLK_DEV_IDECD
+L_OBJS += ide-cd.o
 endif
 
-all: block.a
-
-block.a: $(OBJS)
-	rm -f block.a
-	$(AR) rcs block.a $(OBJS)
-	sync
-
-ifdef BLOCK_MODULE_OBJS
-dep:
-	$(CPP) -M $(SRCS) > .depend
-	$(CPP) -M -DMODULE $(BLOCK_MODULE_OBJS:.o=.c) >> .depend
-else
-dep:
-	$(CPP) -M $(SRCS) > .depend
+ifdef CONFIG_BLK_DEV_XD
+L_OBJS += xd.o
 endif
-
-modules: $(BLOCK_MODULE_OBJS)
-	echo $(BLOCK_MODULE_OBJS) > ../../modules/BLOCK_MODULES
-	(cd ../../modules;for i in $(BLOCK_MODULE_OBJS); do ln -sf ../drivers/block/$$i .; done)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.3.18/linux/drivers/block/README.ide	Mon Jul 31 15:58:59 1995
+++ linux/drivers/block/README.ide	Sun Aug 13 20:19:11 1995
@@ -7,12 +7,13 @@
 
 Major features of ide.c & ide-cd.c:
 
-	- support for up to two IDE interfaces on one or two IRQs
-	- support for any mix of up to four disk and/or cdrom drives
+NEW!	- support for up to *four* IDE interfaces on one or more IRQs
+NEW!	- support for any mix of up to *eight* disk and/or cdrom drives
 	- support for reading IDE ATAPI cdrom drives (NEC,MITSUMI,VERTOS,SONY)
 	- support for audio functions
 	- auto-detection of interfaces, drives, IRQs, and disk geometries
-	  -- "single" drives should be jumpered as "master", not "slave"
+		- "single" drives should be jumpered as "master", not "slave"
+NEW!		  (both are now probed for)
 	- support for BIOSs which report "more than 16 heads" on disk drives
 	- uses LBA (slightly faster) on disk drives which support it
 	- support for lots of fancy (E)IDE drive functions with hdparm utility
@@ -20,41 +21,58 @@
 	- support for IDE multiple (block) mode (same as hd.c)
 	- support for interrupt unmasking during I/O (better than hd.c)
 	- improved handshaking and error detection/recovery
-	- can co-exist with hd.c to control only the secondary interface
+	- can co-exist with hd.c controlling the first interface
 	- support for reliable operation of buggy CMD-640 interfaces
-		- use kernel command line option:   hda=serialize
+NEW!		- use kernel command line option:   ide1=serialize
 	- experimental support for DTC-2278D interfaces
-		- use kernel command line option:  hda=dtc2278
+NEW!		- use kernel command line option:   ide1=dtc2278
 	- run-time selectable 32bit interface support (using hdparm-2.3)
 
 NEW!	- support for drives with a stuck WRERR_STAT bit
-NEW!	- support for removeable devices
+NEW!	- support for removeable devices, including door lock/unlock
 
 NEW!	- transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
+NEW!		- should work for for EZ-Drive disks as well (not verified)
 		- works with Linux fdisk, LILO, loadlin, bootln, etc..
+NEW!	- ide-cd.c now compiles separate from ide.c
+
+For a list of work underway, see the comments near the top of ide.c and ide-cd.c
 
 ***
 
 IMPORTANT NOTICE:  "CMD" EIDE Interfaces will not (by default) work *reliably*
 when drives are attached to the second interface.  To "fix" this, supply the
-special kernel "command line" parameter to LILO:    hda=serialize
+special kernel "command line" parameter to LILO:    ide1=serialize
 Failure to do so can cause severe data corruption!
 
 ***
 
-To access devices on the second interface, device entries must first be
+To access devices on the 2nd/3rd/4th interfaces, device entries must first be
 created in /dev for them.  To create such entries, simply run the included
-shell script:   MAKEDEV.ide1
+shell script:   MAKEDEV.ide
 
-Apparently the early releases of Slackware 2.2 have incorrect entries
-in /dev for hdc* and hdd* -- this can also be corrected by running MAKEDEV.ide1
+Apparently many releases of Slackware 2.2/2.3 have incorrect entries
+in /dev for hdc* and hdd* -- this can also be corrected by running MAKEDEV.ide
 
 ide.c automatically probes for the primary and secondary interfaces,
 for the drives/geometries attached to those interfaces, and for the
 IRQ numbers being used by the interfaces (normally IRQ14 & IRQ15).
 
-The primary and secondary interfaces may share a single IRQ if necessary,
-at a slight performance penalty, whether on separate cards or a single VLB card.
+Interfaces beyond the first two are not normally probed for, but may be
+specified using kernel "command line" options.  For example,
+
+	ide3=0x1e8,0x3f0,11	/* ioports 0x1e8-0x1ef,0x3f0, irq 11 */
+
+Normally the irq number need not be specified, as ide.c will probe for it:
+
+	ide3=0x1e8,0x3f0	/* ioports 0x1e8-0x1ef,0x3f0 */
+
+Any number of interfaces may share a single IRQ if necessary, at a slight
+performance penalty, whether on separate cards or a single VLB card.
+The IDE driver automatically detects and handles this.  However, this may
+or may not be harmful to your hardware.. two or more cards driving the same IRQ
+can potentially burn each other's bus driver, though in practice this
+seldom occurs.  Be careful, and if in doubt, don't do it!
 
 Drives are normally found by auto-probing and/or examining the CMOS/BIOS data.
 For really weird situations, the apparent (fdisk) geometry can also be specified
@@ -63,16 +81,14 @@
 	hdx=cyls,heads,sects,wpcom,irq
 or	hdx=cdrom
 
-where hdx can be any of {hda,hdb,hdc,hdd}, or simply hd, for the "next" drive
-in sequence.  Only the first three parameters are required (cyls,heads,sects),
-and wpcom is ignored for IDE drives.  For example:
+where hdx can be any of hda through hdh, Three values are required
+(cyls,heads,sects).  For example:
 
-	hdc=1050,32,64 hdd=cdrom
+	hdc=1050,32,64  hdd=cdrom
 
-If an irq number is given, it will apply to both drives on the same interface,
 either {hda,hdb} or {hdc,hdd}.  The results of successful auto-probing may
 override the physical geometry/irq specified, though the "original" geometry
-is retained as the "logical" geometry for partitioning purposes (fdisk).
+may be retained as the "logical" geometry for partitioning purposes (fdisk).
 
 If the auto-probing during boot time confuses a drive (ie. the drive works
 with hd.c but not with ide.c), then an command line option may be specified
@@ -85,18 +101,22 @@
 	hdc=noprobe
 
 Note that when only one IDE device is attached to an interface,
-it must be jumpered as "single" or "master", *not* "slave".
-Many folks have had "trouble" with cdroms because of this requirement
-of the ATA (IDE) standard.
+it should be jumpered as "single" or "master", *not* "slave".
+Many folks have had "trouble" with cdroms because of this requirement,
+so ide.c now probes for both units, though success is more likely
+when the drive is jumpered correctly.
 
-Courtesy of Scott Snyder, the driver now supports ATAPI cdrom drives
+Courtesy of Scott Snyder, the driver supports ATAPI cdrom drives
 such as the NEC-260 and the new MITSUMI triple/quad speed drives.
-Such drives will be identified at boot time, as hda,hdb,hdc or hdd,
-just like a harddisk.
+Such drives will be identified at boot time, just like a harddisk.
 
 If for some reason your cdrom drive is *not* found at boot time, you can force
 the probe to look harder by supplying a kernel command line parameter
-via LILO, such as:  hdc=cdrom
+via LILO, such as:
+
+	hdc=cdrom	/* hdc = "master" on second interface */
+or
+	hdd=cdrom	/* hdd = "slave" on second interface */
 
 For example, a GW2000 system might have a harddrive on the primary
 interface (/dev/hda) and an IDE cdrom drive on the secondary interface
@@ -106,11 +126,18 @@
 	mkdir /cd
 	mount /dev/cdrom /cd -t iso9660 -o ro
 
+The kernel is able to execute binaries directly off of the cdrom,
+provided it is mounted with the default block size of 1024 (as above).
+
 Please pass on any feedback on the cdrom stuff to the author & maintainer,
 Scott Snyder (snyder@fnald0.fnal.gov).
 
-The kernel is now be able to execute binaries directly off of the cdrom,
-provided it is mounted with the default block size of 1024.
+Note that if BOTH hd.c and ide.c are configured into the kernel,
+hd.c will normally be allowed to control the primary IDE interface.
+This is useful for older hardware that may be incompatible with ide.c,
+and still allows newer hardware to run on the 2nd/3rd/4th IDE ports
+under control of ide.c.   To have ide.c also "take over" the primary
+IDE port in this situation, use the "command line" parameter:  ide0=0x1f0
 
 The hdparm.c program for controlling various IDE features is now packaged
 separately.  Look for it on popular linux FTP sites.
@@ -119,6 +146,34 @@
 snyder@fnald0.fnal.gov
 ================================================================================
 
+Summary of ide driver parameters for kernel "command line":
+----------------------------------------------------------
+
+  "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
+  "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
+ 
+  "hdx=noprobe"		: drive may be present, but do not probe for it
+  "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
+  "hdx=cdrom"		: drive is present, and is a cdrom drive
+  "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+
+  "idex=noprobe"	: do not attempt to access/use this interface
+  "idex=base"		: probe for an interface at the addr specified,
+                                where "base" is usually 0x1f0 or 0x170
+                                and "ctl" is assumed to be "base"+0x206
+				and "irq" will be probed for
+  "idex=base,ctl"	: specify both base and ctl
+  "idex=base,ctl,irq"	: specify base, ctl, and irq number
+
+The following two are valid ONLY on ide0 or ide1:
+
+  "idex=dtc2278"	: look for and try to initialize a dtc2278
+  "idex=serialize"	: do not overlap operations on ide0 and ide1.
+
+Everything else is rejected with a "BAD OPTION" message.
+
+================================================================================
+
 Some Terminology
 ----------------
 IDE = Integrated Drive Electronics, meaning that each drive has a built-in
@@ -262,7 +317,7 @@
 Note that when creating partitions that span beyond cylinder 1024,
 Linux fdisk will complain about "Partition X has different physical/logical
 endings" and emit messages such as "This is larger than 1024, and may cause
-problems with some software".   Ignore them for linux partitions.  The "some
+problems with some software".   Ignore this for linux partitions.  The "some
 software" refers to DOS, the BIOS, and LILO, as described previously.
 
 Western Digital ships a "DiskManager 6.03" diskette with all of their big
@@ -272,3 +327,35 @@
 with Linux 1.3.x in most cases.  Let me know if you still have trouble.
 
 mlord@bnr.ca
+
+================================================================================
+EIDE card compatibility reports:
+================================================================================
+
+comp.os.linux.hardware #18483 (7 + 0 more)                            (1)--[1]
+From: test <a>
+[1] Re: Promise EIDEMAX
+Date: Fri Aug 11 23:17:39 EDT 1995
+Organization: Technical University of Brno, Czech Republic
+Lines: 14
+Mime-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+X-Mailer: Mozilla 1.1N (X11; I; Linux 1.2.11 i486)
+To: rmorton@VNET.IBM.COM
+X-URL: news:19950806.154256.872@almaden.ibm.com
+
+I have a Promise <sth>2300 board with DX2/80 w/ 32Mb ram.
+
+This one is a bit schizophrenic - half (2 drives) at VLBUS and
+the rest 2 on ISA.
+
+Works quite well, Linux works with it (4 HDDs), it
+also supports its dual irq mechanism (14 & 15).
+In the documentation I've found that there are certain things made about this
+controller(in kernel).
+My current kernel is 1.2.11 and Promise should be supported in all 1.2.xx
+kernels I think.
+
+   Vladimir Myslik
+
diff -u --recursive --new-file v1.3.18/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.3.18/linux/drivers/block/blk.h	Tue Aug  8 12:31:33 1995
+++ linux/drivers/block/blk.h	Tue Aug 15 20:10:23 1995
@@ -332,12 +332,17 @@
 #endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) && !defined(IDE_DRIVER) */
 
 /* end_request() - SCSI devices have their own version */
+/*               - IDE drivers have their own copy too */
 
 #if ! SCSI_MAJOR(MAJOR_NR)
 
+#ifdef _IDE_CD_C	/* ide-cd.c uses copy from ide.c */
+void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
+#else
+
 #ifdef IDE_DRIVER
-static void end_request(byte uptodate, byte hwif) {
-	struct request *req = ide_cur_rq[HWIF];
+void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) {
+	struct request *req = hwgroup->rq;
 #else
 static void end_request(int uptodate) {
 	struct request *req = CURRENT;
@@ -371,7 +376,7 @@
 		}
 	}
 #ifdef IDE_DRIVER
-	ide_cur_rq[HWIF] = NULL;
+	hwgroup->rq = NULL;
 #else
 	DEVICE_OFF(req->dev);
 	CURRENT = req->next;
@@ -381,6 +386,7 @@
 	req->dev = -1;
 	wake_up(&wait_for_request);
 }
+#endif /* ndef _IDE_CD_C */
 #endif /* ! SCSI_MAJOR(MAJOR_NR) */
 
 #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */
diff -u --recursive --new-file v1.3.18/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.18/linux/drivers/block/genhd.c	Tue Aug  8 12:31:33 1995
+++ linux/drivers/block/genhd.c	Sun Aug 13 20:19:11 1995
@@ -17,11 +17,12 @@
  *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/config.h>
+#include <linux/string.h>
 
 struct gendisk *gendisk_head = NULL;
 
@@ -30,18 +31,37 @@
 extern void rd_load(void);
 extern int ramdisk_size;
 
-static char minor_name (struct gendisk *hd, int minor)
+static void print_minor_name (struct gendisk *hd, int minor)
 {
-	char base_name = (hd->major == IDE1_MAJOR) ? 'c' : 'a';
-	return base_name + (minor >> hd->minor_shift);
+	unsigned int unit = minor >> hd->minor_shift;
+	unsigned int part = minor & ((1 << hd->minor_shift) - 1);
+
+#ifdef CONFIG_BLK_DEV_IDE
+	/*
+	 * IDE devices use multiple major numbers, but the drives
+	 * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
+	 * This requires some creative handling here to find the
+	 * correct name to use, with some help from ide.c
+	 */
+	if (!strcmp(hd->major_name,"ide")) {
+		char name[16];		/* more than large enough */
+		strcpy(name, hd->real_devices); /* courtesy ide.c */
+		name[strlen(name)-1] += unit;
+		printk(" %s", name);
+	} else
+#endif
+		printk(" %s%c", hd->major_name, 'a' + unit);
+	if (part)
+		printk("%d", part);
+	else
+		printk(":");
 }
 
 static void add_partition (struct gendisk *hd, int minor, int start, int size)
 {
 	hd->part[minor].start_sect = start;
 	hd->part[minor].nr_sects   = size;
-	printk(" %s%c%d", hd->major_name, minor_name(hd, minor),
-		minor & ((1 << hd->minor_shift) - 1));
+	print_minor_name(hd, minor);
 }
 
 #ifdef CONFIG_MSDOS_PARTITION
@@ -100,7 +120,6 @@
 			    !(hd->part[current_minor].nr_sects = p->nr_sects))
 				goto done;  /* no more logicals in this partition */
 			hd->part[current_minor].start_sect = first_sector + p->start_sect;
-			hd->sizes[current_minor] = p->nr_sects >> (BLOCK_SIZE_BITS - 9);
 			this_sector = first_sector + p->start_sect;
 			dev = ((hd->major) << 8) | current_minor;
 			brelse(bh);
@@ -134,12 +153,14 @@
 
 #ifdef CONFIG_BLK_DEV_IDE
 	/*
-	 *  Check for Disk Manager v6.0x with geometry translation
+	 *  Check for Disk Manager v6.0x (or EZ-DRIVE) with geometry translation
 	 */
 	if (!tested_for_dm6++) {	/* only check for DM6 *once* */
 		extern int ide_xlate_1024(dev_t, int, const char *);
 		/* check for DM6 with Dynamic Drive Overlay (DDO) */
-		if (p->sys_ind == DM6_PARTITION) {
+		if (p->sys_ind == DM6_PARTITION || p->sys_ind == EZD_PARTITION) {
+			const char *label = (p->sys_ind == DM6_PARTITION)?" [DM6:DDO]":" [EZDRIVE]";
+
 			/*
 			 * Everything on the disk is offset by 63 sectors,
 			 * including a "new" MBR with its own partition table,
@@ -150,7 +171,7 @@
 			 * ide_xlate_1024() will take care of the necessary
 			 * adjustments to fool fdisk/LILO and partition check.
 			 */
-			if (ide_xlate_1024(dev,1," [DM6:DDO]")) {
+			if (ide_xlate_1024(dev, 1, label)) {
 				bh->b_dirt = 0;	/* force re-read of MBR block */
 				bh->b_uptodate = 0;
 				bh->b_req = 0;
@@ -164,7 +185,7 @@
 			 && *(unsigned short *)(bh->b_data + sig) == 0x55AA
 			 && (1 & *(unsigned char *)(bh->b_data + sig + 2)) ) 
 			{
-				(void)ide_xlate_1024(dev,0," [DM6:MBR]");
+				(void) ide_xlate_1024 (dev, 0, " [DM6:MBR]");
 			} else {
 				/* look for DM6 AUX partition type in slot 1 */
 				if (p->sys_ind == DM6_AUX1PARTITION
@@ -300,7 +321,8 @@
 		return;
 	}
 
-	printk("  %s%c:", hd->major_name, minor_name(hd, MINOR(dev)));
+	printk(" ");
+	print_minor_name(hd, MINOR(dev));
 #ifdef CONFIG_MSDOS_PARTITION
 	if (msdos_partition(hd, dev, first_sector))
 		return;
@@ -324,37 +346,43 @@
 void resetup_one_dev(struct gendisk *dev, int drive)
 {
 	int i;
-	int start = drive<<dev->minor_shift;
-	int j = start + dev->max_p;
-	int major = dev->major << 8;
-
-	current_minor = 1+(drive<<dev->minor_shift);
-	check_partition(dev, major+(drive<<dev->minor_shift));
-
-	for (i=start ; i < j ; i++)
-		dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+	int major	= dev->major << 8;
+	int first_minor	= drive << dev->minor_shift;
+	int end_minor	= first_minor + dev->max_p;
+
+	blk_size[dev->major] = NULL;
+	current_minor = 1 + first_minor;
+	check_partition(dev, major + first_minor);
+
+	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
+		for (i = first_minor; i < end_minor; i++)
+			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+		blk_size[dev->major] = dev->sizes;
+	}
 }
 
 static void setup_dev(struct gendisk *dev)
 {
-	int i;
-	int j = dev->max_nr * dev->max_p;
-	int major = dev->major << 8;
-	int drive;
-	
+	int i, drive;
+	int major	= dev->major << 8;
+	int end_minor	= dev->max_nr * dev->max_p;
 
-	for (i = 0 ; i < j; i++)  {
+	blk_size[dev->major] = NULL;
+	for (i = 0 ; i < end_minor; i++) {
 		dev->part[i].start_sect = 0;
 		dev->part[i].nr_sects = 0;
 	}
-	dev->init();	
-	for (drive=0 ; drive<dev->nr_real ; drive++) {
-		current_minor = 1+(drive<<dev->minor_shift);
-		check_partition(dev, major+(drive<<dev->minor_shift));
-	}
-	for (i=0 ; i < j ; i++)
-		dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
-	blk_size[dev->major] = dev->sizes;
+	dev->init(dev);	
+	for (drive = 0 ; drive < dev->nr_real ; drive++) {
+		int first_minor	= drive << dev->minor_shift;
+		current_minor = 1 + first_minor;
+		check_partition(dev, major + first_minor);
+	}
+	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
+		for (i = 0; i < end_minor; i++)
+			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+		blk_size[dev->major] = dev->sizes;
+	}
 }
 	
 void device_setup(void)
diff -u --recursive --new-file v1.3.18/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.3.18/linux/drivers/block/hd.c	Tue Aug  8 12:31:33 1995
+++ linux/drivers/block/hd.c	Sun Aug 13 20:19:11 1995
@@ -44,8 +44,6 @@
 #define MAJOR_NR HD_MAJOR
 #include "blk.h"
 
-#define HD_IRQ 14
-
 static int revalidate_hddisk(int, int);
 
 #define	HD_DELAY	0
@@ -915,7 +913,7 @@
 
 }
 
-static void hd_geninit(void);
+static void hd_geninit(struct gendisk *);
 
 static struct gendisk hd_gendisk = {
 	MAJOR_NR,	/* Major number */	
@@ -952,7 +950,7 @@
  * We enable interrupts in some of the routines after making sure it's
  * safe.
  */
-static void hd_geninit(void)
+static void hd_geninit(struct gendisk *ignored)
 {
 	int i;
 
diff -u --recursive --new-file v1.3.18/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v1.3.18/linux/drivers/block/ide-cd.c	Sun Jun 11 19:15:34 1995
+++ linux/drivers/block/ide-cd.c	Mon Aug 14 07:44:04 1995
@@ -6,7 +6,7 @@
  *                       cdrom_check_status.
  * 1.03  Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
  * (from mlord)       -- minor changes to cdrom_setup()
- *                    -- renamed ide_dev_s to ide_dev_t, enable irq on command
+ *                    -- renamed ide_dev_s to ide_drive_t, enable irq on command
  * 2.00  Nov 27, 1994 -- Generalize packet command interface;
  *                       add audio ioctls.
  * 2.01  Dec  3, 1994 -- Rework packet command interface to handle devices
@@ -39,7 +39,23 @@
  *                       Properly supply the page number field in the
  *                        MODE_SELECT command.
  *                       PLAYAUDIO12 is broken on the Aztech; work around it.
- *                       
+ * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
+ *                       (my apologies to Scott, but now ide-cd.c is independent)
+ *
+ * FIX ME!!  A day-one bug exists when the ide.c "serialize" option is used.
+ * For this to always work correctly, ide_set_handler() must be called
+ * *just before* the final trigger is given to the drive (to cause it to go
+ * off and get data and then interrupt us again).  Otherwise, we may get the
+ * interrupt before set_handler() has actually run, resulting in "unexpected_intr".
+ *
+ * This can only happen in scenarios where we handle a "final" interrupt
+ * for one IDE port on, say irq14, and then initiate a new request for the
+ * other port on, say irq15, from the irq14 interrupt handler.  If we are
+ * running with "unmask" on, or have done sti(), then Whammo -- we're exposed.
+ *
+ * Places where this needs fixing have been identified in the code with "BUG".
+ * -ml  August 11, 1995
+ *
  *
  * ATAPI cd-rom driver.  To be used with ide.c.
  *
@@ -49,6 +65,25 @@
  */
 
 
+/***************************************************************************/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/cdrom.h>
+#include <asm/irq.h>
+
+#define _IDE_CD_C	/* used in blk.h */
+#include "ide.h"
+
 /* Turn this on to have the driver print out the meanings of the
    ATAPI error codes.  This will use up additional kernel-space
    memory, though. */
@@ -57,10 +92,6 @@
 #define VERBOSE_IDE_CD_ERRORS 0
 #endif
 
-/***************************************************************************/
-
-#include <linux/cdrom.h>
-
 #define SECTOR_SIZE 512
 #define SECTOR_BITS 9
 #define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
@@ -68,11 +99,11 @@
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 #if 1	/* "old" method */
-#define OUT_WORDS(b,n)  outsw (IDE_PORT (HD_DATA, DEV_HWIF), (b), (n))
-#define IN_WORDS(b,n)   insw  (IDE_PORT (HD_DATA, DEV_HWIF), (b), (n))
+#define OUT_WORDS(b,n)  outsw (IDE_DATA_REG, (b), (n))
+#define IN_WORDS(b,n)   insw  (IDE_DATA_REG, (b), (n))
 #else	/* "new" method -- should really fix each instance instead of this */
-#define OUT_WORDS(b,n)	output_ide_data(dev,b,(n)/2)
-#define IN_WORDS(b,n)	input_ide_data(dev,b,(n)/2)
+#define OUT_WORDS(b,n)	output_ide_data(drive,b,(n)/2)
+#define IN_WORDS(b,n)	input_ide_data(drive,b,(n)/2)
 #endif
 
 /* special command codes for strategy routine. */
@@ -105,34 +136,8 @@
 #define ABORTED_COMMAND         0x0b
 #define MISCOMPARE              0x0e
 
-
-struct packet_command {
-  char *buffer;
-  int buflen;
-  int stat;
-  unsigned char c[12];
-};
-
-
-struct atapi_request_sense {
-  unsigned char error_code : 7;
-  unsigned char valid      : 1;
-  byte reserved1;
-  unsigned char sense_key  : 4;
-  unsigned char reserved2  : 1;
-  unsigned char ili        : 1;
-  unsigned char reserved3  : 2;
-  byte info[4];
-  byte sense_len;
-  byte command_info[4];
-  byte asc;
-  byte ascq;
-  byte fru;
-  byte sense_key_specific[3];
-};
-
 /* We want some additional flags for cd-rom drives.
-   To save space in the ide_dev_t struct, use one of the fields which
+   To save space in the ide_drive_t struct, use one of the fields which
    doesn't make sense for cd-roms -- `bios_sect'. */
 
 struct ide_cd_flags {
@@ -147,69 +152,10 @@
   unsigned reserved : 2;
 };
 
-#define CDROM_FLAGS(dev) ((struct ide_cd_flags *)&((dev)->bios_sect))
-
-
-/* Space to hold the disk TOC. */
-
-#define MAX_TRACKS 99
-struct atapi_toc_header {
-  unsigned short toc_length;
-  byte first_track;
-  byte last_track;
-};
-
-struct atapi_toc_entry {
-  byte reserved1;
-  unsigned control : 4;
-  unsigned adr     : 4;
-  byte track;
-  byte reserved2;
-  unsigned lba;
-};
-
-struct atapi_toc {
-  struct atapi_toc_header hdr;
-  struct atapi_toc_entry  ent[MAX_TRACKS+1];  /* One extra for the leadout. */
-};
-
+#define CDROM_FLAGS(drive) ((struct ide_cd_flags *)&((drive)->bios_sect))
 
 #define SECTOR_BUFFER_SIZE CD_FRAMESIZE
 
-/* Extra per-device info for cdrom drives. */
-struct cdrom_info {
-
-  /* Buffer for table of contents.  NULL if we haven't allocated
-     a TOC buffer for this device yet. */
-
-  struct atapi_toc *toc;
-
-  /* Sector buffer.  If a read request wants only the first part of a cdrom
-     block, we cache the rest of the block here, in the expectation that that
-     data is going to be wanted soon.  SECTOR_BUFFERED is the number of the
-     first buffered sector, and NSECTORS_BUFFERED is the number of sectors
-     in the buffer.  Before the buffer is allocated, we should have
-     SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
-
-  unsigned long sector_buffered;
-  unsigned long nsectors_buffered;
-  char *sector_buffer;
-
-  /* The result of the last successful request sense command
-     on this device. */
-  struct atapi_request_sense sense_data;
-};
-
-
-static struct cdrom_info cdrom_info[2][MAX_DRIVES];
-
-/* Statically allocate one request packet and one packet command struct
-   for each interface for retrieving sense data during error recovery. */
-
-static struct request request_sense_request[2];
-static struct packet_command request_sense_pc[2];
-
-
 
 /****************************************************************************
  * Descriptions of ATAPI error codes.
@@ -359,7 +305,7 @@
 
 
 static
-void cdrom_analyze_sense_data (ide_dev_t *dev, 
+void cdrom_analyze_sense_data (ide_drive_t *drive, 
 			       struct atapi_request_sense *reqbuf,
 			       struct packet_command *failed_command)
 {
@@ -377,7 +323,7 @@
     char *s;
     char buf[80];
 
-    printk ("ATAPI device %s:\n", dev->name);
+    printk ("ATAPI device %s:\n", drive->name);
 
     printk ("  Error code: %x\n", reqbuf->error_code);
 
@@ -437,7 +383,7 @@
 
 #else
   printk ("%s: code: %x  key: %x  asc: %x  ascq: %x\n",
-	  dev->name,
+	  drive->name,
 	  reqbuf->error_code, reqbuf->sense_key, reqbuf->asc, reqbuf->ascq);
 #endif
 }
@@ -458,19 +404,19 @@
 }
 
 
-static void cdrom_queue_request_sense (ide_dev_t *dev)
+static void cdrom_queue_request_sense (ide_drive_t *drive)
 {
   struct request *rq;
   struct packet_command *pc;
   struct atapi_request_sense *reqbuf;
   unsigned long flags;
 
-  int major = ide_major[DEV_HWIF];
+  int major = HWIF(drive)->major;
 
   save_flags (flags);
   cli ();  /* safety */
 
-  rq = ide_cur_rq[DEV_HWIF];
+  rq = HWGROUP(drive)->rq;
 
   /* If we're processing a request, put it back on the request queue. */
   if (rq != NULL)
@@ -478,15 +424,15 @@
       restore_request (rq);
       rq->next = blk_dev[major].current_request;
       blk_dev[major].current_request = rq;
-      ide_cur_rq[DEV_HWIF] = NULL;
+      HWGROUP(drive)->rq = NULL;
     }
 
   restore_flags (flags);
 
   /* Make up a new request to retrieve sense information. */
-  reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data;
+  reqbuf = &drive->cdrom_info.sense_data;
 
-  pc = &request_sense_pc[DEV_HWIF];
+  pc = &HWIF(drive)->request_sense_pc;
   memset (pc, 0, sizeof (*pc));
 
   pc->c[0] = REQUEST_SENSE;
@@ -494,8 +440,8 @@
   pc->buffer = (char *)reqbuf;
   pc->buflen = sizeof (*reqbuf);
   
-  rq = &request_sense_request[DEV_HWIF];
-  rq->dev = MKDEV (major, (dev->select.b.drive) << PARTN_BITS);
+  rq = &HWIF(drive)->request_sense_request;
+  rq->dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS);
   rq->cmd = REQUEST_SENSE_COMMAND;
   rq->errors = 0;
   rq->sector = 0;
@@ -518,9 +464,9 @@
 }
 
 
-static void cdrom_end_request (int uptodate, ide_dev_t *dev)
+static void cdrom_end_request (int uptodate, ide_drive_t *drive)
 {
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
 
   /* The code in blk.h can screw us up on error recovery if the block
      size is larger than 1k.  Fix that up here. */
@@ -534,44 +480,44 @@
   if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate)
     {
       struct atapi_request_sense *reqbuf;
-      reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data;
-      cdrom_analyze_sense_data (dev, reqbuf, NULL);
+      reqbuf = &drive->cdrom_info.sense_data;
+      cdrom_analyze_sense_data (drive, reqbuf, NULL);
     }
 
-  end_request (uptodate, DEV_HWIF);
+  ide_end_request (uptodate, HWGROUP(drive));
 }
 
 
 /* Mark that we've seen a media change, and invalidate our internal
    buffers. */
-static void cdrom_saw_media_change (ide_dev_t *dev)
+static void cdrom_saw_media_change (ide_drive_t *drive)
 {
-  CDROM_FLAGS (dev)->media_changed = 1;
-  CDROM_FLAGS (dev)->toc_valid = 0;
-  cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0;
+  CDROM_FLAGS (drive)->media_changed = 1;
+  CDROM_FLAGS (drive)->toc_valid = 0;
+  drive->cdrom_info.nsectors_buffered = 0;
 }
 
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
-static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
+static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret)
 {
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
   int stat, err, sense_key, cmd;
 
   /* Check for errors. */
-  stat = GET_STAT (DEV_HWIF);
+  stat = GET_STAT();
   *stat_ret = stat;
 
   if (OK_STAT (stat, good_stat, BAD_R_STAT))
     return 0;
 
   /* Got an error. */
-  err = IN_BYTE (HD_ERROR, DEV_HWIF);
+  err = IN_BYTE (IDE_ERROR_REG);
   sense_key = err >> 4;
 
   if (rq == NULL)
-    printk ("%s : missing request in cdrom_decode_status\n", dev->name);
+    printk ("%s : missing request in cdrom_decode_status\n", drive->name);
   else
     {
       cmd = rq->cmd;
@@ -580,13 +526,13 @@
       if (sense_key == NOT_READY)
 	{
 	  struct packet_command *pc;
-	  cdrom_saw_media_change (dev);
+	  cdrom_saw_media_change (drive);
 
 	  /* Fail the request if this is a read command. */
 	  if (cmd == READ)
 	    {
-	      printk ("%s : tray open\n", dev->name);
-	      cdrom_end_request (0, dev);
+	      printk ("%s : tray open\n", drive->name);
+	      cdrom_end_request (0, drive);
 	    }
 
 	  else
@@ -599,19 +545,19 @@
 		 the syslog. */
 	      pc = (struct packet_command *)rq->buffer;
 	      if (pc->c[0] != SCMD_READ_SUBCHANNEL)
-		printk ("%s : tray open\n", dev->name);
+		printk ("%s : tray open\n", drive->name);
 
 	      /* Set the error flag and complete the request. */
 	      pc->stat = 1;
-	      cdrom_end_request (1, dev);
+	      cdrom_end_request (1, drive);
 	    }
 	}
 
       /* Check for media change. */
       else if (sense_key == UNIT_ATTENTION)
 	{
-	  cdrom_saw_media_change (dev);
-	  printk ("%s: media changed\n", dev->name);
+	  cdrom_saw_media_change (drive);
+	  printk ("%s: media changed\n", drive->name);
 
 	  /* Return failure for a packet command, so that
 	     cdrom_queue_packet_command can do a request sense before
@@ -621,14 +567,14 @@
 	    {
 	      struct packet_command *pc = (struct packet_command *)rq->buffer;
 	      pc->stat = 1;
-	      cdrom_end_request (1, dev);
+	      cdrom_end_request (1, drive);
 	    }
 
 	  /* Otherwise, it's a block read.  Arrange to retry it.
 	     But be sure to give up if we've retried too many times. */
 	  else if ((++rq->errors > ERROR_MAX))
 	    {
-	      cdrom_end_request (0, dev);
+	      cdrom_end_request (0, drive);
 	    }
 	}
 
@@ -636,28 +582,29 @@
       else if (cmd == PACKET_COMMAND)
 	{
 	  struct packet_command *pc = (struct packet_command *)rq->buffer;
-	  dump_status (DEV_HWIF, "packet command error", stat);
+	  ide_dump_status (drive, "packet command error", stat);
 	  pc->stat = 1;  /* signal error */
-	  cdrom_end_request (1, dev);
+	  cdrom_end_request (1, drive);
 	}
 
       /* No point in retrying after an illegal request or data protect error.*/
       else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT)
 	{
-	  dump_status (DEV_HWIF, "command error", stat);
-	  cdrom_end_request (0, dev);
+	  ide_dump_status (drive, "command error", stat);
+	  cdrom_end_request (0, drive);
 	}
 
       /* If there were other errors, go to the default handler. */
       else if ((err & ~ABRT_ERR) != 0)
 	{
-	  ide_error (dev, "cdrom_decode_status", stat);
+	  if (ide_error (drive, "cdrom_decode_status", stat))
+	    return 1;
 	}
 
       /* Else, abort if we've racked up too many retries. */
       else if ((++rq->errors > ERROR_MAX))
 	{
-	  cdrom_end_request (0, dev);
+	  cdrom_end_request (0, drive);
 	}
 
       /* If we got a CHECK_STATUS condition, and this was a READ request,
@@ -665,11 +612,11 @@
 	 what went wrong (and clear a unit attention)?  For packet commands,
 	 this is done separately in cdrom_queue_packet_command. */
       if ((stat & ERR_STAT) != 0 && cmd == READ)
-	cdrom_queue_request_sense (dev);
+	cdrom_queue_request_sense (drive);
     }
 
   /* Retry, or handle the next request. */
-  DO_REQUEST;
+  IDE_DO_REQUEST;
   return 1;
 }
 
@@ -678,20 +625,20 @@
    expecting to later transfer XFERLEN bytes.  This should be followed
    by a call to cdrom_transfer_packet_command; however, if this is a
    drq_interrupt device, one must wait for an interrupt first. */
-static int cdrom_start_packet_command (ide_dev_t *dev, int xferlen)
+static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen)
 {
   /* Wait for the controller to be idle. */
-  if (wait_stat (dev, 0, BUSY_STAT, WAIT_READY)) return 1;
+  if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
 
   /* Set up the controller registers. */
-  OUT_BYTE (0, HD_FEATURE);
-  OUT_BYTE (0, HD_NSECTOR);
-  OUT_BYTE (0, HD_SECTOR);
-
-  OUT_BYTE (xferlen & 0xff, HD_LCYL);
-  OUT_BYTE (xferlen >> 8  , HD_HCYL);
-  OUT_BYTE (dev->ctl, HD_CMD);
-  OUT_BYTE (WIN_PACKETCMD, HD_COMMAND); /* packet command */
+  OUT_BYTE (0, IDE_FEATURE_REG);
+  OUT_BYTE (0, IDE_NSECTOR_REG);
+  OUT_BYTE (0, IDE_SECTOR_REG);
+
+  OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
+  OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+  OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+  OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
 
   return 0;
 }
@@ -700,22 +647,22 @@
 /* Send a packet command to DEV described by CMD_BUF and CMD_LEN.
    The device registers must have already been prepared
    by cdrom_start_packet_command. */
-static int cdrom_transfer_packet_command (ide_dev_t *dev,
+static int cdrom_transfer_packet_command (ide_drive_t *drive,
                                           char *cmd_buf, int cmd_len)
 {
-  if (CDROM_FLAGS (dev)->drq_interrupt)
+  if (CDROM_FLAGS (drive)->drq_interrupt)
     {
       /* Here we should have been called after receiving an interrupt
          from the device.  DRQ should how be set. */
       int stat_dum;
 
       /* Check for errors. */
-      if (cdrom_decode_status (dev, DRQ_STAT, &stat_dum)) return 1;
+      if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;
     }
   else
     {
       /* Otherwise, we must wait for DRQ to get set. */
-      if (wait_stat (dev, DRQ_STAT, BUSY_STAT, WAIT_READY)) return 1;
+      if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) return 1;
     }
 
   /* Send the command to the device. */
@@ -737,10 +684,10 @@
  * sector added, SECTOR is its sector number.  (SECTOR is then ignored until
  * the buffer is cleared.)
  */
-static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector,
+static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
                                   int sectors_to_transfer)
 {
-  struct cdrom_info *info = &cdrom_info[DEV_HWIF][dev->select.b.drive];
+  struct cdrom_info *info = &drive->cdrom_info;
 
   /* Number of sectors to read into the buffer. */
   int sectors_to_buffer = MIN (sectors_to_transfer,
@@ -792,7 +739,7 @@
  * ok; nonzero if the request has been terminated.
  */
 static inline
-int cdrom_read_check_ireason (ide_dev_t *dev, int len, int ireason)
+int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 {
   ireason &= 3;
   if (ireason == 2) return 0;
@@ -802,7 +749,7 @@
       /* Whoops... The drive is expecting to receive data from us! */
       printk ("%s: cdrom_read_intr: "
               "Drive wants to transfer data the wrong way!\n",
-              dev->name);
+              drive->name);
 
       /* Throw some data at the drive so it doesn't hang
          and quit this request. */
@@ -818,11 +765,11 @@
     {
       /* Drive wants a command packet, or invalid ireason... */
       printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
-              dev->name, ireason);
+              drive->name, ireason);
     }
 
-  cdrom_end_request (0, dev);
-  DO_REQUEST;
+  cdrom_end_request (0, drive);
+  IDE_DO_REQUEST;
   return -1;
 }
 
@@ -830,19 +777,19 @@
 /*
  * Interrupt routine.  Called when a read request has completed.
  */
-static void cdrom_read_intr (ide_dev_t *dev)
+static void cdrom_read_intr (ide_drive_t *drive)
 {
   int stat;
   int ireason, len, sectors_to_transfer, nskip;
 
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
 
   /* Check for errors. */
-  if (cdrom_decode_status (dev, 0, &stat)) return;
+  if (cdrom_decode_status (drive, 0, &stat)) return;
 
   /* Read the interrupt reason and the transfer length. */
-  ireason = IN_BYTE (HD_NSECTOR, DEV_HWIF);
-  len = IN_BYTE (HD_LCYL, DEV_HWIF) + 256 * IN_BYTE (HD_HCYL, DEV_HWIF);
+  ireason = IN_BYTE (IDE_NSECTOR_REG);
+  len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
 
   /* If DRQ is clear, the command has completed. */
   if ((stat & DRQ_STAT) == 0)
@@ -852,28 +799,28 @@
       if (rq->current_nr_sectors > 0)
         {
           printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
-                  dev->name, rq->current_nr_sectors);
-          cdrom_end_request (0, dev);
+                  drive->name, rq->current_nr_sectors);
+          cdrom_end_request (0, drive);
         }
       else
-        cdrom_end_request (1, dev);
+        cdrom_end_request (1, drive);
 
-      DO_REQUEST;
+      IDE_DO_REQUEST;
       return;
     }
 
   /* Check that the drive is expecting to do the same thing that we are. */
-  if (cdrom_read_check_ireason (dev, len, ireason)) return;
+  if (cdrom_read_check_ireason (drive, len, ireason)) return;
 
   /* Assume that the drive will always provide data in multiples of at least
      SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */
   if ((len % SECTOR_SIZE) != 0)
     {
       printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
-              dev->name, len);
+              drive->name, len);
       printk ("  This drive is not supported by this version of the driver\n");
-      cdrom_end_request (0, dev);
-      DO_REQUEST;
+      cdrom_end_request (0, drive);
+      IDE_DO_REQUEST;
       return;
     }
 
@@ -904,13 +851,13 @@
          buffer after it, move on. */
       if (rq->current_nr_sectors == 0 &&
           rq->nr_sectors > 0)
-        cdrom_end_request (1, dev);
+        cdrom_end_request (1, drive);
 
       /* If the buffers are full, cache the rest of the data in our
          internal buffer. */
       if (rq->current_nr_sectors == 0)
         {
-          cdrom_buffer_sectors (dev, rq->sector, sectors_to_transfer);
+          cdrom_buffer_sectors (drive, rq->sector, sectors_to_transfer);
           sectors_to_transfer = 0;
         }
       else
@@ -937,7 +884,7 @@
 
   /* Done moving data!
      Wait for another interrupt. */
-  ide_handler[DEV_HWIF] = cdrom_read_intr;
+  ide_set_handler(drive, &cdrom_read_intr);	/* this one is okay */
 }
 
 
@@ -945,10 +892,10 @@
  * Try to satisfy some of the current read request from our cached data.
  * Returns nonzero if the request has been completed, zero otherwise.
  */
-static int cdrom_read_from_buffer (ide_dev_t *dev)
+static int cdrom_read_from_buffer (ide_drive_t *drive)
 {
-  struct cdrom_info *info = &cdrom_info[DEV_HWIF][dev->select.b.drive];
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct cdrom_info *info = &drive->cdrom_info;
+  struct request *rq = HWGROUP(drive)->rq;
 
   /* Can't do anything if there's no buffer. */
   if (info->sector_buffer == NULL) return 0;
@@ -960,7 +907,7 @@
          rq->sector < info->sector_buffered + info->nsectors_buffered)
     {
       if (rq->current_nr_sectors == 0)
-        cdrom_end_request (1, dev);
+        cdrom_end_request (1, drive);
 
       memcpy (rq->buffer,
               info->sector_buffer +
@@ -975,13 +922,13 @@
   /* If we've satisfied the current request, terminate it successfully. */
   if (rq->nr_sectors == 0)
     {
-      cdrom_end_request (1, dev);
+      cdrom_end_request (1, drive);
       return -1;
     }
 
   /* Move on to the next buffer if needed. */
   if (rq->current_nr_sectors == 0)
-    cdrom_end_request (1, dev);
+    cdrom_end_request (1, drive);
 
   /* If this condition does not hold, then the kluge i use to
      represent the number of sectors to skip at the start of a transfer
@@ -991,8 +938,8 @@
       (rq->sector % SECTORS_PER_FRAME) != 0)
     {
       printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
-              dev->name, rq->sector);
-      cdrom_end_request (0, dev);
+              drive->name, rq->sector);
+      cdrom_end_request (0, drive);
       return -1;
     }
 
@@ -1007,10 +954,10 @@
  * However, for drq_interrupt devices, it is called from an interrupt
  * when the drive is ready to accept the command.
  */
-static int cdrom_start_read_continuation (ide_dev_t *dev)
+static int cdrom_start_read_continuation (ide_drive_t *drive)
 {
   struct packet_command pc;
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
 
   int nsect, sector, nframes, frame, nskip;
 
@@ -1033,9 +980,9 @@
       if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS))
         {
           printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
-                  dev->name, rq->current_nr_sectors);
-          cdrom_end_request (0, dev);
-          DO_REQUEST;
+                  drive->name, rq->current_nr_sectors);
+          cdrom_end_request (0, drive);
+          IDE_DO_REQUEST;
           return 1;
         }
 
@@ -1071,11 +1018,11 @@
     pc.c[5] = conv.b.b0;
   }
 
-  if (cdrom_transfer_packet_command (dev, pc.c, sizeof (pc.c)))
+  if (cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c)))
     return 1;
 
   /* Set up our interrupt handler and return. */
-  ide_handler[DEV_HWIF] = cdrom_read_intr;
+  ide_set_handler(drive, &cdrom_read_intr); /* BUG: do this BEFORE triggering drive */
 
   return 0;
 }
@@ -1087,29 +1034,29 @@
  *  1 if there was an error and we should either retry or move on to the
  *  next request.
  */
-static int cdrom_start_read (ide_dev_t *dev, unsigned int block)
+static int cdrom_start_read (ide_drive_t *drive, unsigned int block)
 {
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
 
   /* We may be retrying this request after an error.
      Fix up any weirdness which might be present in the request packet. */
   restore_request (rq);
 
   /* Satisfy whatever we can of this request from our cached sector. */
-  if (cdrom_read_from_buffer (dev))
+  if (cdrom_read_from_buffer (drive))
     return 1;
 
   /* Clear the local sector buffer. */
-  cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0;
+  drive->cdrom_info.nsectors_buffered = 0;
 
-  if (cdrom_start_packet_command (dev, 32768))
+  if (cdrom_start_packet_command (drive, 32768))
     return 1;
 
-  if (CDROM_FLAGS (dev)->drq_interrupt)
-    ide_handler[DEV_HWIF] = (void (*)(ide_dev_t *))cdrom_start_read_continuation;
+  if (CDROM_FLAGS (drive)->drq_interrupt)
+    ide_set_handler(drive, (ide_handler_t *)&cdrom_start_read_continuation); /* BUG: do this BEFORE triggering drive */
   else
     {
-      if (cdrom_start_read_continuation (dev))
+      if (cdrom_start_read_continuation (drive))
         return 1;
     }
 
@@ -1125,22 +1072,22 @@
 
 /* Forward declaration */
 static int
-cdrom_request_sense (ide_dev_t *dev, struct atapi_request_sense *reqbuf);
+cdrom_request_sense (ide_drive_t *drive, struct atapi_request_sense *reqbuf);
 
 
 /* Interrupt routine for packet command completion. */
-static void cdrom_pc_intr (ide_dev_t *dev)
+static void cdrom_pc_intr (ide_drive_t *drive)
 {
   int ireason, len, stat, thislen;
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
   struct packet_command *pc = (struct packet_command *)rq->buffer;
 
   /* Check for errors. */
-  if (cdrom_decode_status (dev, 0, &stat)) return;
+  if (cdrom_decode_status (drive, 0, &stat)) return;
 
   /* Read the interrupt reason and the transfer length. */
-  ireason = IN_BYTE (HD_NSECTOR, DEV_HWIF);
-  len = IN_BYTE (HD_LCYL, DEV_HWIF) + 256 * IN_BYTE (HD_HCYL, DEV_HWIF);
+  ireason = IN_BYTE (IDE_NSECTOR_REG);
+  len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
 
   /* If DRQ is clear, the command has completed.
      Complain if we still have data left to transfer. */
@@ -1156,15 +1103,15 @@
       }
 
       if (pc->buflen == 0)
-        cdrom_end_request (1, dev);
+        cdrom_end_request (1, drive);
       else
         {
           printk ("%s: cdrom_pc_intr: data underrun %d\n",
-                  dev->name, pc->buflen);
+                  drive->name, pc->buflen);
           pc->stat = 1;
-          cdrom_end_request (1, dev);
+          cdrom_end_request (1, drive);
         }
-      DO_REQUEST;
+      IDE_DO_REQUEST;
       return;
     }
 
@@ -1180,7 +1127,7 @@
       if (pc->buflen > 0)
         {
           printk ("%s: cdrom_pc_intr: Drive wants to transfer data the wrong way!\n",
-                  dev->name);
+                  drive->name);
           pc->stat = 1;
           thislen = 0;
         }
@@ -1209,7 +1156,7 @@
       if (pc->buflen < 0)
         {
           printk ("%s: cdrom_pc_intr: Drive wants to transfer data the wrong way!\n",
-                  dev->name);
+                  drive->name);
           pc->stat = 1;
           thislen = 0;
         }
@@ -1234,34 +1181,34 @@
   else
     {
       printk ("%s: cdrom_pc_intr: The drive appears confused (ireason = 0x%2x)\n",
-              dev->name, ireason);
+              drive->name, ireason);
       pc->stat = 1;
     }
 
   /* Now we wait for another interrupt. */
-  ide_handler[DEV_HWIF] = cdrom_pc_intr;
+  ide_set_handler(drive, &cdrom_pc_intr);	/* this one is okay */
 }
 
 
-static int cdrom_do_pc_continuation (ide_dev_t *dev)
+static int cdrom_do_pc_continuation (ide_drive_t *drive)
 {
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
   struct packet_command *pc = (struct packet_command *)rq->buffer;
 
-  if (cdrom_transfer_packet_command (dev, pc->c, sizeof (pc->c)))
+  if (cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c)))
     return 1;
 
   /* Set up our interrupt handler and return. */
-  ide_handler[DEV_HWIF] = cdrom_pc_intr;
+  ide_set_handler(drive, &cdrom_pc_intr); /* BUG: do this BEFORE triggering drive */
 
   return 0;
 }
 
 
-static int cdrom_do_packet_command (ide_dev_t *dev)
+static int cdrom_do_packet_command (ide_drive_t *drive)
 {
   int len;
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
   struct packet_command *pc = (struct packet_command *)rq->buffer;
 
   len = pc->buflen;
@@ -1269,14 +1216,14 @@
 
   pc->stat = 0;
 
-  if (cdrom_start_packet_command (dev, len))
+  if (cdrom_start_packet_command (drive, len))
     return 1;
 
-  if (CDROM_FLAGS (dev)->drq_interrupt)
-    ide_handler[DEV_HWIF] = (void (*)(ide_dev_t *))cdrom_do_pc_continuation;
+  if (CDROM_FLAGS (drive)->drq_interrupt)
+    ide_set_handler(drive, (ide_handler_t *)&cdrom_do_pc_continuation); /* BUG: do this BEFORE triggering drive */
   else
     {
-      if (cdrom_do_pc_continuation (dev))
+      if (cdrom_do_pc_continuation (drive))
         return 1;
     }
 
@@ -1285,16 +1232,16 @@
 
 
 static
-int cdrom_queue_packet_command (ide_dev_t *dev, struct packet_command *pc)
+int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
 {
   int retries = 3;
   unsigned long flags;
   struct request req, **p, **pfirst;
   struct semaphore sem = MUTEX_LOCKED;
-  int major = ide_major[DEV_HWIF];
+  int major = HWIF(drive)->major;
 
  retry:
-  req.dev = MKDEV (major, (dev->select.b.drive) << PARTN_BITS);
+  req.dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS);
   req.cmd = PACKET_COMMAND;
   req.errors = 0;
   req.sector = 0;
@@ -1330,15 +1277,14 @@
 	 for this drive.  Check to be sure that it wasn't a request sense
 	 request that failed, though, to prevent infinite loops. */
       
-      struct atapi_request_sense *reqbuf = 
-	&cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data;
+      struct atapi_request_sense *reqbuf = &drive->cdrom_info.sense_data;
 
-      if (pc->c[0] == REQUEST_SENSE || cdrom_request_sense (dev, reqbuf))
+      if (pc->c[0] == REQUEST_SENSE || cdrom_request_sense (drive, reqbuf))
 	{
 	  memset (reqbuf, 0, sizeof (*reqbuf));
 	  reqbuf->asc = 0xff;
 	}
-      cdrom_analyze_sense_data (dev, reqbuf, pc);
+      cdrom_analyze_sense_data (drive, reqbuf, pc);
 
       /* If the error was a unit attention (usually means media was changed),
 	 retry the command. */
@@ -1360,21 +1306,19 @@
  * cdrom driver request routine.
  */
 
-static int do_rw_cdrom (ide_dev_t *dev, unsigned long block)
+void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block)
 {
-  struct request *rq = ide_cur_rq[DEV_HWIF];
+  struct request *rq = HWGROUP(drive)->rq;
 
   if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
-    return cdrom_do_packet_command (dev);
-
-  if (rq -> cmd != READ)
+    cdrom_do_packet_command (drive);
+  else if (rq -> cmd != READ)
     {
       printk ("ide-cd: bad cmd %d\n", rq -> cmd);
-      cdrom_end_request (0, dev);
-      return 1;
+      cdrom_end_request (0, drive);
     }
-
-  return cdrom_start_read (dev, block);
+  else
+    cdrom_start_read (drive, block);
 }
 
 
@@ -1433,7 +1377,7 @@
 
 
 static void
-cdrom_check_status (ide_dev_t  *dev)
+cdrom_check_status (ide_drive_t  *drive)
 {
   struct packet_command pc;
 
@@ -1441,12 +1385,12 @@
 
   pc.c[0] = TEST_UNIT_READY;
 
-  (void) cdrom_queue_packet_command (dev, &pc);
+  (void) cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_request_sense (ide_dev_t *dev, struct atapi_request_sense *reqbuf)
+cdrom_request_sense (ide_drive_t *drive, struct atapi_request_sense *reqbuf)
 {
   struct packet_command pc;
 
@@ -1457,14 +1401,14 @@
   pc.buffer = (char *)reqbuf;
   pc.buflen = sizeof (*reqbuf);
 
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 #if 0
 /* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
 static int
-cdrom_lockdoor (ide_dev_t *dev, int lockflag)
+cdrom_lockdoor (ide_drive_t *drive, int lockflag)
 {
   struct packet_command pc;
 
@@ -1472,7 +1416,7 @@
 
   pc.c[0] = ALLOW_MEDIUM_REMOVAL;
   pc.c[4] = (lockflag != 0);
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 #endif
 
@@ -1480,7 +1424,7 @@
 /* Eject the disk if EJECTFLAG is 0.
    If EJECTFLAG is 1, try to reload the disk. */
 static int
-cdrom_eject (ide_dev_t *dev, int ejectflag)
+cdrom_eject (ide_drive_t *drive, int ejectflag)
 {
   struct packet_command pc;
 
@@ -1488,12 +1432,12 @@
 
   pc.c[0] = START_STOP;
   pc.c[4] = 2 + (ejectflag != 0);
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_pause (ide_dev_t *dev, int pauseflag)
+cdrom_pause (ide_drive_t *drive, int pauseflag)
 {
   struct packet_command pc;
 
@@ -1501,12 +1445,12 @@
 
   pc.c[0] = SCMD_PAUSE_RESUME;
   pc.c[8] = !pauseflag;
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_startstop (ide_dev_t *dev, int startflag)
+cdrom_startstop (ide_drive_t *drive, int startflag)
 {
   struct packet_command pc;
 
@@ -1515,12 +1459,12 @@
   pc.c[0] = START_STOP;
   pc.c[1] = 1;
   pc.c[4] = startflag;
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_read_tocentry (ide_dev_t *dev, int trackno, int msf_flag,
+cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
                      char *buf, int buflen)
 {
   struct packet_command pc;
@@ -1534,44 +1478,44 @@
   pc.c[7] = (buflen >> 8);
   pc.c[8] = (buflen & 0xff);
   if (msf_flag) pc.c[1] = 2;
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 /* Try to read the entire TOC for the disk into our internal buffer. */
 static int
-cdrom_read_toc (ide_dev_t *dev)
+cdrom_read_toc (ide_drive_t *drive)
 {
   int msf_flag;
   int stat, ntracks, i;
-  struct atapi_toc *toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc;
+  struct atapi_toc *toc = drive->cdrom_info.toc;
 
   if (toc == NULL)
     {
       /* Try to allocate space. */
       toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
                                           GFP_KERNEL);
-      cdrom_info[DEV_HWIF][dev->select.b.drive].toc = toc;
+      drive->cdrom_info.toc = toc;
     }
 
   if (toc == NULL)
     {
-      printk ("%s: No cdrom TOC buffer!\n", dev->name);
+      printk ("%s: No cdrom TOC buffer!\n", drive->name);
       return -EIO;
     }
 
   /* Check to see if the existing data is still valid.
      If it is, just return. */
-  if (CDROM_FLAGS (dev)->toc_valid)
-    cdrom_check_status (dev);
+  if (CDROM_FLAGS (drive)->toc_valid)
+    cdrom_check_status (drive);
 
-  if (CDROM_FLAGS (dev)->toc_valid) return 0;
+  if (CDROM_FLAGS (drive)->toc_valid) return 0;
 
   /* Some drives can't return TOC data in LBA format. */
-  msf_flag = (CDROM_FLAGS (dev)->no_lba_toc);
+  msf_flag = (CDROM_FLAGS (drive)->no_lba_toc);
 
   /* First read just the header, so we know how long the TOC is. */
-  stat = cdrom_read_tocentry (dev, 0, msf_flag, (char *)toc,
+  stat = cdrom_read_tocentry (drive, 0, msf_flag, (char *)toc,
                               sizeof (struct atapi_toc_header) +
                               sizeof (struct atapi_toc_entry));
   if (stat) return stat;
@@ -1581,7 +1525,7 @@
   if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
 
   /* Now read the whole schmeer. */
-  stat = cdrom_read_tocentry (dev, 0, msf_flag, (char *)toc,
+  stat = cdrom_read_tocentry (drive, 0, msf_flag, (char *)toc,
                               sizeof (struct atapi_toc_header) +
                               (ntracks+1) * sizeof (struct atapi_toc_entry));
   if (stat) return stat;
@@ -1598,14 +1542,14 @@
     }
 
   /* Remember that we've read this stuff. */
-  CDROM_FLAGS (dev)->toc_valid = 1;
+  CDROM_FLAGS (drive)->toc_valid = 1;
 
   return 0;
 }
 
 
 static int
-cdrom_read_subchannel (ide_dev_t *dev,
+cdrom_read_subchannel (ide_drive_t *drive,
                        char *buf, int buflen)
 {
   struct packet_command pc;
@@ -1619,13 +1563,13 @@
   pc.c[3] = 0x01;  /* Format 1: current position */
   pc.c[7] = (buflen >> 8);
   pc.c[8] = (buflen & 0xff);
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 /* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */
 static int
-cdrom_mode_sense (ide_dev_t *dev, int pageno, int modeflag,
+cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
                   char *buf, int buflen)
 {
   struct packet_command pc;
@@ -1638,12 +1582,12 @@
   pc.c[2] = pageno | (modeflag << 6);
   pc.c[7] = (buflen >> 8);
   pc.c[8] = (buflen & 0xff);
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_mode_select (ide_dev_t *dev, int pageno, char *buf, int buflen)
+cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen)
 {
   struct packet_command pc;
 
@@ -1656,12 +1600,12 @@
   pc.c[2] = pageno;
   pc.c[7] = (buflen >> 8);
   pc.c[8] = (buflen & 0xff);
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_play_lba_range_play12 (ide_dev_t *dev, int lba_start, int lba_end)
+cdrom_play_lba_range_play12 (ide_drive_t *drive, int lba_start, int lba_end)
 {
   struct packet_command pc;
 
@@ -1673,12 +1617,12 @@
   byte_swap_long ((int *)(&pc.c[2]));
   byte_swap_long ((int *)(&pc.c[6]));
 
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 static int
-cdrom_play_lba_range_msf (ide_dev_t *dev, int lba_start, int lba_end)
+cdrom_play_lba_range_msf (ide_drive_t *drive, int lba_start, int lba_end)
 {
   struct packet_command pc;
 
@@ -1688,7 +1632,7 @@
   lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
   lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
 
-  if (CDROM_FLAGS (dev)->msf_as_bcd)
+  if (CDROM_FLAGS (drive)->msf_as_bcd)
     {
       pc.c[3] = bin2bcd (pc.c[3]);
       pc.c[4] = bin2bcd (pc.c[4]);
@@ -1698,14 +1642,14 @@
       pc.c[8] = bin2bcd (pc.c[8]);
     }
 
-  return cdrom_queue_packet_command (dev, &pc);
+  return cdrom_queue_packet_command (drive, &pc);
 }
 
 
 /* Play audio starting at LBA LBA_START and finishing with the
    LBA before LBA_END. */
 static int
-cdrom_play_lba_range (ide_dev_t *dev, int lba_start, int lba_end)
+cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end)
 {
   /* This is rather annoying.
      My NEC-260 won't recognize group 5 commands such as PLAYAUDIO12;
@@ -1718,27 +1662,27 @@
      great.  Otherwise, if the drive reports an illegal command code,
      try PLAYAUDIO_MSF using the NEC 260-style bcd parameters. */
 
-  if (CDROM_FLAGS (dev)->no_playaudio12)
-    return cdrom_play_lba_range_msf (dev, lba_start, lba_end);
+  if (CDROM_FLAGS (drive)->no_playaudio12)
+    return cdrom_play_lba_range_msf (drive, lba_start, lba_end);
   else
     {
       int stat;
       struct atapi_request_sense *reqbuf;
 
-      stat = cdrom_play_lba_range_play12 (dev, lba_start, lba_end);
+      stat = cdrom_play_lba_range_play12 (drive, lba_start, lba_end);
       if (stat == 0) return 0;
 
       /* It failed.  Try to find out why. */
-      reqbuf = &cdrom_info[DEV_HWIF][dev->select.b.drive].sense_data;
+      reqbuf = &drive->cdrom_info.sense_data;
       if (reqbuf->sense_key == 0x05 && reqbuf->asc == 0x20)
         {
           /* The drive didn't recognize the command.
              Retry with the MSF variant. */
           printk ("%s: Drive does not support PLAYAUDIO12; "
-                  "trying PLAYAUDIO_MSF\n", dev->name);
-          CDROM_FLAGS (dev)->no_playaudio12 = 1;
-          CDROM_FLAGS (dev)->msf_as_bcd = 1;
-          return cdrom_play_lba_range_msf (dev, lba_start, lba_end);
+                  "trying PLAYAUDIO_MSF\n", drive->name);
+          CDROM_FLAGS (drive)->no_playaudio12 = 1;
+          CDROM_FLAGS (drive)->msf_as_bcd = 1;
+          return cdrom_play_lba_range_msf (drive, lba_start, lba_end);
         }
 
       /* Failed for some other reason.  Give up. */
@@ -1748,17 +1692,17 @@
 
 
 static
-int cdrom_get_toc_entry (ide_dev_t *dev, int track,
+int cdrom_get_toc_entry (ide_drive_t *drive, int track,
                          struct atapi_toc_entry **ent)
 {
   int stat, ntracks;
   struct atapi_toc *toc;
 
   /* Make sure our saved TOC is valid. */
-  stat = cdrom_read_toc (dev);
+  stat = cdrom_read_toc (drive);
   if (stat) return stat;
 
-  toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc;
+  toc = drive->cdrom_info.toc;
 
   /* Check validity of requested track number. */
   ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
@@ -1774,25 +1718,25 @@
 }
 
 
-static int ide_cdrom_ioctl (ide_dev_t *dev, struct inode *inode,
+int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
                         struct file *file, unsigned int cmd, unsigned long arg)
 {
   switch (cmd)
     {
     case CDROMEJECT:
-      return cdrom_eject (dev, 0);
+      return cdrom_eject (drive, 0);
 
     case CDROMPAUSE:
-      return cdrom_pause (dev, 1);
+      return cdrom_pause (drive, 1);
 
     case CDROMRESUME:
-      return cdrom_pause (dev, 0);
+      return cdrom_pause (drive, 0);
 
     case CDROMSTART:
-      return cdrom_startstop (dev, 1);
+      return cdrom_startstop (drive, 1);
 
     case CDROMSTOP:
-      return cdrom_startstop (dev, 0);
+      return cdrom_startstop (drive, 0);
 
     case CDROMPLAYMSF:
       {
@@ -1811,7 +1755,7 @@
 
         if (lba_end <= lba_start) return -EINVAL;
 
-        return cdrom_play_lba_range (dev, lba_start, lba_end);
+        return cdrom_play_lba_range (drive, lba_start, lba_end);
       }
 
     /* Like just about every other Linux cdrom driver, we ignore the
@@ -1827,9 +1771,9 @@
 
         memcpy_fromfs (&ti, (void *) arg, sizeof(ti));
 
-        stat = cdrom_get_toc_entry (dev, ti.cdti_trk0, &first_toc);
+        stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc);
         if (stat) return stat;
-        stat = cdrom_get_toc_entry (dev, ti.cdti_trk1, &last_toc);
+        stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc);
         if (stat) return stat;
 
         if (ti.cdti_trk1 != CDROM_LEADOUT) ++last_toc;
@@ -1838,7 +1782,7 @@
 
         if (lba_end <= lba_start) return -EINVAL;
 
-        return cdrom_play_lba_range (dev, lba_start, lba_end);
+        return cdrom_play_lba_range (drive, lba_start, lba_end);
       }
 
     case CDROMREADTOCHDR:
@@ -1851,10 +1795,10 @@
         if (stat) return stat;
 
         /* Make sure our saved TOC is valid. */
-        stat = cdrom_read_toc (dev);
+        stat = cdrom_read_toc (drive);
         if (stat) return stat;
 
-        toc = cdrom_info[DEV_HWIF][dev->select.b.drive].toc;
+        toc = drive->cdrom_info.toc;
         tochdr.cdth_trk0 = toc->hdr.first_track;
         tochdr.cdth_trk1 = toc->hdr.last_track;
 
@@ -1876,7 +1820,7 @@
 
         memcpy_fromfs (&tocentry, (void *) arg, sizeof (tocentry));
 
-        stat = cdrom_get_toc_entry (dev, tocentry.cdte_track, &toce);
+        stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce);
         if (stat) return stat;
 
         tocentry.cdte_ctrl = toce->control;
@@ -1911,7 +1855,7 @@
 
         memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl));
 
-        stat = cdrom_read_subchannel (dev, buffer, sizeof (buffer));
+        stat = cdrom_read_subchannel (drive, buffer, sizeof (buffer));
         if (stat) return stat;
 
         abs_lba = *(int *)&buffer[8];
@@ -1956,9 +1900,9 @@
         if (stat) return stat;
         memcpy_fromfs (&volctrl, (void *) arg, sizeof (volctrl));
 
-        stat = cdrom_mode_sense (dev, 0x0e, 0, buffer, sizeof (buffer));
+        stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer));
         if (stat) return stat;
-        stat = cdrom_mode_sense (dev, 0x0e, 1, mask  , sizeof (buffer));
+        stat = cdrom_mode_sense (drive, 0x0e, 1, mask  , sizeof (buffer));
         if (stat) return stat;
 
         buffer[1] = buffer[2] = 0;
@@ -1968,7 +1912,7 @@
         buffer[21] = volctrl.channel2 & mask[21];
         buffer[23] = volctrl.channel3 & mask[23];
 
-        return cdrom_mode_select (dev, 0x0e, buffer, sizeof (buffer));
+        return cdrom_mode_select (drive, 0x0e, buffer, sizeof (buffer));
       }
 
 #ifdef TEST
@@ -1983,7 +1927,7 @@
         if (stat) return stat;
         memcpy_fromfs (&pc.c, (void *) arg, sizeof (pc.c));
 
-        return cdrom_queue_packet_command (dev, &pc);
+        return cdrom_queue_packet_command (drive, &pc);
       }
 
     case 0x1235:
@@ -1994,7 +1938,7 @@
         stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (reqbuf));
         if (stat) return stat;
 
-        stat = cdrom_request_sense (dev, &reqbuf);
+        stat = cdrom_request_sense (drive, &reqbuf);
 
         memcpy_tofs ((void *) arg, &reqbuf, sizeof (reqbuf));
 
@@ -2014,29 +1958,28 @@
  * Other driver requests (open, close, check media change).
  */
 
-static int cdrom_check_media_change (ide_dev_t *dev)
+int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
   int retval;
 
-  cdrom_check_status (dev);
+  cdrom_check_status (drive);
 
-  retval = CDROM_FLAGS (dev)->media_changed;
-  CDROM_FLAGS (dev)->media_changed = 0;
+  retval = CDROM_FLAGS (drive)->media_changed;
+  CDROM_FLAGS (drive)->media_changed = 0;
 
   return retval;
 }
 
 
-static int
-cdrom_open (struct inode *ip, struct file *fp, ide_dev_t *dev)
+int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
 {
   /* no write access */
   if (fp->f_mode & 2) return -EROFS;
 
 #if 0 /* With this, one cannot eject a disk with workman */
   /* If this is the first open, lock the door. */
-  if (dev->usage == 1)
-    (void) cdrom_lockdoor (dev, 1);
+  if (drive->usage == 1)
+    (void) cdrom_lockdoor (drive, 1);
 #endif
 
   /* Should check that there's a disk in the drive? */
@@ -2048,16 +1991,15 @@
  * Close down the device.  Invalidate all cached blocks.
  */
 
-static void
-cdrom_release (struct inode *inode, struct file *file, ide_dev_t *dev)
+void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *drive)
 {
-  if (dev->usage == 0)
+  if (drive->usage == 0)
     {
       invalidate_buffers (inode->i_rdev);
 
 #if 0
       /* Unlock the door. */
-      (void) cdrom_lockdoor (dev, 0);
+      (void) cdrom_lockdoor (drive, 0);
 #endif
     }
 }
@@ -2068,43 +2010,41 @@
  * Device initialization.
  */
 
-static void cdrom_setup (ide_dev_t *dev)
+void ide_cdrom_setup (ide_drive_t *drive)
 {
-  /* Just guess at capacity for now. */
-  ide_capacity[DEV_HWIF][dev->select.b.drive] = 0x1fffff;
-
-  ide_blksizes[DEV_HWIF][dev->select.b.drive << PARTN_BITS] = CD_FRAMESIZE;
+  blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] = CD_FRAMESIZE;
 
-  dev->special.all = 0;
+  drive->special.all = 0;
+  drive->ready_stat = 0;
 
-  CDROM_FLAGS (dev)->media_changed = 0;
-  CDROM_FLAGS (dev)->toc_valid     = 0;
+  CDROM_FLAGS (drive)->media_changed = 0;
+  CDROM_FLAGS (drive)->toc_valid     = 0;
 
-  CDROM_FLAGS (dev)->no_playaudio12 = 0;
-  CDROM_FLAGS (dev)->no_lba_toc = 0;
-  CDROM_FLAGS (dev)->msf_as_bcd = 0;
-  CDROM_FLAGS (dev)->drq_interrupt = ((dev->id->config & 0x0060) == 0x20);
+  CDROM_FLAGS (drive)->no_playaudio12 = 0;
+  CDROM_FLAGS (drive)->no_lba_toc = 0;
+  CDROM_FLAGS (drive)->msf_as_bcd = 0;
+  CDROM_FLAGS (drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20);
 
   /* Accommodate some broken drives... */
-  if (strcmp (dev->id->model, "CD220E") == 0)  /* Creative Labs */
-    CDROM_FLAGS (dev)->no_lba_toc = 1;
+  if (strcmp (drive->id->model, "CD220E") == 0)  /* Creative Labs */
+    CDROM_FLAGS (drive)->no_lba_toc = 1;
 
-  else if (strcmp (dev->id->model, "TO-ICSLYAL") == 0 ||  /* Acer CD525E */
-           strcmp (dev->id->model, "OTI-SCYLLA") == 0)
-    CDROM_FLAGS (dev)->no_lba_toc = 1;
+  else if (strcmp (drive->id->model, "TO-ICSLYAL") == 0 ||  /* Acer CD525E */
+           strcmp (drive->id->model, "OTI-SCYLLA") == 0)
+    CDROM_FLAGS (drive)->no_lba_toc = 1;
 
-  else if (strcmp (dev->id->model, "CDA26803I SE") == 0) /* Aztech */
+  else if (strcmp (drive->id->model, "CDA26803I SE") == 0) /* Aztech */
     {
-      CDROM_FLAGS (dev)->no_lba_toc = 1;
+      CDROM_FLAGS (drive)->no_lba_toc = 1;
 
       /* This drive _also_ does not implement PLAYAUDIO12 correctly. */
-      CDROM_FLAGS (dev)->no_playaudio12 = 1;
+      CDROM_FLAGS (drive)->no_playaudio12 = 1;
     }
 
-  cdrom_info[DEV_HWIF][dev->select.b.drive].toc               = NULL;
-  cdrom_info[DEV_HWIF][dev->select.b.drive].sector_buffer     = NULL;
-  cdrom_info[DEV_HWIF][dev->select.b.drive].sector_buffered   = 0;
-  cdrom_info[DEV_HWIF][dev->select.b.drive].nsectors_buffered = 0;
+  drive->cdrom_info.toc               = NULL;
+  drive->cdrom_info.sector_buffer     = NULL;
+  drive->cdrom_info.sector_buffered   = 0;
+  drive->cdrom_info.nsectors_buffered = 0;
 }
 
 
diff -u --recursive --new-file v1.3.18/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.18/linux/drivers/block/ide.c	Tue Aug  8 12:31:33 1995
+++ linux/drivers/block/ide.c	Tue Aug 15 20:05:34 1995
@@ -1,17 +1,19 @@
 /*
- *  linux/drivers/block/ide.c	Version 4.11  Jul 29, 1995
+ *  linux/drivers/block/ide.c	Version 5.03  Aug 13, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
 
 /*
- * This is the dual IDE interface driver, as evolved from hd.c.  
- * It supports up to two IDE interfaces, on one or two IRQs (usually 14 & 15).
+ * This is the multiple IDE interface driver, as evolved from hd.c.  
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary   i/f: ide0: major=3;  (hda)         minor=0, (hdb)         minor=64
- * Secondary i/f: ide1: major=22; (hdc or hd1a) minor=0, (hdd or hd1b) minor=64
- *
+ * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
+ * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
+ * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ * 
  *  From hd.c:
  *  |
  *  | It traverses the request-list, using interrupts to jump between functions.
@@ -60,7 +62,7 @@
  *			cdrom probe fixes, inspired by jprang@uni-duisburg.de
  *  Version 3.9		don't use LBA if lba_capacity looks funny
  *			correct the drive capacity calculations
- *			fix probing for old Seagates without HD_ALTSTATUS
+ *			fix probing for old Seagates without IDE_ALTSTATUS_REG
  *			fix byte-ordering for some NEC cdrom drives
  *  Version 3.10	disable multiple mode by default; was causing trouble
  *  Version 3.11	fix mis-identification of old WD disks as cdroms
@@ -72,9 +74,9 @@
  *			ignore INDEX bit when checking the ALTSTATUS reg
  *  Version 3.15	add SINGLE_THREADED flag for use with dual-CMD i/f
  *			ignore WRERR_STAT for non-write operations
- *			added VLB_SYNC support for DC-2000A & others,
+ *			added vlb_sync support for DC-2000A & others,
  *			 (incl. some Promise chips), courtesy of Frank Gockel
- *  Version 3.16	convert VLB_32BIT and VLB_SYNC into runtime flags
+ *  Version 3.16	convert vlb_32bit and vlb_sync into runtime flags
  *			add ioctls to get/set VLB flags (HDIO_[SG]ET_CHIPSET)
  *			rename SINGLE_THREADED to SUPPORT_SERIALIZE,
  *			add boot flag to "serialize" operation for CMD i/f
@@ -86,7 +88,7 @@
  *  Version 4.00	tidy up verify_area() calls - heiko@colossus.escape.de
  *			add flag to ignore WRERR_STAT for some drives
  *			 courtesy of David.H.West@um.cc.umich.edu
- *			assembly syntax tweak to VLB_SYNC
+ *			assembly syntax tweak to vlb_sync
  *			removeable drive support from scuba@cs.tu-berlin.de
  *			add transparent support for DiskManager-6.0x "Dynamic
  *			 Disk Overlay" (DDO), most of this in in genhd.c
@@ -95,312 +97,70 @@
  *			fix DM6:DDO support -- now works with LILO, fdisk, ...
  *			don't treat some naughty WD drives as removeable
  *  Version 4.11	updated DM6 support using info provided by OnTrack
+ *  Version 5.00	major overhaul, multmode setting fixed, vlb_sync fixed
+ *			added support for 3rd/4th/alternative IDE ports
+ *			created ide.h; ide-cd.c now compiles separate from ide.c
+ *			hopefully fixed infinite "unexpected_intr" from cdroms
+ *			zillions of other changes and restructuring
+ *			somehow reduced overall memory usage by several kB
+ *			probably slowed things down slightly, but worth it
+ *  Version 5.01	AT LAST!!  Finally understood why "unexpected_intr"
+ *			 was happening at various times/places:  whenever the
+ *			 ide-interface's ctl_port was used to "mask" the irq,
+ *			 it also would trigger an edge in the process of masking
+ *			 which would result in a self-inflicted interrupt!!
+ *			 (such a stupid way to build a hardware interrupt mask).
+ *			 This is now fixed (after a year of head-scratching).
+ *  Version 5.02	got rid of need for {enable,disable}_irq_list()
+ *  Version 5.03	tune-ups, comments, remove "busy wait" from drive resets
+ *			removed PROBE_FOR_IRQS option -- no longer needed
+ *			OOOPS!  fixed "bad access" bug for 2nd drive on an i/f
+ *
+ *  Driver compile-time options are in ide.h
  *
- *  To do:
- *	- add support for alternative IDE port addresses
- *	- refine the DiskManager-6.0x overlay support (special cases)
- *	- improved CMD support:  tech info is in my hands for 640B chip
- *	- special 32-bit controller-type detection & support
- *	- figure out how to support oddball "intelligent" caching cards
- *	- reverse-engineer 3/4 drive support on fancy "Promise" cards
+ *  To do, in likely order of completion:
+ *	- add in several updates from my email collection (soon folks!)
+ *	- add full support for Intel Triton chipset, including bus-mastered DMA
+ *	- improved CMD support:  handing this off to someone else
  *	- find someone to work on IDE *tape drive* support
  */
 
 #include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/malloc.h>
+#include <linux/types.h>
 #include <linux/string.h>
+#include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/major.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/major.h>
 #include <linux/blkdev.h>
-#include <asm/bitops.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <asm/byteorder.h>
 #include <asm/irq.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-
-/*****************************************************************************
- * IDE driver configuration options (play with these as desired):
- */
-#define REALLY_SLOW_IO			/* most systems can safely undef this */
-#include <asm/io.h>
-
-#ifdef __alpha__
-# ifndef SUPPORT_VLB_SYNC
-#  define SUPPORT_VLB_SYNC	0
-# endif
-#endif
-
-#undef	REALLY_FAST_IO			/* define if ide ports are perfect */
-#define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
-#ifndef SUPPORT_VLB_32BIT		/* 1 to support 32bit I/O on VLB */
-#define SUPPORT_VLB_32BIT	1	/* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_VLB_SYNC		/* 1 to support weird 32-bit chips */
-#define SUPPORT_VLB_SYNC	1	/* 0 to reduce kernel size */
-#endif
-#ifndef DISK_RECOVERY_TIME		/* off=0; on=access_delay_time */
-#define DISK_RECOVERY_TIME	0	/*  for hardware that needs it */
-#endif
-#ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
-#define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
-#endif
-#ifndef SUPPORT_TWO_INTERFACES		/* 1 to support one/two interfaces */
-#define SUPPORT_TWO_INTERFACES	1	/* 0 for a smaller, faster kernel */
-#endif
-#ifndef OPTIMIZE_IRQS			/* 1 for slightly faster code */
-#define OPTIMIZE_IRQS		1	/* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_SERIALIZE		/* 1 to support CMD dual interfaces */
-#define SUPPORT_SERIALIZE	1	/* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_SHARING_IRQ		/* 1 to allow two IDE i/f on one IRQ */
-#define SUPPORT_SHARING_IRQ	1	/* 0 to reduce kernel size */
-#endif
-#ifndef SUPPORT_DTC2278			/* 1 to support DTC2278 chipset */
-#define SUPPORT_DTC2278		1	/* 0 to reduce kernel size */
-#endif
-#ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
-#define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
-#endif
-#define PROBE_FOR_IRQS		1	/* 0 to force use of defaults below */
-#define DEFAULT_IDE0_IRQ	14	/* in case irq-probe fails */
-#define DEFAULT_IDE1_IRQ	15	/* in case irq-probe fails */
-
-/* IDE_DRIVE_CMD is used to implement many features of the hdparm utility */
-#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/
-
-/*
- *  "No user-serviceable parts" beyond this point  :)
- ******************************************************************************
- */
-
-/*
- * Need to change these elsewhere in the kernel (someday)
- */
-#ifndef IDE0_TIMER
-#define IDE0_TIMER		HD_TIMER
-#define IDE1_TIMER		HD_TIMER2
-#endif
-
-/*
- * Ensure that various configuration flags have compatible settings
- */
-#ifdef REALLY_SLOW_IO
-#undef REALLY_FAST_IO
-#endif
-#ifdef CONFIG_BLK_DEV_HD
-#undef  SUPPORT_TWO_INTERFACES
-#define SUPPORT_TWO_INTERFACES	0
-#endif	/* CONFIG_BLK_DEV_HD */
-
-#if SUPPORT_TWO_INTERFACES
-#define HWIF			hwif
-#define DEV_HWIF		(dev->hwif)
-#if SUPPORT_SERIALIZE
-#undef	SUPPORT_SHARING_IRQ
-#define	SUPPORT_SHARING_IRQ	1
-#endif
-#else
-#undef	SUPPORT_SERIALIZE
-#define SUPPORT_SERIALIZE		0
-#undef	OPTIMIZE_IRQS
-#define OPTIMIZE_IRQS		0
-#undef	SUPPORT_SHARING_IRQ
-#define SUPPORT_SHARING_IRQ	0
-#ifdef CONFIG_BLK_DEV_HD
-#define HWIF			1
-#else
-#define HWIF			0
-#endif	/* CONFIG_BLK_DEV_HD */
-#define DEV_HWIF		HWIF
-#endif	/* SUPPORT_TWO_INTERFACES */
 
-/*
- * Definitions for accessing IDE controller registers
- */
-typedef unsigned char		byte;	/* used everywhere */
-#define IDE_PORT(p,hwif) ((p)^((hwif)<<7)) /* IDE0: p^0x00 , IDE1: p^0x80 */
+#include "ide.h"
 
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)		outb((b),IDE_PORT(p,DEV_HWIF))
-#define IN_BYTE(p,hwif)		(byte)inb(IDE_PORT(p,hwif))
-#else
-#define OUT_BYTE(b,p)		outb_p((b),IDE_PORT(p,DEV_HWIF))
-#define IN_BYTE(p,hwif)		(byte)inb_p(IDE_PORT(p,hwif))
-#endif /* REALLY_FAST_IO */
-
-#if SUPPORT_VLB_32BIT
-#if SUPPORT_VLB_SYNC
-#define VLB_SYNC __asm__ __volatile__ ("pusha\n movl $0x01f2,%edx\n inb %dx,%al\n inb %dx,%al\n inb %dx,%al\n popa\n")
-#endif	/* SUPPORT_VLB_SYNC */
-#endif	/* SUPPORT_VLB_32BIT */
+static ide_hwif_t	ide_hwifs[MAX_HWIFS];		/* hwif info */
+static ide_hwgroup_t	*irq_to_hwgroup [16];
+static const byte	ide_hwif_to_major[MAX_HWIFS]   = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR};
+
+static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168};
+static const byte	default_irqs[MAX_HWIFS]     = {14, 15, 11, 10};
+static int		single_threaded = 0;	/* "serialize" option */
 
 #if SUPPORT_DTC2278
-static uint probe_dtc2278 = 0;
+static unsigned int	probe_dtc2278 = 0;
 #endif
 
-#define GET_ERR(hwif)		IN_BYTE(HD_ERROR,hwif)
-#define GET_STAT(hwif)		IN_BYTE(HD_STATUS,hwif)
-#define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
-#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
-#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
-#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
-#define DATA_READY		(DRIVE_READY | DRQ_STAT)
-
-/*
- * Some more useful definitions
- */
-#define BIOS_SECTORS(dev)	(dev->bios_head*dev->bios_sect*dev->bios_cyl)
-#define HD_NAME		"hd"	/* the same for both i/f;  see also genhd.c */
-#define PARTN_BITS	6	/* number of minor dev bits for partitions */
-#define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
-#define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */
-
-/*
- * Timeouts for various operations:
- */
-#define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
-#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
-#define WAIT_PIDENTIFY	(1*HZ)	/* 1sec   - should be less than 3ms (?) */
-#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
-#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
-
-/*
- * Now for the data we need to maintain per-device:  ide_dev_t
- *
- * For fast indexing, sizeof(ide_dev_t) = 32 = power_of_2;
- * Everything is carefully aligned on appropriate boundaries,
- *  and several fields are placed for optimal (gcc) access.
- *
- * Ugh.  Actually, we're two bytes over (34 bytes).. gotta fix this someday.
- */
-typedef enum {disk, cdrom} dev_type;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned set_geometry	: 1;	/* respecify drive geometry */
-		unsigned recalibrate	: 1;	/* seek to cyl 0      */
-		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned reserved	: 5;	/* unused */
-		} b;
-	} special_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned drive		: 1;	/* drive number */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-	} select_t;
-
-typedef struct {
-	byte     hwif;			/* first field gets very fast access */
-	byte     unmask;		/* pretty quick access to this also */
-	dev_type type		: 1;	/* disk or cdrom (or tape, floppy..) */
-	unsigned present	: 1;	/* drive is physically present */
-	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
-	unsigned keep_settings  : 1;	/* restore settings after drive reset */
-	unsigned busy		: 1;	/* mutex for ide_open, revalidate_.. */
-	unsigned vlb_32bit	: 1;	/* use 32bit in/out for data */
-	unsigned vlb_sync	: 1;	/* needed for some 32bit chip sets */
-	unsigned be_quiet	: 1;	/* supress "multiple mode" msg at boot */
-	special_t special;		/* special action flags */
-	select_t  select;		/* basic drive/head select reg value */
-	byte mult_count, chipset, bad_wstat;
-	byte usage, mult_req, wpcom, ctl;
-	byte head, sect, bios_head, bios_sect;
-	unsigned short cyl, bios_cyl;
-	const char *name;
-	struct hd_driveid *id;
-	struct wait_queue *wqueue;
-	byte sect0, removeable;
-	} ide_dev_t;
-
-/*
- * Stuff prefixed by "ide_" is indexed by the IDE interface number: 0 or 1
- */
-static const byte	ide_major    [2] = {IDE0_MAJOR,IDE1_MAJOR};
-static byte		ide_irq      [2] = {DEFAULT_IDE0_IRQ,DEFAULT_IDE1_IRQ};
-static struct hd_struct	ide_hd       [2][MAX_DRIVES<<PARTN_BITS] = {{{0,0},},};
-static int		ide_sizes    [2][MAX_DRIVES<<PARTN_BITS] = {{0,},};
-static int		ide_blksizes [2][MAX_DRIVES<<PARTN_BITS] = {{0,},};
-static unsigned long	ide_capacity [2][MAX_DRIVES] = {{0,},};
-static ide_dev_t	ide_dev      [2][MAX_DRIVES] = {{{0,},},};
-static ide_dev_t	*ide_cur_dev [2] = {NULL,NULL};
-static void		(*ide_handler[2])(ide_dev_t *) = {NULL,NULL};
-static struct request	*ide_cur_rq  [2] = {NULL,NULL}; /* current request */
-static struct request	ide_write_rq [2];  /* copy of *ide_cur_rq for WRITEs */
-static const int	ide_timer    [2] = {IDE0_TIMER,IDE1_TIMER};
-static const int	ide_timerbit[2] = {(1<<IDE0_TIMER),(1<<IDE1_TIMER)};
-static const char	*ide_name    [2] = {"ide0", "ide1"};
-static const char	*ide_devname [2][MAX_DRIVES] = /* for printk()'s */
-	{{HD_NAME "a", HD_NAME "b"}, {HD_NAME "c", HD_NAME "d"}};
-static const char	*unsupported = " not supported by this kernel\n";
-
-static byte		single_threaded    = 0;
-#if SUPPORT_SHARING_IRQ
-static byte		sharing_single_irq = 0;	/* for two i/f on one IRQ */
-static volatile byte 	current_hwif = 0;	/* for single_threaded==1 */
-#endif /* SUPPORT_SHARING_IRQ */
-
-/*
- * This structure is used to register our block device(s) with the kernel:
- */
-static void ide0_geninit(void), ide1_geninit(void);
-static struct gendisk	ide_gendisk  [2] =
-	{{
-		IDE0_MAJOR,	/* major number */	
-		HD_NAME,	/* same as below; see genhd.c before changing */
-		PARTN_BITS,	/* minor_shift (to extract minor number) */
-		1 << PARTN_BITS,/* max_p (number of partitions per real) */
-		MAX_DRIVES,	/* maximum number of real drives */
-		ide0_geninit,	/* init function */
-		ide_hd[0],	/* hd_struct */
-		ide_sizes[0],	/* block sizes */
-		0,		/* nr_real (number of drives present) */
-		ide_dev[0],	/* ptr to internal data structure */
-		NULL		/* next */
-	},{
-		IDE1_MAJOR,	/* major number */	
-		HD_NAME,	/* same as above; see genhd.c before changing */
-		PARTN_BITS,	/* minor_shift (to extract minor number) */
-		1 << PARTN_BITS,/* max_p (number of partitions per real) */
-		MAX_DRIVES,	/* maximum number of real drives */
-		ide1_geninit,	/* init function */
-		ide_hd[1],	/* hd_struct */
-		ide_sizes[1],	/* block sizes */
-		0,		/* nr_real (number of drives present) */
-		ide_dev[1],	/* ptr to internal data structure */
-		NULL		/* next */
-	}};
-
-/*
- * One final include file, which references some of the data/defns from above
- */
-#define IDE_DRIVER	/* "parameter" for blk.h */
-#include "blk.h"
-
+#if (DISK_RECOVERY_TIME > 0)
 /*
- * For really screwy hardware (hey, at least it *can* be used with Linux!)
+ * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * we can enforce a minimum delay time between successive operations.
  */
-#if (DISK_RECOVERY_TIME > 0)
-static unsigned long	ide_lastreq[] = {0,0}; /* completion time of last I/O */
-#define SET_DISK_RECOVERY_TIMER  ide_lastreq[DEV_HWIF] = read_timer();
 static unsigned long read_timer(void)
 {
 	unsigned long t, flags;
@@ -415,140 +175,344 @@
 	restore_flags(flags);
 	return (t - i);
 }
-#else
-#define SET_DISK_RECOVERY_TIMER	/* nothing */
-#endif /* DISK_RECOVERY_TIME */
 
-/*
- * The heart of the driver, referenced from lots of other routines:
- */
-static void do_request (byte hwif);
-#define DO_REQUEST {SET_DISK_RECOVERY_TIMER do_request(DEV_HWIF);}
+void ide_set_recovery_timer (ide_hwif_t *hwif)
+{
+	hwif->last_time = read_timer();
+}
+#endif /* DISK_RECOVERY_TIME */
 
 /*
- * This is a macro rather than an inline to permit better gcc code.
- * Caller MUST do sti() before invoking WAIT_STAT() (for jiffies to work).
+ * init_ide_data() sets reasonable default values into all fields
+ * of all instances of the hwifs and drives, but only on the first call.
+ * Subsequent calls have no effect (they don't wipe out anything).
  *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until WAIT_WORSTCASE is achieved, before timing out.
+ * This routine is normally called at driver initialization time,
+ * but may also be called MUCH earlier during kernel "command-line"
+ * parameter processing.  As such, we cannot depend on any other parts
+ * of the kernel (such as memory allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the
+ * ide_drive_t structs as needed, rather than always consuming memory
+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
  */
-#define WAIT_STAT(dev,good,bad,timeout,msg,label)			\
-{									\
-	byte stat;							\
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */	\
-	if (GET_STAT(DEV_HWIF) & BUSY_STAT) {				\
-		unsigned long timer = jiffies + timeout;		\
-		do {							\
-			if ((GET_STAT(DEV_HWIF) & BUSY_STAT) == 0)	\
-				break;					\
-		} while (timer > jiffies);				\
-	}								\
-	udelay(1);	/* spec allows 400ns for status to stabilize */	\
-	if (!OK_STAT(stat=GET_STAT(DEV_HWIF), good, bad)) {		\
-		ide_error(dev, msg " error", stat);			\
-		goto label;						\
-	}								\
+static void init_ide_data (void)
+{
+	unsigned int h, unit;
+	static unsigned long magic_cookie = 0x12345678;
+
+	if (magic_cookie != 0x12345678)
+		return;		/* already initialized */
+	magic_cookie = 0;
+
+	for (h = 0; h < 16; ++h)
+		 irq_to_hwgroup[h] = NULL;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+
+		hwif->noprobe	= (h > 1);
+		hwif->hwgroup	= NULL;
+		hwif->io_base	= default_io_base[h];
+		hwif->ctl_port	= hwif->io_base ? hwif->io_base + 0x206 : 0x000;
+#ifdef CONFIG_BLK_DEV_HD
+		if (hwif->io_base == HD_DATA)
+			hwif->noprobe = 1; /* may be overriden by ide_setup() */
+#endif /* CONFIG_BLK_DEV_HD */
+		hwif->gd	= NULL;
+		hwif->irq	= 0;  /* default_irqs[h] used when probe fails */
+		hwif->major	= ide_hwif_to_major[h];
+		hwif->name[0]	= 'i';
+		hwif->name[1]	= 'd';
+		hwif->name[2]	= 'e';
+		hwif->name[3]	= '0' + h;
+		hwif->name[4]	= '\0';
+		hwif->present	= 0;
+		hwif->next	= NULL;
+		hwif->reset_timeout = 0;
+
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+
+			/* bulk initialize drive info with zeros */
+			byte *p = ((byte *) drive) + sizeof(ide_drive_t);
+			do {
+				*--p = 0;
+			} while (p > (byte *) drive);
+
+			/* fill in any non-zero initial values */
+			drive->select.all		= (unit<<4)|0xa0;
+			drive->hwif			= hwif;
+			drive->ctl			= 0x08;
+			drive->ready_stat		= READY_STAT;
+			drive->bad_wstat		= BAD_W_STAT;
+			drive->special.b.recalibrate	= 1;
+			drive->special.b.set_geometry	= 1;
+			drive->name[0]			= 'h';
+			drive->name[1]			= 'd';
+			drive->name[2]			= 'a' + (h * MAX_DRIVES) + unit;
+		}
+	}
+}
+
+#ifdef __i386__
+#define VLB_SYNC 1
+
+static inline void do_vlb_sync (unsigned short port) {
+	unsigned int _v;
+	__asm__ __volatile__	(
+		"inb %w1,%b0\n\t"
+		"inb %w1,%b0\n\t"
+		"inb %w1,%b0"
+		: "=&a" (_v)		/* outputs */
+		: "d" (port)	);	/* inputs */
 }
+#endif	/* __i386__ */
 
 /*
  * This is used for all data transfers *from* the IDE interface
  */
-void input_ide_data (ide_dev_t *dev, void *buffer, uint wcount)
+void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
-#if SUPPORT_VLB_32BIT
-	if (dev->vlb_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (dev->vlb_sync) {
+	if (drive->vlb_32bit) {
+#ifdef VLB_SYNC
+		if (drive->vlb_sync) {
 			cli();
-			VLB_SYNC;
-			insl(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount);
-			if (dev->unmask)
+			do_vlb_sync(IDE_NSECTOR_REG);
+			insl(IDE_DATA_REG, buffer, wcount);
+			if (drive->unmask)
 				sti();
 		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount);
+#endif /* VLB_SYNC */
+			insl(IDE_DATA_REG, buffer, wcount);
 	} else
-#endif /* SUPPORT_VLB_32BIT */
-		insw(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount<<1);
+		insw(IDE_DATA_REG, buffer, wcount<<1);
 }
 
 /*
  * This is used for all data transfers *to* the IDE interface
  */
-void output_ide_data (ide_dev_t *dev, void *buffer, uint wcount)
+void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
 {
-#if SUPPORT_VLB_32BIT
-	if (dev->vlb_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (dev->vlb_sync) {
+	if (drive->vlb_32bit) {
+#ifdef VLB_SYNC
+		if (drive->vlb_sync) {
 			cli();
-			VLB_SYNC;
-			outsl(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount);
-			if (dev->unmask)
+			do_vlb_sync(IDE_NSECTOR_REG);
+			outsl(IDE_DATA_REG, buffer, wcount);
+			if (drive->unmask)
 				sti();
 		} else
-			outsl(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount);
-#endif /* SUPPORT_VLB_SYNC */
+#endif /* VLB_SYNC */
+			outsl(IDE_DATA_REG, buffer, wcount);
 	} else
-#endif /* SUPPORT_VLB_32BIT */
-		outsw(IDE_PORT(HD_DATA,DEV_HWIF), buffer, wcount<<1);
+		outsw(IDE_DATA_REG, buffer, wcount<<1);
+}
+
+/*
+ * This should get invoked any time we exit the driver to
+ * wait for an interrupt response from a drive.  handler() points
+ * at the appropriate code to handle the next interrupt, and a
+ * timer is started to prevent us from waiting forever in case
+ * something goes wrong (see the timer_expiry() handler later on).
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+#ifdef DEBUG
+	if (hwgroup->handler != NULL)
+		printk("%s: ide_set_handler: old handler not null\n", drive->name);
+#endif
+	hwgroup->handler       = handler;
+	hwgroup->timer.expires = jiffies + WAIT_CMD;
+	add_timer(&(hwgroup->timer));
+}
+
+/*
+ * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
+ * value for this drive (from its reported identification information).
+ *
+ * Returns:	1 if lba_capacity looks sensible
+ *		0 otherwise
+ */
+static int lba_capacity_is_ok (struct hd_driveid *id)
+{
+	unsigned long lba_sects   = id->lba_capacity;
+	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
+	unsigned long _10_percent = chs_sects / 10;
+
+	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
+	if ((lba_sects - chs_sects) < _10_percent)
+		return 1;	/* lba_capacity is good */
+
+	/* some drives have the word order reversed */
+	lba_sects = (lba_sects << 16) | (lba_sects >> 16);
+	if ((lba_sects - chs_sects) < _10_percent) {
+		id->lba_capacity = lba_sects;	/* fix it */
+		return 1;	/* lba_capacity is (now) good */
+	}
+	return 0;	/* lba_capacity value is bad */
 }
 
 /*
- * This should get invoked on every exit path from the driver.
+ * current_capacity() returns the capacity (in sectors) of a drive
+ * according to its current geometry/LBA settings.
  */
-static inline void start_ide_timer (byte hwif)
+static unsigned long current_capacity (ide_drive_t  *drive)
 {
-	if (ide_handler[HWIF] != NULL) {  	/* waiting for an irq? */
-		timer_table[ide_timer[HWIF]].expires = jiffies + WAIT_CMD;
-		timer_active |= ide_timerbit[HWIF];
+	struct hd_driveid *id = drive->id;
+	unsigned long capacity;
+
+	if (!drive->present)
+		return 0;
+	if (drive->media != disk)
+		return 0x1fffff;	/* cdrom */
+	/* Determine capacity, and use LBA if the drive properly supports it */
+	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
+		drive->select.b.lba = 1;
+		capacity = id->lba_capacity;
+	} else {
+		drive->select.b.lba = 0;
+		capacity = drive->cyl * drive->head * drive->sect;
 	}
+	return (capacity - drive->sect0);
 }
 
-static void do_ide_reset (ide_dev_t *dev)
+/*
+ * ide_geninit() is called exactly *once* for each major, from genhd.c,
+ * at the beginning of the initial partition check for the drives.
+ */
+static void ide_geninit (struct gendisk *gd)
 {
-	byte tmp;
-	unsigned long timer, flags;
+	unsigned int unit;
+	ide_hwif_t *hwif = gd->real_devices;
 
-	save_flags(flags);
-	sti();
-	for (tmp = 0; tmp < MAX_DRIVES; tmp++) {
-		ide_dev_t *rdev = &ide_dev[DEV_HWIF][tmp];
-		rdev->special.b.set_geometry = 1;
-		rdev->special.b.recalibrate  = 1;
-		rdev->special.b.set_multmode = 0;
-		if (OK_TO_RESET_CONTROLLER)
-			rdev->mult_count = 0;
-		if (!rdev->keep_settings) {
-			rdev->mult_req = 0;
-			rdev->unmask = 0;
+	for (unit = 0; unit < gd->nr_real; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		drive->part[0].nr_sects = current_capacity(drive);
+		if (!drive->present || drive->media != disk) {
+			drive->part[0].start_sect = -1; /* skip partition check */
 		}
-		if (rdev->mult_req != rdev->mult_count)
-			rdev->special.b.set_multmode = 1;
 	}
+	/*
+	 * The partition check in genhd.c needs this string to identify
+	 * our minor devices by name for display purposes.
+	 * Note that doing this will prevent us from working correctly
+	 * if ever called a second time for this major (never happens).
+	 */
+	gd->real_devices = hwif->drives[0].name;  /* name of first drive */
+}
 
-#if OK_TO_RESET_CONTROLLER
-	cli();
-	OUT_BYTE(dev->ctl|6,HD_CMD);	/* set nIEN, set SRST */
-	udelay(10);			/* more than enough time */
-	OUT_BYTE(dev->ctl|2,HD_CMD);	/* clear SRST */
-	udelay(10);			/* more than enough time */
-	sti();				/* needed for jiffies */
-	for (timer = jiffies + WAIT_WORSTCASE; timer > jiffies;) {
-		if ((GET_STAT(DEV_HWIF) & BUSY_STAT) == 0)
+/*
+ * ide_alloc(): memory allocation for using during driver initialization.
+ */
+static unsigned long init_mem_start = 0uL;	/* used by init routines */
+
+static inline void *ide_alloc (unsigned long bytecount)
+{
+	unsigned long p = init_mem_start;
+	if (!p) panic("ide: ide_alloc() not valid now\n");
+	init_mem_start += (bytecount + 3uL) & ~3uL;
+	return (void *) p;
+}
+
+/*
+ * init_gendisk() (as opposed to ide_geninit) is called for each major device,
+ * after probing for drives, to allocate partition tables and other data
+ * structures needed for the routines in genhd.c.  ide_geninit() gets called
+ * somewhat later, during the partition check.
+ */
+static void init_gendisk (ide_hwif_t *hwif)
+{
+	struct gendisk *gd;
+	unsigned int unit, units, minors;
+	int *bs;
+
+	/* figure out maximum drive number on the interface */
+	for (units = MAX_DRIVES; units > 0; --units) {
+		if (hwif->drives[units-1].present)
 			break;
 	}
-	printk("%s: do_ide_reset: ", ide_name[DEV_HWIF]);
-	/* ATAPI devices usually do *not* assert READY after a reset */
-	if (!OK_STAT(tmp=GET_STAT(DEV_HWIF), 0, BUSY_STAT)) {
-		printk("timed-out, status=0x%02x\n", tmp);
+	minors    = units * (1<<PARTN_BITS);
+	gd        = ide_alloc(sizeof(struct gendisk));
+	gd->sizes = ide_alloc(minors * sizeof(int));
+	gd->part  = ide_alloc(minors * sizeof(struct hd_struct));
+	bs        = ide_alloc(minors*sizeof(int));
+
+	/* cdroms and msdos f/s are examples of non-1024 blocksizes */
+	blksize_size[hwif->major] = bs;
+	for (unit = 0; unit < minors; ++unit)
+		*bs++ = BLOCK_SIZE;
+
+	for (unit = 0; unit < units; ++unit)
+		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
+
+	gd->major	= hwif->major;		/* our major device number */
+	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
+	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
+	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
+	gd->max_nr	= units;		/* max num real drives */
+	gd->nr_real	= units;		/* current num real drives */
+	gd->init	= ide_geninit;		/* initialization function */
+	gd->real_devices= hwif;			/* ptr to internal data */
+
+	gd->next = gendisk_head;		/* link new major into list */
+	hwif->gd = gendisk_head = gd;
+}
+
+static void unexpected_intr (int, ide_hwgroup_t *);
+/*
+ * reset_ihandler() is a dummy interrupt handler which we install during
+ * an ide interface reset operation.  This prevents other devices in the
+ * same hwgroup from being serviced while we play around with shared resources.
+ * If it ever gets invoked, we call unexpected_intr(), which treats the event
+ * the same as a timer_expiry().
+ */
+static void reset_ihandler (ide_drive_t *drive)
+{
+	unexpected_intr (HWIF(drive)->irq, HWGROUP(drive));
+}
+
+/*
+ * start_reset_timer() sets up a timer event for 50ms in the future,
+ * to poll for completion of an ide reset operation (no interrupt to help us).
+ */
+static void start_reset_timer (ide_hwif_t *hwif)
+{
+	ide_hwgroup_t *hwgroup = hwif->hwgroup;
+
+	hwif->reset_timeout = jiffies + WAIT_WORSTCASE;	/* max waiting time */
+	hwgroup->handler = &reset_ihandler;		/* dummy irq handler */
+	hwgroup->timer.expires = jiffies + (HZ/20);	/* polling interval */
+	add_timer(&(hwgroup->timer));
+}
+
+/*
+ * reset_handler() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not not responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ *
+ * Returns 1 if waiting for another 50ms, returns 0 otherwise.
+ */
+static int reset_handler (ide_hwgroup_t *hwgroup)
+{
+	ide_hwif_t *hwif = hwgroup->hwif;
+	ide_drive_t *drive = hwgroup->drive;
+	byte tmp;
+
+	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
+		if (jiffies < hwif->reset_timeout) {
+			start_reset_timer (hwif);
+			return 1;
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
 	} else  {
-		if ((tmp = GET_ERR(DEV_HWIF)) == 1)
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = GET_ERR()) == 1)
 			printk("success\n");
 		else {
-			printk("%s: ", ide_devname[DEV_HWIF][0]);
+			printk("master: ");
 			switch (tmp & 0x7f) {
 				case 1: printk("passed");
 					break;
@@ -563,51 +527,114 @@
 				default:printk("error (0x%02x?)", tmp);
 			}
 			if (tmp & 0x80)
-				printk("; %s: error", ide_devname[DEV_HWIF][1]);
+				printk("; slave: failed");
 			printk("\n");
 		}
 	}
+	hwgroup->handler = NULL;	/* allow new requests to be processed */
+	hwif->reset_timeout = 0;	/* signal end of ide reset operation */
+	return 0;
+}
+
+/*
+ * ide_do_reset() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism (not handled here),
+ * which allows them to be individually reset without clobbering other
+ * devices on the same interface.  ide-cd.c will handle those separately.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+static int ide_do_reset (ide_drive_t *drive)
+{
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	save_flags(flags);
+	cli();		/* Why ? */
+
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *rdrive = &hwif->drives[unit];
+		rdrive->special.b.set_geometry = 1;
+		rdrive->special.b.recalibrate  = 1;
+		rdrive->special.b.set_multmode = 0;
+		if (OK_TO_RESET_CONTROLLER)
+			rdrive->mult_count = 0;
+		if (!rdrive->keep_settings) {
+			rdrive->mult_req = 0;
+			rdrive->unmask = 0;
+		}
+		if (rdrive->mult_req != rdrive->mult_count)
+			rdrive->special.b.set_multmode = 1;
+	}
+
+#if OK_TO_RESET_CONTROLLER
+	/*
+	 * Note that we also set nIEN while resetting the device,
+	 * to mask unwanted interrupts from the interface during the reset.
+	 * However, due to the design of PC hardware, this will cause an
+	 * immediate interrupt due to the edge transition it produces.
+	 * This single interrupt gives us a "fast poll" for drives that
+	 * recover from reset very quickly, saving us the first 50ms wait time.
+	 */
+	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set nIEN and SRST */
+	udelay(5);			/* more than enough time */
+	OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
+	hwif->reset_timeout = jiffies + WAIT_WORSTCASE;
+	start_reset_timer (hwif);	/* begin periodic polling */
 #endif	/* OK_TO_RESET_CONTROLLER */
-	restore_flags(flags);
+
+	restore_flags (flags);
+	return OK_TO_RESET_CONTROLLER;	/* 1 = we are waiting, 0 = done */
 }
 
 /*
  * Clean up after success/failure of an explicit (ioctl) drive cmd
  */
-static void end_drive_cmd (ide_dev_t *dev, byte stat, byte err)
+static void end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
 {
 	unsigned long flags;
-	struct request *rq = ide_cur_rq[DEV_HWIF];
+	struct request *rq = HWGROUP(drive)->rq;
 	byte *args = (byte *) rq->buffer;
 
 	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 	if (args) {
 		args[0] = stat;
 		args[1] = err;
-		args[2] = IN_BYTE(HD_NSECTOR,DEV_HWIF);
+		args[2] = IN_BYTE(IDE_NSECTOR_REG);
 	}
 	save_flags(flags);
 	cli();
 	up(rq->sem);
-	ide_cur_rq[DEV_HWIF] = NULL;
+	HWGROUP(drive)->rq = NULL;
 	restore_flags(flags);
 }
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-static byte dump_status (byte hwif, const char *msg, byte stat)
+byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
 {
 	unsigned long flags;
 	byte err = 0;
-	ide_dev_t *dev = ide_cur_dev[HWIF];
-	const char *name = dev ? dev->name : ide_name[HWIF];
 
 	save_flags (flags);
 	sti();
-	printk("%s: %s: status=0x%02x", name, msg, stat);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
-	if (dev && dev->type == disk) {
+	if (drive->media == disk) {
 		printk(" { ");
 		if (stat & BUSY_STAT)
 			printk("Busy ");
@@ -625,10 +652,10 @@
 #endif	/* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR(HWIF);
-		printk("%s: %s: error=0x%02x", name, msg, err);
+		err = GET_ERR();
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (dev && dev->type == disk) {
+		if (drive->media == disk) {
 			printk(" { ");
 			if (err & BBD_ERR)	printk("BadSector ");
 			if (err & ECC_ERR)	printk("UncorrectableError ");
@@ -638,22 +665,22 @@
 			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
 			printk("}");
 			if (err & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
-				byte cur = IN_BYTE(HD_CURRENT,HWIF);
+				byte cur = IN_BYTE(IDE_SELECT_REG);
 				if (cur & 0x40) {	/* using LBA? */
 					printk(", LBAsect=%ld", (unsigned long)
 					 ((cur&0xf)<<24)
-					 |(IN_BYTE(HD_HCYL,HWIF)<<16)
-					 |(IN_BYTE(HD_LCYL,HWIF)<<8)
-					 | IN_BYTE(HD_SECTOR,HWIF));
+					 |(IN_BYTE(IDE_HCYL_REG)<<16)
+					 |(IN_BYTE(IDE_LCYL_REG)<<8)
+					 | IN_BYTE(IDE_SECTOR_REG));
 				} else {
 					printk(", CHS=%d/%d/%d",
-					 (IN_BYTE(HD_HCYL,HWIF)<<8) +
-					  IN_BYTE(HD_LCYL,HWIF),
+					 (IN_BYTE(IDE_HCYL_REG)<<8) +
+					  IN_BYTE(IDE_LCYL_REG),
 					  cur & 0xf,
-					  IN_BYTE(HD_SECTOR,HWIF));
+					  IN_BYTE(IDE_SECTOR_REG));
 				}
-				if (ide_cur_rq[HWIF])
-					printk(", sector=%ld", ide_cur_rq[HWIF]->sector);
+				if (HWGROUP(drive)->rq)
+					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
 			}
 		}
 #endif	/* FANCY_STATUS_DUMPS */
@@ -664,81 +691,103 @@
 }
 
 /*
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive.  Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+static void try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	while (i > 0) {
+		unsigned long buffer[16];
+		unsigned int wcount = (i > 16) ? 16 : i;
+		i -= wcount;
+		ide_input_data (drive, buffer, wcount);
+	}
+}
+
+/*
  * ide_error() takes action based on the error returned by the controller.
+ *
+ * Returns 1 if an ide reset operation has been initiated, in which case
+ * the caller MUST simply return from the driver (through however many levels).
+ * Returns 0 otherwise.
  */
-#define ERROR_MAX	8	/* Max read/write errors per sector */
-#define ERROR_RESET	3	/* Reset controller every 4th retry */
-#define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
-static void ide_error (ide_dev_t *dev, const char *msg, byte stat)
+int ide_error (ide_drive_t *drive, const char *msg, byte stat)
 {
 	struct request *rq;
 	byte err;
 
-	err = dump_status(DEV_HWIF, msg, stat);
-	if ((rq = ide_cur_rq[DEV_HWIF]) == NULL || dev == NULL)
-		return;
+	err = ide_dump_status(drive, msg, stat);
+	if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
+		return 0;
 #ifdef IDE_DRIVE_CMD
 	if (rq->cmd == IDE_DRIVE_CMD) {	/* never retry an explicit DRIVE_CMD */
-		end_drive_cmd(dev, stat, err);
-		return;
+		end_drive_cmd(drive, stat, err);
+		return 0;
 	}
 #endif	/* IDE_DRIVE_CMD */
 	if (stat & BUSY_STAT) {		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
-		if (dev->type == disk && (stat & ERR_STAT)) {
+		if (drive->media == disk && (stat & ERR_STAT)) {
 			/* err has different meaning on cdrom */
 			if (err & BBD_ERR)		/* retries won't help this! */
 				rq->errors = ERROR_MAX;
 			else if (err & TRK0_ERR)	/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
 		}
-		if ((stat & DRQ_STAT) && rq->cmd == READ) {
-			int i = dev->mult_count ? dev->mult_count<<8 : 1<<8;
-			while (i-- > 0)			/* try to flush data */
-				(void) IN_BYTE(HD_DATA, dev->hwif);
-		}
+		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+			try_to_flush_leftover_data(drive);
 	}
-	if (GET_STAT(dev->hwif) & (BUSY_STAT|DRQ_STAT))
+	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
 		rq->errors |= ERROR_RESET;	/* Mmmm.. timing problem */
 
 	if (rq->errors >= ERROR_MAX)
-		end_request(0, DEV_HWIF);
+		ide_end_request(0, HWGROUP(drive));
 	else {
-		if ((rq->errors & ERROR_RESET) == ERROR_RESET)
-			do_ide_reset(dev);
-		else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-			dev->special.b.recalibrate = 1;
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		} else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
 		++rq->errors;
 	}
+	return 0;
 }
 
-static void read_intr (ide_dev_t *dev)
+/*
+ * read_intr() is the handler for disk read/multread interrupts
+ */
+static void read_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
 	unsigned int msect, nsect;
 	struct request *rq;
 
-	if (!OK_STAT(stat=GET_STAT(DEV_HWIF),DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 		sti();
-		ide_error(dev, "read_intr", stat);
-		DO_REQUEST;
+		if (!ide_error(drive, "read_intr", stat))
+			IDE_DO_REQUEST;
 		return;
 	}
-	msect = dev->mult_count;
+	msect = drive->mult_count;
 read_next:
-	rq = ide_cur_rq[DEV_HWIF];
+	rq = HWGROUP(drive)->rq;
 	if (msect) {
 		if ((nsect = rq->current_nr_sectors) > msect)
 			nsect = msect;
 		msect -= nsect;
 	} else
 		nsect = 1;
-	input_ide_data(dev, rq->buffer, nsect * SECTOR_WORDS);
+	ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
-		dev->name, rq->sector, rq->sector+nsect-1,
+		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
 	rq->sector += nsect;
@@ -746,27 +795,29 @@
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if ((rq->current_nr_sectors -= nsect) <= 0)
-		end_request(1, DEV_HWIF);
+		ide_end_request(1, HWGROUP(drive));
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_handler[DEV_HWIF] = &read_intr;
+		ide_set_handler (drive, &read_intr);
 		return;
 	}
-	/* (void) GET_STAT(DEV_HWIF); */	/* hd.c did this */
-	DO_REQUEST;
+	IDE_DO_REQUEST;
 }
 
-static void write_intr (ide_dev_t *dev)
+/*
+ * write_intr() is the handler for disk write interrupts
+ */
+static void write_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
-	struct request *rq = ide_cur_rq[DEV_HWIF];
+	struct request *rq = HWGROUP(drive)->rq;
 
-	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) {
+	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
-			dev->name, rq->sector, (unsigned long) rq->buffer,
+			drive->name, rq->sector, (unsigned long) rq->buffer,
 			rq->nr_sectors-1);
 #endif
 		if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
@@ -776,25 +827,29 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (rq->current_nr_sectors <= 0)
-				end_request(1, DEV_HWIF);
+				ide_end_request(1, HWGROUP(drive));
 			if (i > 0) {
-				ide_handler[DEV_HWIF] = &write_intr;
-				output_ide_data(dev, rq->buffer, SECTOR_WORDS);
+				ide_output_data (drive, rq->buffer, SECTOR_WORDS);
+				ide_set_handler (drive, &write_intr);
 				return;
 			}
-			DO_REQUEST;
+			IDE_DO_REQUEST;
 			return;
 		}
 	}
 	sti();
-	ide_error(dev, "write_intr", stat);
-	DO_REQUEST;
+	if (!ide_error(drive, "write_intr", stat))
+		IDE_DO_REQUEST;
 }
 
-static void multwrite (ide_dev_t *dev)
+/*
+ * multwrite() transfers a block of one or more sectors of data to a drive
+ * as part of a disk multwrite operation.  
+ */
+static void multwrite (ide_drive_t *drive)
 {
-	struct request *rq = &ide_write_rq[DEV_HWIF];
-	unsigned int mcount = dev->mult_count;
+	struct request *rq = &HWGROUP(drive)->wrq;
+	unsigned int mcount = drive->mult_count;
 
 	do {
 		unsigned int nsect = rq->current_nr_sectors;
@@ -802,10 +857,10 @@
 			nsect = mcount;
 		mcount -= nsect;
 
-		output_ide_data(dev, rq->buffer, nsect<<7);
+		ide_output_data(drive, rq->buffer, nsect<<7);
 #ifdef DEBUG
 		printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n",
-			dev->name, rq->sector, (unsigned long) rq->buffer,
+			drive->name, rq->sector, (unsigned long) rq->buffer,
 			nsect, rq->nr_sectors - nsect);
 #endif
 		if ((rq->nr_sectors -= nsect) <= 0)
@@ -815,7 +870,7 @@
 				rq->current_nr_sectors = rq->bh->b_size>>9;
 				rq->buffer             = rq->bh->b_data;
 			} else {
-				panic("%s: buffer list corrupted\n", dev->name);
+				panic("%s: buffer list corrupted\n", drive->name);
 				break;
 			}
 		} else {
@@ -824,415 +879,410 @@
 	} while (mcount);
 }
 
-static void multwrite_intr (ide_dev_t *dev)
+/*
+ * write_intr() is the handler for disk multwrite interrupts
+ */
+static void multwrite_intr (ide_drive_t *drive)
 {
 	byte stat;
 	int i;
-	struct request *rq = &ide_write_rq[DEV_HWIF];
+	struct request *rq = &HWGROUP(drive)->wrq;
 
-	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) {
+	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			if (rq->nr_sectors) {
-				if (dev->mult_count)
-					multwrite(dev);
-				ide_handler[DEV_HWIF] = &multwrite_intr;
+				multwrite(drive);
+				ide_set_handler (drive, &multwrite_intr);
 				return;
 			}
 		} else {
 			if (!rq->nr_sectors) {	/* all done? */
-				rq = ide_cur_rq[DEV_HWIF];
+				rq = HWGROUP(drive)->rq;
 				for (i = rq->nr_sectors; i > 0;){
 					i -= rq->current_nr_sectors;
-					end_request(1, DEV_HWIF);
+					ide_end_request(1, HWGROUP(drive));
 				}
-				DO_REQUEST;
+				IDE_DO_REQUEST;
 				return;
 			}
 		}
 	}
 	sti();
-	ide_error(dev, "multwrite_intr", stat);
-	DO_REQUEST;
+	if (!ide_error(drive, "multwrite_intr", stat))
+		IDE_DO_REQUEST;
 }
 
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-static inline void ide_cmd(ide_dev_t *dev, byte cmd, byte nsect,
-				void (*handler)(ide_dev_t *dev))
+static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
-	OUT_BYTE(dev->ctl,HD_CMD);
-	OUT_BYTE(nsect,HD_NSECTOR);
-	OUT_BYTE(cmd,HD_COMMAND);
-	ide_handler[DEV_HWIF] = handler;
+	ide_set_handler (drive, handler);
+	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE(nsect,IDE_NSECTOR_REG);
+	OUT_BYTE(cmd,IDE_COMMAND_REG);
 }
 
-static void set_multmode_intr (ide_dev_t *dev)
+static void set_multmode_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT(DEV_HWIF);
+	byte stat = GET_STAT();
 
 	sti();
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT)) {
-		dev->mult_req = dev->mult_count = 0;
-		dev->special.b.recalibrate = 1;
-		(void) dump_status(DEV_HWIF, "set_multmode", stat);
-	} else if (!dev->be_quiet) {
-		if ((dev->mult_count = dev->mult_req))
-			printk ("  %s: enabled %d-sector multiple mode\n",
-				dev->name, dev->mult_count);
-		else
-			printk ("  %s: multiple mode turned off\n", dev->name);
+	if (OK_STAT(stat,READY_STAT,BAD_STAT)) {
+		drive->mult_count = drive->mult_req;
+	} else {
+		drive->mult_req = drive->mult_count = 0;
+		drive->special.b.recalibrate = 1;
+		(void) ide_dump_status(drive, "set_multmode", stat);
 	}
-	dev->be_quiet = 0;
-	DO_REQUEST;
+	IDE_DO_REQUEST;
 }
 
-static void set_geometry_intr (ide_dev_t *dev)
+static void set_geometry_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT(DEV_HWIF);
+	byte stat = GET_STAT();
 
 	sti();
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(dev, "set_geometry_intr", stat);
-	DO_REQUEST;
+		if (ide_error(drive, "set_geometry_intr", stat))
+			return;
+	IDE_DO_REQUEST;
 }
 
-static void recal_intr (ide_dev_t *dev)
+static void recal_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT(DEV_HWIF);
+	byte stat = GET_STAT();
 
 	sti();
 	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(dev, "recal_intr", stat);
-	DO_REQUEST;
+		if (ide_error(drive, "recal_intr", stat))
+			return;
+	IDE_DO_REQUEST;
 }
 
-static void drive_cmd_intr (ide_dev_t *dev)
+static void drive_cmd_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT(DEV_HWIF);
+	byte stat = GET_STAT();
 
 	sti();
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		ide_error(dev, "drive_cmd", stat); /* calls end_drive_cmd() */
-	else
-		end_drive_cmd (dev, stat, GET_ERR(DEV_HWIF));
-	DO_REQUEST;
-}
-
-static void timer_expiry (byte hwif)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	if (ide_handler[HWIF] == NULL || (timer_active & ide_timerbit[HWIF])) {
-		/* The drive must have responded just as the timer expired */
-		sti();
-		printk("%s: marginal timeout\n", ide_name[HWIF]);
-	} else {
-		ide_handler[HWIF] = NULL;
-		disable_irq(ide_irq[HWIF]);
-#if SUPPORT_SERIALIZE
-		if (single_threaded && ide_irq[HWIF] != ide_irq[HWIF^1])
-			disable_irq(ide_irq[HWIF^1]);
-#endif /* SUPPORT_SERIALIZE */
-		sti();
-		ide_error(ide_cur_dev[HWIF], "timeout", GET_STAT(HWIF));
-		do_request(HWIF);
-#if SUPPORT_SHARING_IRQ
-		if (single_threaded)	/* this line is indeed necessary */
-			hwif = current_hwif;
-#endif /* SUPPORT_SHARING_IRQ */
-		cli();
-		start_ide_timer(HWIF);
-		enable_irq(ide_irq[HWIF]);
-#if SUPPORT_SERIALIZE
-		if (single_threaded && ide_irq[HWIF] != ide_irq[HWIF^1])
-			enable_irq(ide_irq[HWIF^1]);
-#endif /* SUPPORT_SERIALIZE */
-	}
-	restore_flags(flags);
-}
-
-static void ide0_timer_expiry (void)		/* invoked from sched.c */
-{
-	timer_expiry (0);
-}
-
-static void ide1_timer_expiry (void)		/* invoked from sched.c */
-{
-	timer_expiry (1);
+	if (OK_STAT(stat,READY_STAT,BAD_STAT))
+		end_drive_cmd (drive, stat, GET_ERR());
+	else if (ide_error(drive, "drive_cmd", stat)) /* calls end_drive_cmd */
+		return;
+	IDE_DO_REQUEST;
 }
 
-static int do_special (ide_dev_t *dev)
+static void do_special (ide_drive_t *drive)
 {
-	special_t *s = &dev->special;
+	special_t *s = &drive->special;
 #ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", dev->name, s->all);
+	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
 	if (s->b.set_geometry) {
 		s->b.set_geometry = 0;
-		if (dev->type == disk) {
-			OUT_BYTE(dev->sect,HD_SECTOR);
-			OUT_BYTE(dev->cyl,HD_LCYL);
-			OUT_BYTE(dev->cyl>>8,HD_HCYL);
-			OUT_BYTE(((dev->head-1)|dev->select.all)&0xBF,HD_CURRENT);
-			ide_cmd(dev, WIN_SPECIFY, dev->sect, &set_geometry_intr);
+		if (drive->media == disk) {
+			OUT_BYTE(drive->sect,IDE_SECTOR_REG);
+			OUT_BYTE(drive->cyl,IDE_LCYL_REG);
+			OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
+			OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);
+			ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);
 		}
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		if (dev->type == disk)
-			ide_cmd(dev,WIN_RESTORE,dev->sect,&recal_intr);
-	} else if (s->b.set_multmode) {
-		if (dev->type == disk) {
-			if (dev->id && dev->mult_req > dev->id->max_multsect)
-				dev->mult_req = dev->id->max_multsect;
-			ide_cmd(dev,WIN_SETMULT,dev->mult_req,&set_multmode_intr);
-		} else {
-			dev->mult_req = 0;
-			printk("%s: multmode not supported by this device\n", dev->name);
+		if (drive->media == disk) {
+			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
 		}
+	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
-	} else {
-		if (s->all) {
-			printk("%s: bad special flag: 0x%02x\n", dev->name, s->all);
-			s->all = 0;
-		}
+		if (drive->media == disk) {
+			if (drive->id && drive->mult_req > drive->id->max_multsect)
+				drive->mult_req = drive->id->max_multsect;
+			ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
+		} else
+			drive->mult_req = 0;
+	} else if (s->all) {
+		s->all = 0;
+		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
 	}
-	return (ide_handler[DEV_HWIF] == NULL) ? 1 : 0;
 }
 
-#ifdef CONFIG_BLK_DEV_IDECD
-static byte wait_stat (ide_dev_t *dev, byte good, byte bad, unsigned long timeout)
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error()
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until WAIT_WORSTCASE is achieved, before timing out.
+ */
+int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
 {
-	unsigned long flags;
+	byte stat;
 
-	save_flags(flags);
-	sti();
-	WAIT_STAT(dev, good, bad, timeout, "status", error);
-	restore_flags(flags);
-	return 0;
-error:
-	restore_flags(flags);
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if (GET_STAT() & BUSY_STAT) {
+		unsigned long flags;
+		save_flags(flags);
+		sti();
+		timeout += jiffies;
+		while (GET_STAT() & BUSY_STAT) {
+			if (jiffies > timeout) {
+				restore_flags(flags);
+				(void) ide_error(drive, "status timeout", GET_STAT());
+				return 1;
+			}
+		}
+		restore_flags(flags);
+		udelay(1);	/* spec allows 400ns for status to stabilize */
+	}
+	if (OK_STAT(stat=GET_STAT(), good, bad))
+		return 0;
+	(void) ide_error(drive, "status error", stat);
 	return 1;
 }
 
-#include "ide-cd.c"
-#endif	/* CONFIG_BLK_DEV_IDECD */
-
-static inline int do_rw_disk (ide_dev_t *dev, struct request *rq, unsigned long block)
+static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	OUT_BYTE(dev->ctl,HD_CMD);
-	OUT_BYTE(rq->nr_sectors,HD_NSECTOR);
-	if (dev->select.b.lba) {
+	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+	OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
+	if (drive->select.b.lba) {
 #ifdef DEBUG
 		printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
-			dev->name, (rq->cmd==READ)?"read":"writ", 
+			drive->name, (rq->cmd==READ)?"read":"writ", 
 			block, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
-		OUT_BYTE(block,HD_SECTOR);
-		OUT_BYTE(block>>=8,HD_LCYL);
-		OUT_BYTE(block>>=8,HD_HCYL);
-		OUT_BYTE(((block>>8)&0x0f)|dev->select.all,HD_CURRENT);
+		OUT_BYTE(block,IDE_SECTOR_REG);
+		OUT_BYTE(block>>=8,IDE_LCYL_REG);
+		OUT_BYTE(block>>=8,IDE_HCYL_REG);
+		OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
 	} else {
 		unsigned int sect,head,cyl,track;
-		track = block / dev->sect;
-		sect  = block % dev->sect + 1;
-		OUT_BYTE(sect,HD_SECTOR);
-		head  = track % dev->head;
-		cyl   = track / dev->head;
-		OUT_BYTE(cyl,HD_LCYL);
-		OUT_BYTE(cyl>>8,HD_HCYL);
-		OUT_BYTE(head|dev->select.all,HD_CURRENT);
+		track = block / drive->sect;
+		sect  = block % drive->sect + 1;
+		OUT_BYTE(sect,IDE_SECTOR_REG);
+		head  = track % drive->head;
+		cyl   = track / drive->head;
+		OUT_BYTE(cyl,IDE_LCYL_REG);
+		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
+		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
 		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
-			dev->name, (rq->cmd==READ)?"read":"writ", cyl,
+			drive->name, (rq->cmd==READ)?"read":"writ", cyl,
 			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
 	}
 	if (rq->cmd == READ) {
-		OUT_BYTE(dev->mult_count ? WIN_MULTREAD : WIN_READ, HD_COMMAND);
-		ide_handler[DEV_HWIF] = &read_intr;
-		return 0;
+		ide_set_handler(drive, &read_intr);
+		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+		return;
 	}
 	if (rq->cmd == WRITE) {
-		OUT_BYTE(dev->wpcom,HD_PRECOMP);	/* for ancient drives */
-		OUT_BYTE(dev->mult_count ? WIN_MULTWRITE : WIN_WRITE, HD_COMMAND);
-		WAIT_STAT(dev,DATA_READY,dev->bad_wstat,WAIT_DRQ,"DRQ",error);
-		if (!dev->unmask)
+		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+			printk("%s: no DRQ after issuing %s\n", drive->name,
+				drive->mult_count ? "MULTWRITE" : "WRITE");
+			return;
+		}
+		if (!drive->unmask)
 			cli();
-		if (dev->mult_count) {
-			ide_write_rq[DEV_HWIF] = *rq; /* scratchpad */
-			multwrite(dev);
-			ide_handler[DEV_HWIF] = &multwrite_intr;
+		if (drive->mult_count) {
+			HWGROUP(drive)->wrq = *rq; /* scratchpad */
+			ide_set_handler (drive, &multwrite_intr);
+			multwrite(drive);
 		} else {
-			output_ide_data(dev, rq->buffer, SECTOR_WORDS);
-			ide_handler[DEV_HWIF] = &write_intr;
+			ide_set_handler (drive, &write_intr);
+			ide_output_data(drive, rq->buffer, SECTOR_WORDS);
 		}
-		return 0;
+		return;
 	}
 #ifdef IDE_DRIVE_CMD
 	if (rq->cmd == IDE_DRIVE_CMD) {
 		byte *args = rq->buffer;
 		if (args) {
-			OUT_BYTE(args[2],HD_FEATURE);
-			ide_cmd(dev, args[0], args[1], &drive_cmd_intr);
 			printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n",
-			 dev->name, args[0], args[1], args[2]);
-			return 0;
+			 drive->name, args[0], args[1], args[2]);
+			OUT_BYTE(args[2],IDE_FEATURE_REG);
+			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+			return;
 		} else {
 #ifdef DEBUG
-			printk("%s: DRIVE_CMD (null)\n", dev->name);
+			printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
-			end_drive_cmd(dev,GET_STAT(DEV_HWIF),GET_ERR(DEV_HWIF));
-			return 1;
+			end_drive_cmd(drive, GET_STAT(), GET_ERR());
+			return;
 		}
 	}
 #endif	/* IDE_DRIVE_CMD */
-	printk("%s: bad command: %d\n", dev->name, rq->cmd);
-	end_request(0, DEV_HWIF);
-error:
-	return 1;
+	printk("%s: bad command: %d\n", drive->name, rq->cmd);
+	ide_end_request(0, HWGROUP(drive));
 }
 
-/*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is always masked before entry, and
- * (b) the timeout-interrupt is always disabled before entry.
- *
- * Interrupts are still masked (by default) whenever we are exchanging
- * data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O.  For devices which don't suffer from
- * this problem (most don't), the ide_dev[][].unmask flag can be set to permit
- * other interrupts during data/cmd transfers by using the "hdparm" utility.
- */
-static void do_request (byte hwif)
+static inline void do_request (ide_hwif_t *hwif, struct request *rq)
 {
-	unsigned int minor, drive;
+	unsigned int minor, unit;
 	unsigned long block, blockend;
-	struct request *rq;
-	ide_dev_t *dev;
-repeat:
+	ide_drive_t *drive;
+
 	sti();
-#if SUPPORT_SHARING_IRQ
-	current_hwif = hwif;	/* used *only* when single_threaded==1 */
-#endif /* SUPPORT_SHARING_IRQ */
-	if ((rq = ide_cur_rq[HWIF]) == NULL) {
-		rq = blk_dev[ide_major[HWIF]].current_request;
-		if ((rq == NULL) || (rq->dev < 0)) {
-#if SUPPORT_SHARING_IRQ
-			if (single_threaded) {
-				if (sharing_single_irq && (dev = ide_cur_dev[hwif])) /* disable irq */
-					OUT_BYTE(dev->ctl|2,HD_CMD);
-				rq = blk_dev[ide_major[hwif^=1]].current_request;
-				if ((rq != NULL) && (rq->dev >= 0))
-					goto repeat;
-			}
-#endif /* SUPPORT_SHARING_IRQ */
-			return;
-		}
-		blk_dev[ide_major[HWIF]].current_request = rq->next;
-		ide_cur_rq[HWIF] = rq;
-	}
 #ifdef DEBUG
-	printk("%s: do_request: current=0x%08lx\n",ide_name[HWIF],(unsigned long)rq);
+	printk("%s: ide_do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
 #endif
 	minor = MINOR(rq->dev);
-	drive = minor >> PARTN_BITS;
-	ide_cur_dev[HWIF] = dev = &ide_dev[HWIF][drive];
-	if ((MAJOR(rq->dev) != ide_major[HWIF]) || (drive >= MAX_DRIVES)) {
-		printk("%s: bad device number: 0x%04x\n", ide_name[HWIF], rq->dev);
-		end_request(0, HWIF);
-		goto repeat;
+	unit = minor >> PARTN_BITS;
+	if (MAJOR(rq->dev) != hwif->major || unit >= MAX_DRIVES) {
+		printk("%s: bad device number: 0x%04x\n", hwif->name, rq->dev);
+		goto kill_rq;
 	}
+	drive = &hwif->drives[unit];
 	if (rq->bh && !rq->bh->b_lock) {
-		printk("%s: block not locked\n", ide_name[HWIF]);
-		end_request(0, HWIF);
-		goto repeat;
+		printk("%s: block not locked\n", drive->name);
+		goto kill_rq;
 	}
 	block    = rq->sector;
 	blockend = block + rq->nr_sectors;
-	if ((blockend < block) || (blockend > ide_hd[HWIF][minor].nr_sects)) {
+	if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
 		printk("%s: bad access: block=%ld, count=%ld\n",
-			dev->name, block, rq->nr_sectors);
-		end_request(0, HWIF);
-		goto repeat;
+			drive->name, block, rq->nr_sectors);
+		goto kill_rq;
 	}
-	block += ide_hd[HWIF][minor].start_sect + dev->sect0;
+	block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
 #if (DISK_RECOVERY_TIME > 0)
-	while ((read_timer() - ide_lastreq[HWIF]) < DISK_RECOVERY_TIME);
+	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
-	OUT_BYTE(dev->select.all,HD_CURRENT);
-#ifdef CONFIG_BLK_DEV_IDECD
-	WAIT_STAT(dev, (dev->type == cdrom) ? 0 : READY_STAT,
-		BUSY_STAT|DRQ_STAT, WAIT_READY, "DRDY", repeat);
-#else
-	WAIT_STAT(dev, READY_STAT, BUSY_STAT|DRQ_STAT, WAIT_READY, "DRDY", repeat);
-#endif	/* CONFIG_BLK_DEV_IDECD */
-	if (!dev->special.all) {
-#ifdef CONFIG_BLK_DEV_IDECD
-		if (dev->type == disk) {
-#endif	/* CONFIG_BLK_DEV_IDECD */
-			if (do_rw_disk(dev, rq, block))
-				goto repeat;
+	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
+	if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+		printk("%s: drive not ready for command\n", drive->name);
+		return;
+
+	}
+	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
+	if (!drive->special.all) {
 #ifdef CONFIG_BLK_DEV_IDECD
-		} else {
-			if (do_rw_cdrom(dev, block))
-				goto repeat;
+		switch (drive->media) {
+			case disk:
+				do_rw_disk (drive, rq, block);
+				return;
+			case cdrom:
+				ide_do_rw_cdrom (drive, block);
+				return;
+			default:
+				printk("%s: media type %d not supported\n",
+					drive->name, drive->media);
+				goto kill_rq;
 		}
-#endif	/* CONFIG_BLK_DEV_IDECD */
-	} else {
-		if (do_special(dev))
-			goto repeat;
+#else
+		do_rw_disk (drive, rq, block); /* simpler and faster */
+		return;
+#endif;
 	}
+	do_special(drive);
+	return;
+kill_rq:
+	ide_end_request(0, hwif->hwgroup);
 }
 
 /*
- * This is a macro rather than an inline function to
- * prevent gcc from over-optimizing accesses to current_hwif,
- * which may have a different value on exit from do_request().
+ * The driver enables interrupts as much as possible.  In order to do this,
+ * (a) the device-interrupt is always masked before entry, and
+ * (b) the timeout-interrupt is always disabled before entry.
+ *
+ * If we enter here from, say irq14, and then start a new request for irq15,
+ * (possible with "serialize" option) then we cannot ensure that we exit
+ * before the irq15 hits us. So, we must be careful not to let this bother us.
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O.  For devices which don't suffer from
+ * this problem (most don't), the unmask flag can be set using the "hdparm"
+ * utility, to permit other interrupts during data/cmd transfers.
  */
-#define DO_IDE_REQUEST(hwif)			\
-{						\
-	if (ide_handler[hwif] == NULL) {	\
-		disable_irq(ide_irq[hwif]);	\
-		if (single_threaded && ide_irq[hwif] != ide_irq[hwif^1]) \
-			disable_irq(ide_irq[hwif^1]); \
-		do_request(hwif);		\
-		cli();				\
-		start_ide_timer(hwif);		\
-		enable_irq(ide_irq[hwif]);	\
-		if (single_threaded && ide_irq[hwif] != ide_irq[hwif^1]) \
-			enable_irq(ide_irq[hwif^1]); \
-	}					\
+void ide_do_request (ide_hwgroup_t *hwgroup)
+{
+	cli();	/* paranoia */
+
+	if (hwgroup->handler != NULL) {
+		printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
+		return;
+	}
+	do {
+		ide_hwif_t *hwif = hwgroup->hwif;
+		struct request *rq;
+		if ((rq = hwgroup->rq) == NULL) {
+			hwgroup->drive = NULL;	/* paranoia */
+			do {
+				rq = blk_dev[hwif->major].current_request;
+				if (rq != NULL && rq->dev != -1)
+					goto got_rq;
+			} while ((hwif = hwif->next) != hwgroup->hwif);
+			return;		/* no work left for this hwgroup */
+		}
+	got_rq:
+		blk_dev[hwif->major].current_request = rq->next;
+		do_request(hwgroup->hwif = hwif, hwgroup->rq = rq);
+		cli();
+	} while (hwgroup->handler == NULL);
+}
+
+static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
+{
+	if (hwgroup->handler == NULL) {
+		ide_hwif_t *hgif = hwgroup->hwif;
+		ide_hwif_t *hwif = hgif;
+		do {
+			disable_irq(hwif->irq);
+		} while ((hwif = hwif->next) != hgif);
+		ide_do_request (hwgroup);
+		do {
+			enable_irq(hwif->irq);
+		} while ((hwif = hwif->next) != hgif);
+	}
 }
 
-#if SUPPORT_TWO_INTERFACES
 static void do_ide0_request (void)	/* invoked with cli() */
 {
-	DO_IDE_REQUEST(0);
+	do_hwgroup_request (ide_hwifs[0].hwgroup);
 }
 
 static void do_ide1_request (void)	/* invoked with cli() */
 {
-	DO_IDE_REQUEST(1);
+	do_hwgroup_request (ide_hwifs[1].hwgroup);
 }
-#else
-#define do_ide1_request	do_ide0_request
-static void do_ide0_request (void)	/* invoked with cli() */
+
+static void do_ide2_request (void)	/* invoked with cli() */
 {
-	DO_IDE_REQUEST(HWIF);
+	do_hwgroup_request (ide_hwifs[2].hwgroup);
 }
-#endif	/* SUPPORT_TWO_INTERFACES */
 
-#if SUPPORT_SHARING_IRQ
-static void do_shared_request (void)	/* invoked with cli() */
+static void do_ide3_request (void)	/* invoked with cli() */
 {
-	DO_IDE_REQUEST(current_hwif);
+	do_hwgroup_request (ide_hwifs[3].hwgroup);
+}
+
+static void timer_expiry (unsigned long data)
+{
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+	ide_drive_t   *drive   = hwgroup->drive;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if (hwgroup->hwif->reset_timeout != 0) { /* ide reset in progress? */
+		if (!reset_handler(hwgroup))
+			do_hwgroup_request (hwgroup);
+	} else if (hwgroup->handler == NULL) {	 /* not waiting for anything? */
+		sti(); /* drive must have responded just as the timer expired */
+		printk("%s: marginal timeout\n", drive->name);
+	} else {				 /* drive not responding */
+		hwgroup->handler = NULL;
+		if (!ide_error(drive, "irq timeout", GET_STAT()))
+			do_hwgroup_request (hwgroup);
+	}
+	restore_flags(flags);
 }
-#endif /* SUPPORT_SHARING_IRQ */
 
 /*
  * There's nothing really useful we can do with an unexpected interrupt,
@@ -1244,135 +1294,177 @@
  * drive enters "idle", "standby", or "sleep" mode, so if the status looks
  * "good", we just ignore the interrupt completely.
  */
-static void unexpected_intr (byte hwif)
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
 	byte stat;
+	unsigned int unit;
+	ide_hwif_t *hwif = hwgroup->hwif;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
 
-	if (!OK_STAT(stat=GET_STAT(HWIF), DRIVE_READY, BAD_STAT))
-		(void) dump_status(HWIF, "unexpected_intr", stat);
-	outb_p(2,IDE_PORT(HD_CMD,hwif));	/* disable device irq */
-#if SUPPORT_SHARING_IRQ
-	if (single_threaded && ide_irq[hwif] == ide_irq[hwif^1]) {
-		if (!OK_STAT(stat=GET_STAT(hwif^1), DRIVE_READY, BAD_STAT))
-			(void) dump_status(hwif^1, "unexpected_intr", stat);
-		outb_p(2,IDE_PORT(HD_CMD,hwif^1));	/* disable device irq */
+	/*
+	 * check for ide reset in progress
+	 */
+	if (hwif->reset_timeout != 0) {
+		if (!reset_handler(hwgroup))
+			do_hwgroup_request (hwgroup);
+		restore_flags(flags);
+		return;
 	}
-#endif /* SUPPORT_SHARING_IRQ */
+
+	/*
+	 * handle the unexpected interrupt
+	 */
+	do {
+		if (hwif->irq == irq) {
+			for (unit = 0; unit < MAX_DRIVES; ++unit) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (!drive->present)
+					continue;
+				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT))
+					(void) ide_dump_status(drive, "unexpected_intr", stat);
+				if ((stat & DRQ_STAT))
+					try_to_flush_leftover_data(drive);
+			}
+		}
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+	restore_flags(flags);
 }
 
 /*
- * This is a macro rather than an inline function to
- * prevent gcc from over-optimizing accesses to current_hwif,
- * which may have a different value on exit from handler().
+ * entry point for all interrupts, caller does cli() for us
  */
-#define IDE_INTR(hwif)					\
-{							\
-	ide_dev_t *dev;					\
-	void (*handler)(ide_dev_t *);			\
-							\
-	timer_active &= ~ide_timerbit[hwif];		\
-	if ((handler = ide_handler[hwif]) != NULL) {	\
-		ide_handler[hwif] = NULL;		\
-		dev = ide_cur_dev[hwif];		\
-		if (dev->unmask)			\
-			sti();				\
-		handler(dev);				\
-	} else						\
-		unexpected_intr(hwif);			\
-	cli();						\
-}
-
-#if SUPPORT_SERIALIZE
-/* entry point for all interrupts when single_threaded==1 */
-static void ide_seq_intr (int irq, struct pt_regs *regs)
+static void ide_intr (int irq, struct pt_regs *regs)
 {
-	byte hwif = (irq != ide_irq[0]);
-	IDE_INTR(HWIF);
-	start_ide_timer(current_hwif);
+	ide_hwgroup_t  *hwgroup = irq_to_hwgroup[irq];
+	ide_handler_t  *handler;
+	if (irq != hwgroup->hwif->irq) {
+#ifdef DEBUG
+		printk("ide_intr: expected ira %d, got irq %d instead\n",
+			hwgroup->hwif->irq, irq);
+#endif
+		unexpected_intr(irq, hwgroup);
+	} else if ((handler = hwgroup->handler) != NULL) {
+		ide_drive_t *drive = hwgroup->drive;
+		hwgroup->handler = NULL;
+		del_timer(&(hwgroup->timer));
+		if (drive->unmask)
+			sti();
+		handler(drive);
+	} else {
+		sti();
+		unexpected_intr(irq, hwgroup);
+	}
+	cli();
 }
-#endif /* SUPPORT_SERIALIZE */
-
-#if OPTIMIZE_IRQS
 
-/* entry point for all interrupts on ide0 when single_threaded==0 */
-static void ide0_intr (int irq, struct pt_regs *regs)
+static ide_drive_t *get_info_ptr (int i_rdev)
 {
-	IDE_INTR(0);
-	start_ide_timer(0);
-}
+	int		major = MAJOR(i_rdev);
+	unsigned int	h;
 
-/* entry point for all interrupts on ide1 when single_threaded==0 */
-static void ide1_intr (int irq, struct pt_regs *regs)
-{
-	IDE_INTR(1);
-	start_ide_timer(1);
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t  *hwif = &ide_hwifs[h];
+		if (hwif->present && major == hwif->major) {
+			unsigned unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (drive->present)
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
 }
 
-#else	/* OPTIMIZE_IRQS */
-
-#define ide0_intr	ide_intr
-#define ide1_intr	ide_intr
-
-/* entry point for all interrupts when single_threaded==0 */
-static void ide_intr (int irq, struct pt_regs *regs)
+#ifdef IDE_DRIVE_CMD
+static int write_fs_long (unsigned long useraddr, long value)
 {
-#if SUPPORT_TWO_INTERFACES
-	byte hwif = (irq != ide_irq[0]);
-#endif	/* SUPPORT_TWO_INTERFACES */
-	IDE_INTR(HWIF);
-	start_ide_timer(HWIF);
-}
-
-#endif	/* OPTIMIZE_IRQS */
+	int err;
 
-#if SUPPORT_SHARING_IRQ
-/* entry point for all interrupts on ide0/ide1 when sharing_single_irq==1 */
-static void ide_shared_intr (int irq, struct pt_regs * regs)
-{
-	IDE_INTR(current_hwif);
-	start_ide_timer(current_hwif);
+	if (NULL == (long *)useraddr)
+		return -EINVAL;
+	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
+		return err;
+	put_user((unsigned)value, (long *) useraddr);
+	return 0;
 }
-#endif /* SUPPORT_SHARING_IRQ */
 
-static ide_dev_t *get_info_ptr (int i_rdev)
+/*
+ * This function issues a specific IDE drive command onto the
+ * tail of the request queue, and waits for it to be completed.
+ * If arg is NULL, it goes through all the motions,
+ * but without actually sending a command to the drive.
+ */
+static int do_drive_cmd(int rdev, char *args)
 {
-	unsigned int drive = DEVICE_NR(i_rdev);
-	ide_dev_t *dev;
+	unsigned long flags;
+	unsigned int major = MAJOR(rdev);
+	struct request rq, *cur_rq;
+	struct blk_dev_struct *bdev;
+	struct semaphore sem = MUTEX_LOCKED;
 
-	if (drive < MAX_DRIVES) {
-		switch (MAJOR(i_rdev)) {
-#ifndef CONFIG_BLK_DEV_HD
-			case IDE0_MAJOR:	dev = &ide_dev[0][drive];
-						if (dev->present) return dev;
-						break;
-#endif /* CONFIG_BLK_DEV_HD */
-			case IDE1_MAJOR:	dev = &ide_dev[1][drive];
-						if (dev->present) return dev;
-						break;
-		}
+	/* build up a special request, and add it to the queue */
+	rq.buffer = args;
+	rq.cmd = IDE_DRIVE_CMD;
+	rq.errors = 0;
+	rq.sector = 0;
+	rq.nr_sectors = 0;
+	rq.current_nr_sectors = 0;
+	rq.sem = &sem;
+	rq.bh = NULL;
+	rq.bhtail = NULL;
+	rq.next = NULL;
+	rq.dev = rdev;
+	bdev = &blk_dev[major];
+
+	save_flags(flags);
+	cli();
+	cur_rq = bdev->current_request;
+	if (cur_rq == NULL) {			/* empty request list? */
+		bdev->current_request = &rq;	/* service ours immediately */
+		bdev->request_fn();
+	} else {
+		while (cur_rq->next != NULL)	/* find end of request list */
+			cur_rq = cur_rq->next;
+		cur_rq->next = &rq;		/* add rq to the end */
 	}
-	return NULL;
+
+	down(&sem);				/* wait for it to be serviced */
+	restore_flags(flags);
+	return rq.errors ? -EIO : 0;		/* return -EIO if errors */
 }
+#endif	/* IDE_DRIVE_CMD */
 
 static int ide_open(struct inode * inode, struct file * filp)
 {
-	ide_dev_t *dev;
+	ide_drive_t *drive;
 	unsigned long flags;
 
-	if ((dev = get_info_ptr(inode->i_rdev)) == NULL)
+	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 	save_flags(flags);
 	cli();
-	while (dev->busy)
-		sleep_on(&dev->wqueue);
-	dev->usage++;
+	while (drive->busy)
+		sleep_on(&drive->wqueue);
+	drive->usage++;
 	restore_flags(flags);
 #ifdef CONFIG_BLK_DEV_IDECD
-	if (dev->type == cdrom)
-		return cdrom_open (inode, filp, dev);
+	if (drive->media == cdrom)
+		return ide_cdrom_open (inode, filp, drive);
 #endif	/* CONFIG_BLK_DEV_IDECD */
-	if (dev->removeable)	/* for disks */
+	if (drive->removeable) {
 		check_disk_change(inode->i_rdev);
+#ifdef IDE_DRIVE_CMD
+		{
+		byte door_lock[] = {WIN_DOORLOCK,0,0,0};
+		do_drive_cmd(inode->i_rdev, door_lock);
+		}
+#endif /* IDE_DRIVE_CMD */
+	}
 	return 0;
 }
 
@@ -1382,15 +1474,25 @@
  */
 static void ide_release(struct inode * inode, struct file * file)
 {
-	ide_dev_t *dev;
+	ide_drive_t *drive;
 
-	if ((dev = get_info_ptr(inode->i_rdev)) != NULL) {
+	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
 		sync_dev(inode->i_rdev);
-		dev->usage--;
+		drive->usage--;
 #ifdef CONFIG_BLK_DEV_IDECD
-		if (dev->type == cdrom)
-			cdrom_release (inode, file, dev);
+		if (drive->media == cdrom)
+			ide_cdrom_release (inode, file, drive);
+		else
 #endif	/* CONFIG_BLK_DEV_IDECD */
+		if (drive->removeable) {
+			invalidate_buffers(inode->i_rdev);
+#ifdef IDE_DRIVE_CMD
+			{
+			byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
+			do_drive_cmd(inode->i_rdev, door_unlock);
+			}
+#endif /* IDE_DRIVE_CMD */
+		}
 	}
 }
 
@@ -1404,100 +1506,37 @@
  */
 static int revalidate_disk(dev_t  i_rdev)
 {
-	unsigned int i, major, start, drive = DEVICE_NR(i_rdev);
-	ide_dev_t *dev;
-	struct gendisk *gd;
+	ide_drive_t *drive;
+	unsigned int p, major, minor;
 	long flags;
 
-	if ((dev = get_info_ptr(i_rdev)) == NULL)
+	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
 
+	major = MAJOR(i_rdev);
+	minor = drive->select.b.unit << PARTN_BITS;
 	save_flags(flags);
 	cli();
-	if (dev->busy || (dev->usage > 1)) {
+	if (drive->busy || (drive->usage > 1)) {
 		restore_flags(flags);
 		return -EBUSY;
 	};
-	dev->busy = 1;
+	drive->busy = 1;
 	restore_flags(flags);
 
-	gd    = &ide_gendisk[DEV_HWIF];
-	major = ide_major[DEV_HWIF] << 8;
-	start = drive << PARTN_BITS;
-
-	for (i = 0; i < (1<<PARTN_BITS); i++) {
-		unsigned int minor = start + i;
-		sync_dev           (major | minor);
-		invalidate_inodes  (major | minor);
-		invalidate_buffers (major | minor);
-		gd->part[minor].start_sect = 0;
-		gd->part[minor].nr_sects   = 0;
+	for (p = 0; p < (1<<PARTN_BITS); ++p) {
+		sync_dev           (major | (minor + p));
+		invalidate_inodes  (major | (minor + p));
+		invalidate_buffers (major | (minor + p));
+		drive->part[p].start_sect = 0;
+		drive->part[p].nr_sects   = 0;
 	};
 
-	gd->part[start].nr_sects = ide_capacity[DEV_HWIF][drive];
-	resetup_one_dev(gd, drive);
-
-	dev->busy = 0;
-	wake_up(&dev->wqueue);
-	return 0;
-}
-
-#ifdef IDE_DRIVE_CMD
-/*
- * This function issues a specific IDE drive command onto the
- * tail of the request queue, and waits for it to be completed.
- * If arg is NULL, it goes through all the motions,
- * but without actually sending a command to the drive.
- */
-static int do_drive_cmd(int dev, char *args)
-{
-	unsigned long flags;
-	unsigned int major = MAJOR(dev);
-	struct request rq, *cur_rq;
-	struct blk_dev_struct *bdev;
-	struct semaphore sem = MUTEX_LOCKED;
-
-	/* build up a special request, and add it to the queue */
-	rq.buffer = args;
-	rq.cmd = IDE_DRIVE_CMD;
-	rq.errors = 0;
-	rq.sector = 0;
-	rq.nr_sectors = 0;
-	rq.current_nr_sectors = 0;
-	rq.sem = &sem;
-	rq.bh = NULL;
-	rq.bhtail = NULL;
-	rq.next = NULL;
-	rq.dev = dev;
-	bdev = &blk_dev[major];
-
-	save_flags(flags);
-	cli();
-	cur_rq = bdev->current_request;
-	if (cur_rq == NULL) {			/* empty request list? */
-		bdev->current_request = &rq;	/* service ours immediately */
-		bdev->request_fn();
-	} else {
-		while (cur_rq->next != NULL)	/* find end of request list */
-			cur_rq = cur_rq->next;
-		cur_rq->next = &rq;		/* add rq to the end */
-	}
-
-	down(&sem);				/* wait for it to be serviced */
-	restore_flags(flags);
-	return rq.errors ? -EIO : 0;		/* return -EIO if errors */
-}
-#endif	/* IDE_DRIVE_CMD */
-
-static int write_fs_long (unsigned long useraddr, long value)
-{
-	int err;
+	drive->part[0].nr_sects = current_capacity(drive);
+	resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
 
-	if (NULL == (long *)useraddr)
-		return -EINVAL;
-	if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
-		return err;
-	put_user((unsigned)value, (long *) useraddr);
+	drive->busy = 0;
+	wake_up(&drive->wqueue);
 	return 0;
 }
 
@@ -1506,26 +1545,23 @@
 {
 	struct hd_geometry *loc = (struct hd_geometry *) arg;
 	int err;
-	ide_dev_t *dev;
+	ide_drive_t *drive;
 	unsigned long flags;
 
 	if (!inode || !inode->i_rdev)
 		return -EINVAL;
-	if ((dev = get_info_ptr(inode->i_rdev)) == NULL)
+	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 	switch (cmd) {
 		case HDIO_GETGEO:
-			if (!loc || dev->type != disk) return -EINVAL;
+			if (!loc || drive->media != disk) return -EINVAL;
 			err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 			if (err) return err;
-			put_user(dev->bios_head,
-				(char *) &loc->heads);
-			put_user(dev->bios_sect,
-				(char *) &loc->sectors);
-			put_user(dev->bios_cyl,
-				(short *) &loc->cylinders);
-			put_user((unsigned)ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].start_sect,
-				(long *) &loc->start);
+			put_user(drive->bios_head, (byte *) &loc->heads);
+			put_user(drive->bios_sect, (byte *) &loc->sectors);
+			put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders);
+			put_user((unsigned)drive->part[inode->i_rdev&PARTN_MASK].start_sect,
+				(unsigned long *) &loc->start);
 			return 0;
 
 		case BLKFLSBUF:
@@ -1544,34 +1580,34 @@
 			return write_fs_long(arg, read_ahead[MAJOR(inode->i_rdev)]);
 
          	case BLKGETSIZE:   /* Return device size */
-			return write_fs_long(arg, ide_hd[DEV_HWIF][MINOR(inode->i_rdev)].nr_sects);
+			return write_fs_long(arg, drive->part[inode->i_rdev&PARTN_MASK].nr_sects);
 		case BLKRRPART: /* Re-read partition tables */
 			return revalidate_disk(inode->i_rdev);
 
                 case HDIO_GET_KEEPSETTINGS:
-			return write_fs_long(arg, dev->keep_settings);
+			return write_fs_long(arg, drive->keep_settings);
 
                 case HDIO_GET_UNMASKINTR:
-			return write_fs_long(arg, dev->unmask);
+			return write_fs_long(arg, drive->unmask);
 
                 case HDIO_GET_CHIPSET:
-			return write_fs_long(arg, dev->chipset);
+			return write_fs_long(arg, drive->chipset);
 
                 case HDIO_GET_MULTCOUNT:
-			return write_fs_long(arg, dev->mult_count);
+			return write_fs_long(arg, drive->mult_count);
 
 		case HDIO_GET_IDENTITY:
-			if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK))
+			if (!arg || (inode->i_rdev & PARTN_MASK))
 				return -EINVAL;
-			if (dev->id == NULL)
+			if (drive->id == NULL)
 				return -ENOMSG;
-			err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*dev->id));
+			err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
 			if (err) return err;
-			memcpy_tofs((char *)arg, (char *)dev->id, sizeof(*dev->id));
+			memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
 			return 0;
 
 			case HDIO_GET_NOWERR:
-			return write_fs_long(arg, dev->bad_wstat == BAD_R_STAT);
+			return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
 
 		case HDIO_SET_KEEPSETTINGS:
 		case HDIO_SET_UNMASKINTR:
@@ -1581,24 +1617,28 @@
 		case HDIO_SET_CHIPSET:
 			if (!suser())
 				return -EACCES;
-			if ((MINOR(inode->i_rdev) & PARTN_MASK))
+			if ((inode->i_rdev & PARTN_MASK))
 				return -EINVAL;
 			save_flags(flags);
 			cli();
 			switch (cmd) {
 				case HDIO_SET_KEEPSETTINGS:
-					dev->keep_settings = arg;
+					drive->keep_settings = arg;
 					break;
 				case HDIO_SET_UNMASKINTR:
-					dev->unmask = arg;
+					drive->unmask = arg;
 					break;
 				case HDIO_SET_NOWERR:
-					dev->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+					drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
 					break;
 				case HDIO_SET_CHIPSET:
-					dev->chipset   = arg;
-					dev->vlb_sync  = (arg & 2) >> 1;
-					dev->vlb_32bit = (arg & 1);
+					drive->chipset   = arg;
+					drive->vlb_32bit = (arg & 1);
+					drive->vlb_sync  = (arg & 2) >> 1;
+#ifndef VLB_SYNC
+					if (drive->vlb_sync)
+						printk("%s: VLB_SYNC not supported by this kernel\n", drive->name);
+#endif
 					break;
 			}
 			restore_flags(flags);
@@ -1606,24 +1646,24 @@
 
 		case HDIO_SET_MULTCOUNT:
 			if (!suser()) return -EACCES;
-			if (MINOR(inode->i_rdev) & PARTN_MASK)
+			if (inode->i_rdev & PARTN_MASK)
 				return -EINVAL;
-			if ((dev->id != NULL) && (arg > dev->id->max_multsect))
+			if ((drive->id != NULL) && (arg > drive->id->max_multsect))
 				return -EINVAL;
 			save_flags(flags);
 			cli();
-			if (dev->special.b.set_multmode) {
+			if (drive->special.b.set_multmode) {
 				restore_flags(flags);
 				return -EBUSY;
 			}
-			dev->mult_req = arg;
-			dev->special.b.set_multmode = 1;
+			drive->mult_req = arg;
+			drive->special.b.set_multmode = 1;
 			restore_flags(flags);
 #ifndef IDE_DRIVE_CMD
 			return 0;
 #else
 			do_drive_cmd (inode->i_rdev, NULL);
-			return (dev->mult_count == arg) ? 0 : -EIO;
+			return (drive->mult_count == arg) ? 0 : -EIO;
 
 		case HDIO_DRIVE_CMD:
 		{
@@ -1649,41 +1689,39 @@
 
 		default:
 #ifdef CONFIG_BLK_DEV_IDECD
-			if (dev->type == cdrom)
-				return ide_cdrom_ioctl(dev, inode, file, cmd, arg);
+			if (drive->media == cdrom)
+				return ide_cdrom_ioctl(drive, inode, file, cmd, arg);
 #endif /* CONFIG_BLK_DEV_IDECD */
 			return -EPERM;
 	}
 }
 
-static int ide_check_media_change (dev_t full_dev)
+static int ide_check_media_change (dev_t i_rdev)
 {
-	ide_dev_t *dev;
+	ide_drive_t *drive;
 
-	if ((dev = get_info_ptr(full_dev)) == NULL)
+	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
 #ifdef CONFIG_BLK_DEV_IDECD
-	if (dev->type == cdrom)
-		return cdrom_check_media_change (dev);
+	if (drive->media == cdrom)
+		return ide_cdrom_check_media_change (drive);
 #endif	/* CONFIG_BLK_DEV_IDECD */
-	if (dev->removeable) /* for disks */
+	if (drive->removeable) /* for disks */
 		return 1;	/* always assume it was changed */
 	return 0;
 }
 
-
-static void fixstring (byte *s, int bytecount, int byteswap)
+static void fixstring (byte *s, const int bytecount, const int byteswap)
 {
-	byte *p, *end = &s[bytecount &= ~1];	/* bytecount must be even */
+	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
 
 	if (byteswap) {
-		/* convert from big-endian to little-endian */
+		/* convert from big-endian to host byte order */
 		for (p = end ; p != s;) {
 			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = (*pp >> 8) | (*pp << 8);
+			*pp = ntohs(*pp);
 		}
 	}
-	p = s;
 
 	/* strip leading blanks */
 	while (s != end && *s == ' ')
@@ -1700,40 +1738,14 @@
 		*p++ = '\0';
 }
 
-static int lba_capacity_is_ok (struct hd_driveid *id)
-/*
- * Returns:	1 if lba_capacity looks sensible
- *		0 otherwise
- */
-{
-	unsigned long lba_sects   = id->lba_capacity;
-	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
-	unsigned long _10_percent = chs_sects / 10;
-
-	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
-	if ((lba_sects - chs_sects) < _10_percent)
-		return 1;	/* lba_capacity is good */
-
-	/* some drives have the word order reversed */
-	lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-	if ((lba_sects - chs_sects) < _10_percent) {
-		id->lba_capacity = lba_sects;	/* fix it */
-		return 1;	/* lba_capacity is (now) good */
-	}
-	return 0;	/* lba_capacity value is bad */
-}
-
-static unsigned long probe_mem_start;	/* used by drive/irq probing routines */
-
-static void do_identify (ide_dev_t *dev, byte cmd)
+static void do_identify (ide_drive_t *drive, byte cmd)
 {
 	int bswap;
 	struct hd_driveid *id;
 	unsigned long capacity, check;
 
-	id = dev->id = (struct hd_driveid *) probe_mem_start; /* kmalloc() */
-	probe_mem_start += 512;
-	input_ide_data(dev, id, SECTOR_WORDS);	/* read 512 bytes of id info */
+	id = drive->id = ide_alloc(SECTOR_WORDS*4);
+	ide_input_data(drive, id, SECTOR_WORDS);	/* read 512 bytes of id info */
 	sti();
 
 	/*
@@ -1741,8 +1753,8 @@
 	 */
 	if ((id->model[0] == 'P' && id->model[1] == 'M')
 	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
-		printk("%s: EATA SCSI HBA %.10s\n", dev->name, id->model);
-		dev->present = 0;
+		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
+		drive->present = 0;
 		return;
 	}
 
@@ -1768,17 +1780,17 @@
 #ifdef CONFIG_BLK_DEV_IDECD
 		byte type = (id->config >> 8) & 0x0f;
 #endif	/* CONFIG_BLK_DEV_IDECD */
-		printk("%s: %s, ATAPI,", dev->name, id->model);
+		printk("%s: %s, ATAPI, ", drive->name, id->model);
+		drive->media = cdrom;
 #ifdef CONFIG_BLK_DEV_IDECD
 		if (type == 0 || type == 5)
-			printk(" CDROM drive\n");
+			printk("CDROM drive\n");
 		else
-			printk(" UNKNOWN device\n");
-		dev->type = cdrom;	/* until we do it "correctly" above */
-		dev->present = 1;
-		dev->removeable = 1;
+			printk("UNKNOWN device\n");
+		drive->present = 1;
+		drive->removeable = 1;
 #else
-		printk(unsupported);
+		printk("not supported by this kernel\n");
 #endif	/* CONFIG_BLK_DEV_IDECD */
 		return;
 	}
@@ -1786,16 +1798,16 @@
 	/* check for removeable disks (eg. SYQUEST), ignore 'WD' drives */
 	if (id->config & (1<<7)) {	/* removeable disk ? */
 		if (id->model[0] != 'W' || id->model[1] != 'D')
-			dev->removeable = 1;
+			drive->removeable = 1;
 	}
 
-	dev->type = disk;
+	drive->media = disk;
 	/* Extract geometry if we did not already have one for the drive */
-	if (!dev->present) {
-		dev->present = 1;
-		dev->cyl     = dev->bios_cyl  = id->cyls;
-		dev->head    = dev->bios_head = id->heads;
-		dev->sect    = dev->bios_sect = id->sectors; 
+	if (!drive->present) {
+		drive->present = 1;
+		drive->cyl     = drive->bios_cyl  = id->cyls;
+		drive->head    = drive->bios_head = id->heads;
+		drive->sect    = drive->bios_sect = id->sectors; 
 	}
 	/* Handle logical geometry translation by the drive */
 	if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
@@ -1811,12 +1823,12 @@
 		 * An exception to this is the cylinder count,
 		 * which we reexamine later on to correct for 1024 limitations.
 		 */
-		dev->cyl  = id->cur_cyls;
-		dev->head = id->cur_heads;
-		dev->sect = id->cur_sectors;
-		capacity  = dev->cyl * dev->head * dev->sect;
+		drive->cyl  = id->cur_cyls;
+		drive->head = id->cur_heads;
+		drive->sect = id->cur_sectors;
 
 		/* check for word-swapped "capacity" field in id information */
+		capacity = drive->cyl * drive->head * drive->sect;
 		check = (id->cur_capacity0 << 16) | id->cur_capacity1;
 		if (check == capacity) {	/* was it swapped? */
 			/* yes, bring it into little-endian order: */
@@ -1825,39 +1837,31 @@
 		}
 	}
 	/* Use physical geometry if what we have still makes no sense */
-	if ((!dev->head || dev->head > 16) && id->heads && id->heads <= 16) {
-		dev->cyl  = id->cyls;
-		dev->head = id->heads;
-		dev->sect = id->sectors; 
+	if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
+		drive->cyl  = id->cyls;
+		drive->head = id->heads;
+		drive->sect = id->sectors; 
 	}
 	/* Correct the number of cyls if the bios value is too small */
-	if (dev->sect == dev->bios_sect && dev->head == dev->bios_head) {
-		if (dev->cyl > dev->bios_cyl)
-			dev->bios_cyl = dev->cyl;
-	}
-	/* Determine capacity, and use LBA if the drive properly supports it */
-	if ((id->capability & 2) && lba_capacity_is_ok(id)) {
-		dev->select.b.lba = 1;
-		capacity = id->lba_capacity;
-	} else {
-		capacity = dev->cyl * dev->head * dev->sect;
+	if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
+		if (drive->cyl > drive->bios_cyl)
+			drive->bios_cyl = drive->cyl;
 	}
 
-	ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity;
+	(void) current_capacity (drive); /* initialize LBA selection */
+
 	printk ("%s: %.40s, %ldMB w/%dKB Cache, %sCHS=%d/%d/%d",
-	 dev->name, id->model, capacity/2048L, id->buf_size/2,
-	 dev->select.b.lba ? "LBA, " : "",
-	 dev->bios_cyl, dev->bios_head, dev->bios_sect);
+	 drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2,
+	 drive->select.b.lba ? "LBA, " : "",
+	 drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
-	dev->mult_count = 0;
+	drive->mult_count = 0;
 	if (id->max_multsect) {
-		dev->mult_req = INITIAL_MULT_COUNT;
-		if (dev->mult_req > id->max_multsect)
-			dev->mult_req = id->max_multsect;
-		if (dev->mult_req || ((id->multsect_valid & 1) && id->multsect)) {
-			dev->special.b.set_multmode = 1;
-			dev->be_quiet = 1;
-		}
+		drive->mult_req = INITIAL_MULT_COUNT;
+		if (drive->mult_req > id->max_multsect)
+			drive->mult_req = id->max_multsect;
+		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+			drive->special.b.set_multmode = 1;
 		printk(", MaxMult=%d", id->max_multsect);
 	}
 	printk("\n");
@@ -1873,70 +1877,66 @@
 	while (timer > jiffies);
 }
 
-
-static int try_to_identify (ide_dev_t *dev, byte cmd)
 /*
+ * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
+ * and waits for a response.  It also monitors irqs while this is
+ * happening, in hope of automatically determining which one is
+ * being used by the interface.
+ *
  * Returns:	0  device was identified
  *		1  device timed-out (no response to identify request)
  *		2  device aborted the command (refused to identify itself)
  */
+static int try_to_identify (ide_drive_t *drive, byte cmd)
 {
 	int hd_status, rc;
 	unsigned long timeout;
-#if PROBE_FOR_IRQS
 	int irqs = 0;
-	static byte irq_probed[2] = {0,0};
-#endif	/* PROBE_FOR_IRQS */
 
-	OUT_BYTE(dev->ctl|2,HD_CMD);		/* disable device irq */
-#if PROBE_FOR_IRQS
-	if (!irq_probed[DEV_HWIF]) {		/* already probed for IRQ? */
+	if (!HWIF(drive)->irq) {		/* already got an IRQ? */
 		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
 		irqs = probe_irq_on();		/* start monitoring irqs */
-		OUT_BYTE(dev->ctl,HD_CMD);	/* enable device irq */
+		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
 	}
-#endif	/* PROBE_FOR_IRQS */
+
 	delay_10ms();				/* take a deep breath */
-	if ((IN_BYTE(HD_ALTSTATUS,DEV_HWIF) ^ IN_BYTE(HD_STATUS,DEV_HWIF)) & ~INDEX_STAT) {
-		hd_status = HD_STATUS;		/* an ancient Seagate drive */
-		printk("%s: probing with STATUS instead of ALTSTATUS\n", dev->name);
+	if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) {
+		printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name);
+		hd_status = IDE_STATUS_REG;	/* ancient Seagate drives */
 	} else
-		hd_status = HD_ALTSTATUS;	/* use non-intrusive polling */
-	OUT_BYTE(cmd,HD_COMMAND);		/* ask drive for ID */
+		hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+
+	OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
 		if (jiffies > timeout) {
-#if PROBE_FOR_IRQS
-			if (!irq_probed[DEV_HWIF])
+			if (!HWIF(drive)->irq)
 				(void) probe_irq_off(irqs);
-#endif	/* PROBE_FOR_IRQS */
 			return 1;	/* drive timed-out */
 		}
 		delay_10ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status,DEV_HWIF) & BUSY_STAT);
+	} while (IN_BYTE(hd_status) & BUSY_STAT);
+
 	delay_10ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_R_STAT)) {
+	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
 		cli();			/* some systems need this */
-		do_identify(dev, cmd);	/* drive returned ID */
+		do_identify(drive, cmd); /* drive returned ID */
 		rc = 0;			/* success */
 	} else
 		rc = 2;			/* drive refused ID */
-#if PROBE_FOR_IRQS
-	if (!irq_probed[DEV_HWIF]) {
+	if (!HWIF(drive)->irq) {
 		irqs = probe_irq_off(irqs);	/* get irq number */
-		if (irqs > 0) {
-			irq_probed[DEV_HWIF] = 1;
-			ide_irq[DEV_HWIF] = irqs;
-		} else				/* Mmmm.. multiple IRQs */
-			printk("%s: IRQ probe failed (%d)\n", dev->name, irqs);
+		if (irqs > 0)
+			HWIF(drive)->irq = irqs;
+		else				/* Mmmm.. multiple IRQs */
+			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
 	}
-#endif	/* PROBE_FOR_IRQS */
 	return rc;
 }
 
 /*
- * This routine has the difficult job of finding a drive if it exists,
+ * do_probe() has the difficult job of finding a drive if it exists,
  * without getting hung up if it doesn't exist, without trampling on
  * ethernet cards, and without leaving any IRQs dangling to haunt us later.
  *
@@ -1944,274 +1944,356 @@
  * but does not respond right away, the probe will "hang in there"
  * for the maximum wait time (about 30 seconds), otherwise it will
  * exit much more quickly.
- */
-static int do_probe (ide_dev_t *dev, byte cmd)
-/*
+ *
  * Returns:	0  device was identified
  *		1  device timed-out (no response to identify request)
  *		2  device aborted the command (refused to identify itself)
  *		3  bad status from device (possible for ATAPI drives)
- *		4  probe was not attempted
+ *		4  probe was not attempted because failure was obvious
  */
+static int do_probe (ide_drive_t *drive, byte cmd)
 {
 	int rc;
 
 #ifdef CONFIG_BLK_DEV_IDECD
-	if (dev->present) {	/* avoid waiting for inappropriate probes */
-		if ((dev->type == disk) ^ (cmd == WIN_IDENTIFY))
+	if (drive->present) {	/* avoid waiting for inappropriate probes */
+		if ((drive->media == disk) ^ (cmd == WIN_IDENTIFY))
 			return 4;
 	}
 #endif	/* CONFIG_BLK_DEV_IDECD */
-#if DEBUG
+#ifdef DEBUG
 	printk("probing for %s: present=%d, type=%s, probetype=%s\n",
-		dev->name, dev->present, dev->type ? "cdrom":"disk",
+		drive->name, drive->present, drive->media ? "cdrom":"disk",
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	OUT_BYTE(dev->select.all,HD_CURRENT);	/* select target drive */
+	OUT_BYTE(drive->select.all,IDE_SELECT_REG);	/* select target drive */
 	delay_10ms();				/* wait for BUSY_STAT */
-	if (IN_BYTE(HD_CURRENT,DEV_HWIF) != dev->select.all && !dev->present) {
-		OUT_BYTE(0xa0,HD_CURRENT);	/* exit with drive0 selected */
+	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
 		return 3;    /* no i/f present: avoid killing ethernet cards */
 	}
 
-	if (OK_STAT(GET_STAT(DEV_HWIF),READY_STAT,BUSY_STAT)
-	 || dev->present || cmd == WIN_PIDENTIFY)
+	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
+	 || drive->present || cmd == WIN_PIDENTIFY)
 	{
-		if ((rc = try_to_identify(dev, cmd)))  /* send cmd and wait */
-			rc = try_to_identify(dev, cmd);	/* failed: try again */
+		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
+			rc = try_to_identify(drive,cmd); /* failed: try again */
 		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n",
-			 dev->name, GET_STAT(DEV_HWIF));
-		OUT_BYTE(dev->ctl|2,HD_CMD);	/* disable device irq */
-		delay_10ms();
-		(void) GET_STAT(DEV_HWIF);	/* ensure drive irq is clear */
+			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
+		(void) GET_STAT();		/* ensure drive irq is clear */
 	} else {
 		rc = 3;				/* not present or maybe ATAPI */
 	}
-	if (dev->select.b.drive == 1) {
-		OUT_BYTE(0xa0,HD_CURRENT);	/* exit with drive0 selected */
-		delay_10ms();
-		OUT_BYTE(dev->ctl|2,HD_CMD);	/* disable device irq */
+	if (drive->select.b.unit != 0) {
+		OUT_BYTE(0xa0,IDE_SELECT_REG);	/* exit with drive0 selected */
 		delay_10ms();
-		(void) GET_STAT(DEV_HWIF);	/* ensure drive irq is clear */
+		(void) GET_STAT();		/* ensure drive irq is clear */
 	}
 	return rc;
 }
 
-static byte probe_for_drive (ide_dev_t *dev)
 /*
+ * probe_for_drive() tests for existance of a given drive using do_probe().
+ *
  * Returns:	0  no device was found
- *		1  device was found (note: dev->present might still be 0)
+ *		1  device was found (note: drive->present might still be 0)
  */
+static byte probe_for_drive (ide_drive_t *drive)
 {
-	if (dev->noprobe)			/* skip probing? */
-		return dev->present;
-	if (do_probe(dev, WIN_IDENTIFY) >= 2) {	/* if !(success || timed-out) */
+	if (drive->noprobe)			/* skip probing? */
+		return drive->present;
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
 #ifdef CONFIG_BLK_DEV_IDECD
-		(void) do_probe(dev, WIN_PIDENTIFY); /* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
 #endif	/* CONFIG_BLK_DEV_IDECD */
 	}
-	if (!dev->present)
+	if (!drive->present)
 		return 0;			/* drive not found */
-	if (dev->id == NULL) {			/* identification failed? */
-		if (dev->type == disk) {
-			printk ("%s: non-IDE device, CHS=%d/%d/%d\n",
-			 dev->name, dev->cyl, dev->head, dev->sect);
+	if (drive->id == NULL) {		/* identification failed? */
+		if (drive->media == disk) {
+			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
+			 drive->name, drive->cyl, drive->head, drive->sect);
 		}
 #ifdef CONFIG_BLK_DEV_IDECD
-		else if (dev->type == cdrom) {
-			printk("%s: ATAPI cdrom (?)\n", dev->name);
+		else if (drive->media == cdrom) {
+			printk("%s: ATAPI cdrom (?)\n", drive->name);
 		}
 #endif	/* CONFIG_BLK_DEV_IDECD */
 		else {
-			dev->present = 0;	/* nuke it */
+			drive->present = 0;	/* nuke it */
 			return 1;		/* drive was found */
 		}
 	}
-#ifdef CONFIG_BLK_DEV_IDECD
-	if (dev->type == cdrom)
-		cdrom_setup(dev);
-#endif	/* CONFIG_BLK_DEV_IDECD */
-	if (dev->type == disk && !dev->select.b.lba) {
-		if (!dev->head || dev->head > 16) {
-			printk("%s: cannot handle disk with %d physical heads\n",
-			 dev->name, dev->head);
-			dev->present = 0;
+	if (drive->media == disk && !drive->select.b.lba) {
+		if (!drive->head || drive->head > 16) {
+			printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			 drive->name, drive->head);
+			drive->present = 0;
 		}
 	}
 	return 1;	/* drive was found */
 }
 
-static void probe_for_drives (byte hwif)
+/*
+ *  This routine only knows how to look for drive units 0 and 1
+ *  on an interface, so any setting of MAX_DRIVES > 2 won't work here.
+ */
+static void probe_for_drives (ide_hwif_t *hwif)
 {
-	ide_dev_t *devs = &ide_dev[HWIF][0];	/* for convenience */
+	unsigned int unit;
 
-	if (check_region(IDE_PORT(HD_DATA,HWIF),8)
-	 || check_region(IDE_PORT(HD_CMD,HWIF),1))
-	{
-		if (devs[0].present || devs[1].present)
-			printk("ERROR: ");
-		printk("%s: port(s) already in use\n", ide_name[HWIF]);
-		devs[0].present = 0;
-		devs[1].present = 0;
+	if (check_region(hwif->io_base,8) || check_region(hwif->ctl_port,1)) {
+		int msgout = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				drive->present = 0;
+				printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
+				msgout = 1;
+			}
+		}
+		if (!msgout)
+			printk("%s: ports already in use, skipping probe\n", hwif->name);
 	} else {
 		unsigned long flags;
 		save_flags(flags);
-		sti();	/* needed for jiffies and irq probing */
 
-		/* second drive should only exist if first drive was found */
-		if (probe_for_drive(&devs[0]) || devs[1].present)
-			(void) probe_for_drive(&devs[1]);
-#if PROBE_FOR_IRQS
-		(void) probe_irq_off(probe_irq_on()); /* clear dangling irqs */
-#endif	/* PROBE_FOR_IRQS */
-		if (devs[0].present || devs[1].present) {
-			request_region(IDE_PORT(HD_DATA,HWIF),8,ide_name[HWIF]);
-			request_region(IDE_PORT(HD_CMD,HWIF),1,ide_name[HWIF]);
+#if (MAX_DRIVES > 2)
+		printk("%s: probing for first 2 of %d possible drives\n", hwif->name, MAX_DRIVES);
+#endif
+		sti();	/* needed for jiffies and irq probing */
+		/*
+		 * Second drive should only exist if first drive was found,
+		 * but a lot of cdrom drives seem to be configured as slave-only
+		 */
+		for (unit = 0; unit < 2; ++unit)  /* note the hardcoded '2' */
+			(void) probe_for_drive(&hwif->drives[unit]);
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				hwif->present = 1;
+				request_region(hwif->io_base,  8, hwif->name);
+				request_region(hwif->ctl_port, 1, hwif->name);
+#ifdef CONFIG_BLK_DEV_IDECD
+				if (drive->media == cdrom)
+					ide_cdrom_setup(drive);
+#endif	/* CONFIG_BLK_DEV_IDECD */
+				break;
+			}
 		}
 		restore_flags(flags);
 	}
 }
 
-static int next_drive = 0;	/* used by the ide_setup() routines below */
-
-void ide_setup(char *str, int *ints)
+/*
+ * stridx() returns the offset of c within s,
+ * or -1 if c is '\0' or not found within s.
+ */
+static int stridx (const char *s, char c)
 {
-	ide_dev_t *dev;
-	const char *p[] = {"cyls","heads","sects","wpcom","irq"};
-	int i, hwif, drive = next_drive++;
-#ifdef CONFIG_BLK_DEV_HD
-	extern void hd_setup(char *, int *);
+	char *i = strchr(s, c);
+	return (i && c) ? i - s : -1;
+}
 
-	if (drive < 2) {
-		hd_setup (str, ints);
-		return;
-	}
-#endif /* CONFIG_BLK_DEV_HD */
-	hwif = (drive > 1);
-	printk("%s: ", ide_name[hwif]);
-	if (drive > 3) {
-		printk("too many drives defined\n");
-		return;
-	}
-	drive = drive & 1;
-	printk("%s: ", ide_devname[hwif][drive]);
-	if (!SUPPORT_TWO_INTERFACES && hwif != HWIF) {
-		printk(unsupported);
-		return;
-	}
-	dev = &ide_dev[hwif][drive];
-	if (dev->present)
-		printk("(redefined) ");
-	if (ints[0] == 0) {
-#if SUPPORT_DTC2278
-		if (!strcmp(str,"dtc2278")) {
-			printk("%s\n",str);
-			probe_dtc2278 = 1;	/* try to init DTC-2278 at boot */
-			return;
-		}
-#endif /* SUPPORT_DTC2278 */
-#if SUPPORT_SERIALIZE
-		if (!strcmp(str,"serialize")) {
-			printk("%s\n",str);
-			single_threaded = 1;	/* serialize all drive access */
-			return;
-		}
-#endif /* SUPPORT_SERIALIZE */
-		if (!strcmp(str,"noprobe")) {
-			printk("%s\n",str);
-			dev->noprobe = 1;	/* don't probe for this drive */
-			return;
-		}
-		if (!strcmp(str,"nowerr")) {
-			printk("%s\n",str);
-			dev->bad_wstat = BAD_R_STAT; /* ignore WRERR_STAT */
-			return;
+/*
+ * match_parm() does parsing for ide_setup():
+ *
+ * 1. the first char of s must be '='.
+ * 2. if the remainder matches one of the supplied keywords,
+ *     the index (1 based) of the keyword is negated and returned.
+ * 3. if the remainder is a series of no more than max_vals numbers
+ *     separated by commas, the numbers are saved in vals[] and a 
+ *     count of how many were saved is returned.  Base10 is assumed,
+ *     and base16 is allowed when prefixed with "0x".
+ * 4. otherwise, zero is returned.
+ */
+static int match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+{
+	static const char *decimal = "0123456789";
+	static const char *hex = "0123456789abcdef";
+	int i, n;
+
+	if (*s++ == '=') {
+		/*
+		 * Try matching against the supplied keywords,
+		 * and return -(index+1) if we match one
+		 */
+		for (i = 0; *keywords != NULL; ++i) {
+			if (!strcmp(s, *keywords++))
+				return -(i+1);
 		}
-#ifdef CONFIG_BLK_DEV_IDECD
-		if (!strcmp(str,"cdrom")) {
-			printk("cdrom\n");
-			dev->present = 1;	/* force autoprobe to find it */
-			dev->type = cdrom;
-			return;
+		/*
+		 * Look for a series of no more than "max_vals"
+		 * numeric values separated by commas, in base10,
+		 * or base16 when prefixed with "0x".  
+		 * Return a count of how many were found.
+		 */
+		for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
+			vals[n] = i;
+			while ((i = stridx(decimal, *++s)) >= 0)
+				vals[n] = (vals[n] * 10) + i;
+			if (*s == 'x' && !vals[n]) {
+				while ((i = stridx(hex, *++s)) >= 0)
+					vals[n] = (vals[n] * 0x10) + i;
+			}
+			if (++n == max_vals)
+				break;
+			if (*s == ',')
+				++s;
 		}
-#endif	/* CONFIG_BLK_DEV_IDECD */
+		if (!*s)
+			return n;
 	}
-	if (ints[0] < 3 || ints[0] > 5) {
-		printk("bad parms, expected: cyls,heads,sects[,wpcom[,irq]]\n");
-	} else {
-		for (i=0; i++ < ints[0];)
-			printk("%s=%d%c",p[i-1],ints[i],i<ints[0]?',':'\n');
-		dev->type    = disk;
-		dev->cyl     = dev->bios_cyl  = ints[1];
-		dev->head    = dev->bios_head = ints[2];
-		dev->ctl     = (ints[2] > 8 ? 8 : 0);
-		dev->sect    = dev->bios_sect = ints[3];
-		dev->wpcom   = (ints[0] >= 4) ? ints[4] : 0;
-		if (ints[0] >= 5)
-			ide_irq[HWIF] = ints[5];
-		ide_capacity[HWIF][drive] = BIOS_SECTORS(dev);
-		dev->present = 1;
-	}
-}
-
-void hda_setup(char *str, int *ints)
-{
-	next_drive = 0;
-	ide_setup (str, ints);
-}
-
-void hdb_setup(char *str, int *ints)
-{
-	next_drive = 1;
-	ide_setup (str, ints);
+	return 0;	/* zero = nothing matched */
 }
 
-void hdc_setup(char *str, int *ints)
-{
-	next_drive = 2;
-	ide_setup (str, ints);
-}
-
-void hdd_setup(char *str, int *ints)
+/*
+ * ide_setup() gets called VERY EARLY during initialization,
+ * to handle kernel "command line" strings beginning with "hdx="
+ * or "ide".  Here is the complete set currently supported:
+ *
+ * "hdx="  is recognized for all "x" from "a" to "h", such as "hdc".
+ * "idex=" is recognized for all "x" from "0" to "3", such as "ide1".
+ *
+ * "hdx=noprobe"	: drive may be present, but do not probe for it
+ * "hdx=nowerr"		: ignore the WRERR_STAT bit on this drive
+ * "hdx=cdrom"		: drive is present, and is a cdrom drive
+ * "hdx=cyl,head,sect"	: disk drive is present, with specified geometry
+ *
+ * "idex=noprobe"	: do not attempt to access/use this interface
+ * "idex=base"		: probe for an interface at the addr specified,
+ *				where "base" is usually 0x1f0 or 0x170
+ *				and "ctl" is assumed to be "base"+0x206
+ * "idex=base,ctl"	: specify both base and ctl
+ * "idex=base,ctl,irq"	: specify base, ctl, and irq number
+ *
+ * The following two are valid ONLY on ide0 or ide1:
+ *
+ * "idex=dtc2278"	: look for and try to initialize a dtc2278
+ * "idex=serialize"	: do not overlap operations on ide0 and ide1.
+ */
+void ide_setup (char *s)
 {
-	next_drive = 3;
-	ide_setup (str, ints);
+	int vals[3];
+	ide_drive_t *drive;
+	unsigned int unit, hwif;
+	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
+	const char max_hwif  = '0' + (MAX_HWIFS - 1);
+
+	printk("ide_setup: %s", s);
+	init_ide_data ();
+	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
+		const char *hd_words[] = {"noprobe", "nowerr", "cdrom", "serialize", NULL};
+		unit = s[2] - 'a';
+		hwif = unit / MAX_DRIVES;
+		unit = unit % MAX_DRIVES;
+		drive = &ide_hwifs[hwif].drives[unit];
+		switch (match_parm(&s[3], hd_words, vals, 3)) {
+			case -1: /* "noprobe" */
+				drive->noprobe = 1;
+				goto done;
+			case -2: /* "nowerr" */
+				drive->bad_wstat = BAD_R_STAT;
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+			case -3: /* "cdrom" */
+				drive->present = 1;
+				drive->media = cdrom;
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+			case -4: /* "serialize" */
+				printk(" -- USE ""ide%c=serialize"" INSTEAD", '0'+hwif);
+				goto do_serialize;
+			case 3: /* cyl,head,sect */
+				drive->media	= disk;
+				drive->cyl	= drive->bios_cyl  = vals[0];
+				drive->head	= drive->bios_head = vals[1];
+				drive->sect	= drive->bios_sect = vals[2];
+				drive->present	= 1;
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+			default:
+				goto bad_option;
+		}
+	}
+	if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) {
+		const char *ide_words[] = {"dtc2278", "serialize", "noprobe", NULL};
+		hwif = s[3] - '0';
+		switch (match_parm(&s[4], ide_words, vals, 3)) {
+#if SUPPORT_DTC2278
+			case -1: /* "dtc2278" */
+				if (hwif > 1) goto bad_hwif;
+				probe_dtc2278 = 1;
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+#endif /* SUPPORT_DTC2278 */
+			case -2: /* "serialize" */
+			do_serialize:
+				if (hwif > 1) goto bad_hwif;
+				single_threaded = 1;
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+			case -3: /* "noprobe" */
+				ide_hwifs[hwif].noprobe = 1;
+				goto done;
+			case 1:	/* base */
+				vals[1] = vals[0] + 0x206; /* default ctl */
+			case 2: /* base,ctl */
+				vals[2] = 0;	/* default irq = probe for it */
+			case 3: /* base,ctl,irq */
+				ide_hwifs[hwif].io_base  = vals[0];
+				ide_hwifs[hwif].ctl_port = vals[1];
+				ide_hwifs[hwif].irq      = vals[2];
+				ide_hwifs[hwif].noprobe = 0;
+				goto done;
+		}
+	}
+bad_option:
+	printk(" -- BAD OPTION\n");
+	return;
+bad_hwif:
+	printk("-- NOT SUPPORTED ON ide%d", hwif);
+done:
+	printk("\n");
 }
 
-int ide_xlate_1024 (dev_t full_dev, int need_offset, const char *msg)
-{
-	ide_dev_t *dev;
-	byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}, *heads = head_vals;
-	unsigned long capacity;
+/*
+ * This routine is called from the partition-table code in genhd.c
+ * to "convert" a drive to a logical geometry with fewer than 1024 cyls
+ * It mimics the method used by Ontrack Disk Manager.
+ */
+int ide_xlate_1024 (dev_t i_rdev, int need_offset, const char *msg)
+{
+	ide_drive_t *drive;
+	static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const byte *heads = head_vals;
+	unsigned long tracks;
 
-	if ((dev = get_info_ptr(full_dev)) == NULL && dev->id == NULL)
+	if ((drive = get_info_ptr(i_rdev)) == NULL || drive->id == NULL)
 		return 0;
 
-	dev->cyl  = dev->bios_cyl   = dev->id->cyls;
-	dev->head = dev->bios_head  = dev->id->heads;
-	dev->sect = dev->bios_sect  = dev->id->sectors; 
-	dev->special.b.set_geometry = 1;
-
-	capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect / 63;
-	dev->bios_sect = 63;
-	do {
-		dev->bios_head = *heads;
-		dev->bios_cyl = capacity / dev->bios_head;
-	} while (dev->bios_cyl >= 1024 && *++heads);
+	drive->cyl  = drive->bios_cyl  = drive->id->cyls;
+	drive->head = drive->bios_head = drive->id->heads;
+	drive->sect = drive->bios_sect = drive->id->sectors; 
+	drive->special.b.set_geometry = 1;
+
+	tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
+	drive->bios_sect = 63;
+	while (drive->bios_cyl >= 1024) {
+		drive->bios_head = *heads;
+		drive->bios_cyl = tracks / drive->bios_head;
+		if (0 == *++heads)
+			break;
+	}
 	if (need_offset) {
-		dev->sect0 = 63;
-		capacity -= 1;
-		dev->bios_cyl = capacity / dev->bios_head;
-	}
-	capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect;
-	ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity;
-	ide_hd[DEV_HWIF][MINOR(full_dev)].nr_sects  = capacity;
-	printk("%s [+%d,%d/%d/%d]", msg, dev->sect0, dev->bios_cyl, dev->bios_head, dev->bios_sect);
+		drive->sect0 = 63;
+		drive->bios_cyl = (tracks - 1) / drive->bios_head;
+	}
+	drive->part[0].nr_sects = current_capacity(drive);
+	printk("%s [+%d,%d/%d/%d]", msg, drive->sect0, drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return 1;
 }
 
-#ifndef CONFIG_BLK_DEV_HD
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -2224,135 +2306,90 @@
  * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value 
  * means we have an AT controller hard disk for that drive.
  */
-static void probe_cmos_for_drives (void)
+static void probe_cmos_for_drives (ide_hwif_t *hwif)
 {
 #ifdef __i386__
 	extern struct drive_info_struct drive_info;
-	byte drive, cmos_disks, *BIOS = (byte *) &drive_info;
+	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	int unit;
 
 	outb_p(0x12,0x70);		/* specify CMOS address 0x12 */
 	cmos_disks = inb_p(0x71);	/* read the data from 0x12 */
 	/* Extract drive geometry from CMOS+BIOS if not already setup */
-	for (drive = 0; drive < MAX_DRIVES; drive++) {
-		ide_dev_t *dev = &ide_dev[0][drive];
-		if ((cmos_disks & (0xf0 >> (drive*4))) && !dev->present) {
-			dev->cyl     = dev->bios_cyl  = *(unsigned short *)BIOS;
-			dev->head    = dev->bios_head = * (BIOS+2);
-			dev->sect    = dev->bios_sect = * (BIOS+14);
-			dev->wpcom   = (*(unsigned short *)(BIOS+5))>>2;
-			dev->ctl     = *(BIOS+8);
-			dev->wpcom   = 0;
-			dev->type    = disk;
-			dev->present = 1;
-			ide_capacity[0][drive] = BIOS_SECTORS(dev);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+		if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) {
+			drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
+			drive->head  = drive->bios_head = * (BIOS+2);
+			drive->sect  = drive->bios_sect = * (BIOS+14);
+			drive->wpcom = (*(unsigned short *)(BIOS+5))>>2;
+			drive->ctl   = *(BIOS+8);
+			drive->wpcom = 0;
+			drive->media = disk;
+			drive->present = 1;
 		}
 		BIOS += 16;
 	}
 #endif
 }
-#endif	/* CONFIG_BLK_DEV_HD */
-
-static void init_ide_data (byte hwif)
-{
-	int drive;
-
-	for (drive = 0; drive < (MAX_DRIVES<<PARTN_BITS); drive++)
-		ide_blksizes[hwif][drive] = 1024;
-	blksize_size[ide_major[hwif]] = ide_blksizes[hwif];
-
-	/* Initialize non-geometry fields -- ide_setup() runs before we do */
-	for (drive = 0; drive < MAX_DRIVES; drive++) {
-		ide_dev_t *dev = &ide_dev[hwif][drive];
-		dev->select.all			= (drive<<4)|0xa0;
-		dev->hwif			= hwif;
-		dev->unmask			= 0;
-		dev->busy			= 0;
-		dev->mult_count			= 0; /* set by do_identify() */
-		dev->mult_req			= 0; /* set by do_identify() */
-		dev->usage			= 0;
-		dev->vlb_32bit			= 0;
-		dev->vlb_sync			= 0;
-		dev->id				= NULL;
-		dev->ctl			= 0x08;
-		dev->wqueue			= NULL;
-		dev->special.all		= 0;
-		dev->special.b.recalibrate	= 1;
-		dev->special.b.set_geometry	= 1;
-		dev->keep_settings		= 0;
-		dev->sect0			= 0;
-		dev->removeable			= 0;
-		ide_hd[hwif][drive<<PARTN_BITS].start_sect = 0;
-		dev->name = ide_devname[hwif][drive];
-		if (!dev->bad_wstat)
-			dev->bad_wstat = BAD_W_STAT;
-	}
-}
 
 /*
- * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
- * means we enter the IRQ-handler with interrupts disabled: this is bad for
- * interrupt latency, but anything else has led to problems on some
- * machines.  We enable interrupts as much as we can safely do in most places.
+ * This routine sets up the irq for an ide interface, and creates a new
+ * hwgroup for the irq/hwif if none was previously assigned.
+ *
+ * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
+ * interrupts completely disabled.  This can be bad for interrupt latency,
+ * but anything else has led to problems on some machines.  We re-enable
+ * interrupts as much as we can safely do in most places.
  */
-static byte setup_irq (byte hwif)
+static int init_irq (ide_hwif_t *hwif)
 {
-	static byte rc = 0;
 	unsigned long flags;
-	const char *msg = "", *primary_secondary[] = {"primary", "secondary"};
-	void (*handler)(int, struct pt_regs *) = HWIF ? &ide1_intr : &ide0_intr;
+	ide_hwgroup_t *hwgroup;
 
-#if SUPPORT_SHARING_IRQ
-	if (sharing_single_irq) {
-		if (HWIF != 0 && !rc) {	/* IRQ already allocated? */
-			msg = " (shared with ide0)";
-			goto done;
-		}
-		handler = &ide_shared_intr;
-	}
-#if SUPPORT_SERIALIZE
-	else if (single_threaded) {
-		handler = &ide_seq_intr;
-		if (HWIF != 0)
-			msg = " (single-threaded with ide0)";
-	}
-#endif /* SUPPORT_SERIALIZE */
-#endif /* SUPPORT_SHARING_IRQ */
+	/*
+	 * First, we try to grab the irq
+	 */
 	save_flags(flags);
 	cli();
-	if ((rc = request_irq(ide_irq[HWIF],handler,SA_INTERRUPT,ide_name[HWIF])))
-		msg = ":  FAILED! unable to allocate IRQ";
-	restore_flags(flags);
-#if SUPPORT_SHARING_IRQ
-done:
-#endif /* SUPPORT_SHARING_IRQ */
-	printk("%s: %s interface on irq %d%s\n",
-	 ide_name[HWIF], primary_secondary[HWIF], ide_irq[HWIF], msg);
-	return rc;
-}
+	if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT, hwif->name)) {
+		restore_flags(flags);
+		printk(" -- FAILED!");
+		return 1;
+	}
 
-static void ide_geninit(byte hwif)
-{
-	static int drive;
-	
-	for (drive = 0; drive < MAX_DRIVES; drive++) {
-		ide_dev_t *dev = &ide_dev[HWIF][drive];
-		if (dev->present) {
-			ide_hd[HWIF][drive<<PARTN_BITS].nr_sects = ide_capacity[HWIF][drive];
-			/* Skip partition check for cdroms. */
-			if (dev->type == cdrom)
-				ide_hd[HWIF][drive<<PARTN_BITS].start_sect = -1;
-		}
+	/*
+	 * Got the irq,  now set everything else up
+	 */
+	if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
+		hwgroup = ide_alloc(sizeof(ide_hwgroup_t));
+		irq_to_hwgroup[hwif->irq] = hwgroup;
+		hwgroup->hwif 	 = hwif->next = hwif;
+		hwgroup->rq      = NULL;
+		hwgroup->handler = NULL;
+		hwgroup->drive   = NULL;
+		init_timer(&hwgroup->timer);
+		hwgroup->timer.function = &timer_expiry;
+		hwgroup->timer.data = (unsigned long) hwgroup;
+	} else {
+		hwif->next = hwgroup->hwif->next;
+		hwgroup->hwif->next = hwif;
 	}
-}
+	hwif->hwgroup = hwgroup;
 
-static void ide0_geninit(void)
-{
-	ide_geninit(0);
-}
+	restore_flags(flags);	/* safe now that hwif->hwgroup is set up */
 
-static void ide1_geninit(void)
-{
-	ide_geninit(1);
+	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+		hwif->io_base, hwif->io_base + 7, hwif->ctl_port, hwif->irq);
+	if (hwgroup->hwif != hwif) {
+		char *name = hwgroup->hwif->name;
+		if (hwgroup->hwif->irq == hwif->irq)
+			printk(" (shared with %s)", name);
+		else
+			printk(" (serialized with %s)", name);
+	}
+	printk("\n");
+	return 0;
 }
 
 static struct file_operations ide_fops = {
@@ -2388,15 +2425,15 @@
 {
 	int i;
 
-	for(i = 0; i < 3; i++) {
-		__inb(0x3f6);
+	for(i = 0; i < 3; ++i) {
+		inb(0x3f6);
 		outb_p(b,0xb0);
-		__inb(0x3f6);
+		inb(0x3f6);
 		outb_p(c,0xb4);
-		__inb(0x3f6);
-		if(__inb(0xb4) == c) {
+		inb(0x3f6);
+		if(inb(0xb4) == c) {
 			outb_p(7,0xb0);
-			__inb(0x3f6);
+			inb(0x3f6);
 			return;	/* success */
 		}
 	}
@@ -2413,9 +2450,9 @@
 /* This enables the second interface */
 
 	outb_p(4,0xb0);
-	__inb(0x3f6);
+	inb(0x3f6);
 	outb_p(0x20,0xb4);
-	__inb(0x3f6);
+	inb(0x3f6);
 }
 #endif /* SUPPORT_DTC2278 */
 
@@ -2424,76 +2461,81 @@
  */
 unsigned long ide_init (unsigned long mem_start, unsigned long mem_end)
 {
-	byte hwif;
+	int h;
 
+	init_mem_start = (mem_start + 3uL) & ~3uL;	/* for ide_alloc() */
+	init_ide_data ();
+	/*
+	 * First, we determine what hardware is present
+	 */
 #if SUPPORT_DTC2278
 	if (probe_dtc2278)
 		try_to_init_dtc2278();
 #endif /* SUPPORT_DTC2278 */
-	/* single_threaded = 0; */	/* zero by default, override at boot */
-	for (hwif = 0; hwif < 2; hwif++) {
-		init_ide_data (hwif);
-		if (SUPPORT_TWO_INTERFACES || hwif == HWIF) {
-			if (hwif == 0)
-#ifdef CONFIG_BLK_DEV_HD
-				continue;
-#else
-				probe_cmos_for_drives ();
-#endif /* CONFIG_BLK_DEV_HD */
-			probe_mem_start = (mem_start + 3uL) & ~3uL;
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (!hwif->noprobe) {
+			if (hwif->io_base == HD_DATA)
+				probe_cmos_for_drives (hwif);
 			probe_for_drives (hwif);
-			mem_start = probe_mem_start;
-		}
-	}
-
-	/* At this point, all methods of drive detection have completed */
-	ide_gendisk[0].nr_real = ide_dev[0][0].present + ide_dev[0][1].present;
-	ide_gendisk[1].nr_real = ide_dev[1][0].present + ide_dev[1][1].present;
-	if (ide_gendisk[1].nr_real && (ide_irq[0] == ide_irq[1])) {
-		if (!ide_gendisk[0].nr_real) {
-			ide_irq[0] = 0;	/* needed by ide_intr() */
-		} else {
-#if SUPPORT_SHARING_IRQ
-			sharing_single_irq = 1;
-			single_threaded = 1;
-#else /* SUPPORT_SHARING_IRQ */
-			printk("%s: ide irq-sharing%s", ide_name[1], unsupported);
-			return mem_start;
-#endif /* SUPPORT_SHARING_IRQ */
 		}
-	}
+		if (hwif->present) {
+			if (!hwif->irq) {
+				if (!(hwif->irq = default_irqs[h])) {
+					printk("%s: DISABLED, NO IRQ\n", hwif->name);
+					hwif->present = 0;
+					continue;
+				}
+			}
 #ifdef CONFIG_BLK_DEV_HD
-#if SUPPORT_SHARING_IRQ
-	if (ide_irq[1] == 14 || sharing_single_irq) {
-#else
-	if (ide_irq[1] == 14) {
-#endif /* SUPPORT_SHARING_IRQ */
-		printk("%s: irq-sharing not possible with old harddisk driver (hd.c)\n", ide_name[1]);
-		return mem_start;
-	}
+			if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) {
+				printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
+				hwif->present = 0;
+			}
 #endif /* CONFIG_BLK_DEV_HD */
+		}
+	}
 
-	for (hwif = 2; hwif-- > 0;) {
-		if (ide_gendisk[hwif].nr_real != 0 && !setup_irq(hwif)) {
-			const char *name = ide_name[HWIF];
-			unsigned int major = ide_major[HWIF];
-			if (register_blkdev(major, name, &ide_fops)) {
-				printk("%s: unable to get major number %d\n", name, major);
-			} else {
-				timer_table[ide_timer[HWIF]].fn
-					= HWIF ? ide1_timer_expiry : ide0_timer_expiry;
-#if SUPPORT_SHARING_IRQ
-				if (single_threaded)
-					blk_dev[major].request_fn = &do_shared_request;
-				else
-#endif /* SUPPORT_SHARING_IRQ */
-				blk_dev[major].request_fn =
-				 HWIF ? &do_ide1_request : &do_ide0_request;
-				read_ahead[major] = 8;	/* (4kB) */
-				ide_gendisk[HWIF].next = gendisk_head;
-				gendisk_head = &ide_gendisk[HWIF];
+	/*
+	 * Now we try to set up irqs and major devices for what was found
+	 */
+	for (h = MAX_HWIFS-1; h >= 0; --h) {
+		void (*rfn)(void);
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (!hwif->present)
+			continue;
+		hwif->present = 0; /* we set it back to 1 if all is ok below */
+		if (h == 0 && single_threaded) {
+			if (ide_hwifs[1].present) {
+				if (irq_to_hwgroup[hwif->irq] != NULL) {
+					printk("%s: SERIALIZE BUG!\n", hwif->name);
+					continue;
+				}
+				irq_to_hwgroup[hwif->irq] = irq_to_hwgroup[ide_hwifs[1].irq];
 			}
 		}
+		switch (hwif->major) {
+			case IDE0_MAJOR: rfn = &do_ide0_request; break;
+			case IDE1_MAJOR: rfn = &do_ide1_request; break;
+			case IDE2_MAJOR: rfn = &do_ide2_request; break;
+			case IDE3_MAJOR: rfn = &do_ide3_request; break;
+			default:
+				printk("%s: request_fn NOT DEFINED\n", hwif->name);
+				continue;
+		}
+		if (register_blkdev (hwif->major, hwif->name, &ide_fops)) {
+			printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
+		} else if (init_irq (hwif)) {
+			printk("%s: UNABLE TO GET IRQ %d\n", hwif->name, hwif->irq);
+			(void) unregister_blkdev (hwif->major, hwif->name);
+		} else {
+			init_gendisk(hwif);
+			blk_dev[hwif->major].request_fn = rfn;
+			read_ahead[hwif->major] = 8;	/* (4kB) */
+			hwif->present = 1;	/* success */
+		}
 	}
+	mem_start = init_mem_start;
+	init_mem_start = 0uL;	/* prevent further use of ide_alloc() */
 	return mem_start;
 }
diff -u --recursive --new-file v1.3.18/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v1.3.18/linux/drivers/block/ide.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/block/ide.h	Tue Aug 15 20:10:48 1995
@@ -0,0 +1,376 @@
+/*
+ *  linux/drivers/block/ide.h
+ *
+ *  Copyright (C) 1994, 1995  Linus Torvalds & authors
+ */
+
+/*
+ * This is the multiple IDE interface driver, as evolved from hd.c.  
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * There can be up to two drives per interface, as per the ATA-2 spec.
+ *
+ * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
+ * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
+ * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ */
+
+/******************************************************************************
+ * IDE driver configuration options (play with these as desired):
+ */
+#undef REALLY_SLOW_IO			/* most systems can safely undef this */
+#include <asm/io.h>
+
+#define	REALLY_FAST_IO			/* define if ide ports are perfect */
+#define INITIAL_MULT_COUNT	0	/* off=0; on=2,4,8,16,32, etc.. */
+
+#ifndef DISK_RECOVERY_TIME		/* off=0; on=access_delay_time */
+#define DISK_RECOVERY_TIME	0	/*  for hardware that needs it */
+#endif
+#ifndef OK_TO_RESET_CONTROLLER		/* 1 needed for good error recovery */
+#define OK_TO_RESET_CONTROLLER	1	/* 0 for use with AH2372A/B interface */
+#endif
+#ifndef SUPPORT_DTC2278			/* 1 to support DTC2278 chipset */
+#define SUPPORT_DTC2278		1	/* 0 to reduce kernel size */
+#endif
+#ifndef FANCY_STATUS_DUMPS		/* 1 for human-readable drive errors */
+#define FANCY_STATUS_DUMPS	1	/* 0 to reduce kernel size */
+#endif
+
+/*
+ * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
+ */
+#define IDE_DRIVE_CMD		99	/* (magic) undef to reduce kernel size*/
+
+/*
+ *  "No user-serviceable parts" beyond this point  :)
+ *****************************************************************************/
+
+typedef unsigned char	byte;	/* used everywhere */
+
+/*
+ * Probably not wise to fiddle with these
+ */
+#define ERROR_MAX	8	/* Max read/write errors per sector */
+#define ERROR_RESET	3	/* Reset controller every 4th retry */
+#define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
+
+/*
+ * Ensure that various configuration flags have compatible settings
+ */
+#ifdef REALLY_SLOW_IO
+#undef REALLY_FAST_IO
+#endif
+
+/*
+ * Definitions for accessing IDE controller registers
+ */
+
+#define HWIF(drive)		((ide_hwif_t *)drive->hwif)
+#define HWGROUP(drive)		((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
+
+#define IDE_DATA_REG		(HWIF(drive)->io_base)
+#define IDE_ERROR_REG		(HWIF(drive)->io_base+1)
+#define IDE_NSECTOR_REG		(HWIF(drive)->io_base+2)
+#define IDE_SECTOR_REG		(HWIF(drive)->io_base+3)
+#define IDE_LCYL_REG		(HWIF(drive)->io_base+4)
+#define IDE_HCYL_REG		(HWIF(drive)->io_base+5)
+#define IDE_SELECT_REG		(HWIF(drive)->io_base+6)
+#define IDE_STATUS_REG		(HWIF(drive)->io_base+7)
+#define IDE_CONTROL_REG		(HWIF(drive)->ctl_port)
+#define IDE_FEATURE_REG		IDE_ERROR_REG
+#define IDE_COMMAND_REG		IDE_STATUS_REG
+#define IDE_ALTSTATUS_REG	IDE_CONTROL_REG
+
+#ifdef REALLY_FAST_IO
+#define OUT_BYTE(b,p)		outb((b),p)
+#define IN_BYTE(p)		(byte)inb(p)
+#else
+#define OUT_BYTE(b,p)		outb_p((b),p)
+#define IN_BYTE(p)		(byte)inb_p(p)
+#endif /* REALLY_FAST_IO */
+
+#define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
+#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
+#define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
+#define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
+#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
+#define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
+#define DRIVE_READY		(READY_STAT  | SEEK_STAT)
+#define DATA_READY		(DRIVE_READY | DRQ_STAT)
+
+/*
+ * Some more useful definitions
+ */
+#define IDE_MAJOR_NAME	"ide"	/* the same for all i/f; see also genhd.c */
+#define MAJOR_NAME	IDE_MAJOR_NAME
+#define PARTN_BITS	6	/* number of minor dev bits for partitions */
+#define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
+#define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
+#define MAX_HWIFS	4	/* an arbitrary, but realistic limit */
+#define SECTOR_WORDS	(512 / 4)	/* number of 32bit words per sector */
+
+/*
+ * Timeouts for various operations:
+ */
+#define WAIT_DRQ	(5*HZ/100)	/* 50msec - spec allows up to 20ms */
+#define WAIT_READY	(3*HZ/100)	/* 30msec - should be instantaneous */
+#define WAIT_PIDENTIFY	(1*HZ)	/* 1sec   - should be less than 3ms (?) */
+#define WAIT_WORSTCASE	(30*HZ)	/* 30sec  - worst case when spinning up */
+#define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
+
+#ifdef CONFIG_BLK_DEV_IDECD
+
+struct packet_command {
+  char *buffer;
+  int buflen;
+  int stat;
+  unsigned char c[12];
+};
+
+
+struct atapi_request_sense {
+  unsigned char error_code : 7;
+  unsigned char valid      : 1;
+  byte reserved1;
+  unsigned char sense_key  : 4;
+  unsigned char reserved2  : 1;
+  unsigned char ili        : 1;
+  unsigned char reserved3  : 2;
+  byte info[4];
+  byte sense_len;
+  byte command_info[4];
+  byte asc;
+  byte ascq;
+  byte fru;
+  byte sense_key_specific[3];
+};
+
+/* Space to hold the disk TOC. */
+
+#define MAX_TRACKS 99
+struct atapi_toc_header {
+  unsigned short toc_length;
+  byte first_track;
+  byte last_track;
+};
+
+struct atapi_toc_entry {
+  byte reserved1;
+  unsigned control : 4;
+  unsigned adr     : 4;
+  byte track;
+  byte reserved2;
+  unsigned lba;
+};
+
+struct atapi_toc {
+  struct atapi_toc_header hdr;
+  struct atapi_toc_entry  ent[MAX_TRACKS+1];  /* One extra for the leadout. */
+};
+
+/* Extra per-device info for cdrom drives. */
+struct cdrom_info {
+
+  /* Buffer for table of contents.  NULL if we haven't allocated
+     a TOC buffer for this device yet. */
+
+  struct atapi_toc *toc;
+
+  /* Sector buffer.  If a read request wants only the first part of a cdrom
+     block, we cache the rest of the block here, in the expectation that that
+     data is going to be wanted soon.  SECTOR_BUFFERED is the number of the
+     first buffered sector, and NSECTORS_BUFFERED is the number of sectors
+     in the buffer.  Before the buffer is allocated, we should have
+     SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
+
+  unsigned long sector_buffered;
+  unsigned long nsectors_buffered;
+  char *sector_buffer;
+
+  /* The result of the last successful request sense command
+     on this device. */
+  struct atapi_request_sense sense_data;
+};
+
+#endif /* CONFIG_BLK_DEV_IDECD */
+
+/*
+ * Now for the data we need to maintain per-drive:  ide_drive_t
+ */
+typedef enum {disk, cdrom} media_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned set_geometry	: 1;	/* respecify drive geometry */
+		unsigned recalibrate	: 1;	/* seek to cyl 0      */
+		unsigned set_multmode	: 1;	/* set multmode count */
+		unsigned reserved	: 5;	/* unused */
+		} b;
+	} special_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+	} b;
+	} select_t;
+
+typedef struct ide_drive_s {
+	special_t	special;	/* special action flags */
+	unsigned present	: 1;	/* drive is physically present */
+	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
+	unsigned keep_settings  : 1;	/* restore settings after drive reset */
+	unsigned busy		: 1;	/* currently doing revalidate_disk() */
+	unsigned vlb_32bit	: 1;	/* use 32bit in/out for data */
+	unsigned vlb_sync	: 1;	/* needed for some 32bit chip sets */
+	unsigned removeable	: 1;	/* 1 if need to do check_media_change */
+	unsigned dma_capable	: 1;	/* for Intel Triton chipset, others.. */
+	select_t	select;		/* basic drive/head select reg value */
+	byte		unmask;		/* flag: okay to unmask other irqs */
+	void		*hwif;		/* actually (ide_hwif_t *) */
+	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
+	byte		ready_stat;	/* min status value for drive ready */
+	byte		wpcom;		/* ignored by all IDE drives */
+	media_t		media;		/* disk, cdrom, tape */
+	byte		mult_count;	/* current multiple sector setting */
+	byte 		mult_req;	/* requested multiple sector setting */
+	byte		chipset;	/* interface chipset access method */
+	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
+	byte		sect0;		/* offset of first sector for DM6:DDO */
+	byte 		usage;		/* current "open()" count for drive */
+	byte 		head;		/* "real" number of heads */
+	byte		sect;		/* "real" sectors per track */
+	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
+	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	unsigned short	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
+	unsigned short	cyl;		/* "real" number of cyls */
+	struct wait_queue *wqueue;	/* used to wait for drive in open() */
+	struct hd_driveid *id;		/* drive model identification info */
+	struct hd_struct  *part;	/* drive partition table */
+	char		name[4];	/* drive name, such as "hda" */
+#ifdef CONFIG_BLK_DEV_IDECD
+	struct cdrom_info cdrom_info;	/* from ide-cd.c */
+#endif /* CONFIG_BLK_DEV_IDECD */
+	} ide_drive_t;
+
+typedef struct hwif_s {
+	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
+	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
+	unsigned short	io_base;	/* base io port addr */
+	unsigned short	ctl_port;	/* usually io_base+0x206 */
+	ide_drive_t		drives[MAX_DRIVES];	/* drive info */
+	struct gendisk	*gd;		/* gendisk structure */
+	byte		irq;		/* our irq number */
+	byte		major;		/* our major number */
+	byte		drivecount;	/* how many drives attached */
+	char 		name[5];	/* name of interface, eg. "ide0" */
+	unsigned	noprobe : 1;	/* don't probe for this interface */
+	unsigned	present : 1;	/* this interface exists */
+	unsigned long	reset_timeout;	/* timeout value during ide resets */
+#if (DISK_RECOVERY_TIME > 0)
+	unsigned long	last_timer;	/* time when previous rq was done */
+#endif
+#ifdef CONFIG_BLK_DEV_IDECD
+	struct request request_sense_request;	/* from ide-cd.c */
+	struct packet_command request_sense_pc;	/* from ide-cd.c */
+#endif /* CONFIG_BLK_DEV_IDECD */
+	} ide_hwif_t;
+
+/*
+ *  our internal interrupt handler type
+ */
+typedef void (ide_handler_t)(ide_drive_t *);
+
+typedef struct hwgroup_s {
+	ide_handler_t		*handler;/* irq handler, if active */
+	ide_drive_t		*drive;	/* current drive */
+	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
+	struct request		*rq;	/* current request */
+	struct timer_list	timer;	/* failsafe timer */
+	struct request		wrq;	/* local copy of current write rq */
+	} ide_hwgroup_t;
+
+/*
+ * One final include file, which references some of the data/defns from above
+ */
+#define IDE_DRIVER	/* "parameter" for blk.h */
+#include "blk.h"
+
+#if (DISK_RECOVERY_TIME > 0)
+void ide_set_recovery_timer (ide_hwif_t *);
+#define SET_RECOVERY_TIMER(drive) ide_set_recovery_timer (drive)
+#else
+#define SET_RECOVERY_TIMER(drive)
+#endif
+
+/*
+ * The main (re-)entry point for handling a new request is IDE_DO_REQUEST.
+ * Note that IDE_DO_REQUEST should *only* ever be invoked from an interrupt
+ * handler.  All others, such as a timer expiry handler, should call
+ * do_hwgroup_request() instead (currently local to ide.c).
+ */
+void ide_do_request (ide_hwgroup_t *);
+#define IDE_DO_REQUEST { SET_RECOVERY_TIMER(HWIF(drive)); ide_do_request(HWGROUP(drive)); }
+
+
+/*
+ * This is used for (nearly) all data transfers from the IDE interface
+ */
+void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * This is used for (nearly) all data transfers to the IDE interface
+ */
+void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+
+/*
+ * This is used on exit from the driver, to designate the next irq handler
+ * and also to start the safety timer.
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler);
+
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * ide_error() takes action based on the error returned by the controller.
+ *
+ * Returns 1 if an ide reset operation has been initiated, in which case
+ * the caller MUST simply return from the driver (through however many levels).
+ * Returns 0 otherwise.
+ */
+int ide_error (ide_drive_t *drive, const char *msg, byte stat);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error()
+ *
+ */
+int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+
+/*
+ * This is called from genhd.c to correct DiskManager/EZ-Drive geometries
+ */
+int ide_xlate_1024(dev_t, int, const char *);
+
+#ifdef CONFIG_BLK_DEV_IDECD
+/*
+ * These are routines in ide-cd.c invoked from ide.c
+ */
+void ide_do_rw_cdrom (ide_drive_t *, unsigned long);
+int ide_cdrom_ioctl (ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_cdrom_check_media_change (ide_drive_t *);
+int ide_cdrom_open (struct inode *, struct file *, ide_drive_t *);
+void ide_cdrom_release (struct inode *, struct file *, ide_drive_t *);
+void ide_cdrom_setup (ide_drive_t *);
+#endif /* CONFIG_BLK_DEV_IDECD */
diff -u --recursive --new-file v1.3.18/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.18/linux/drivers/block/ll_rw_blk.c	Fri Jul  7 08:54:45 1995
+++ linux/drivers/block/ll_rw_blk.c	Sun Aug 13 20:19:12 1995
@@ -243,7 +243,7 @@
 					if (disk_index < 4)
 						kstat.dk_drive[disk_index]++;
 					break;
-		case HD_MAJOR:
+		case IDE0_MAJOR:	/* same as HD_MAJOR */
 		case XT_DISK_MAJOR:	disk_index = (MINOR(req->dev) & 0x0040) >> 6;
 					kstat.dk_drive[disk_index]++;
 					break;
@@ -305,6 +305,7 @@
 		if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) {
 			bh->b_dirt = bh->b_uptodate = 0;
 			bh->b_req = 0;
+			printk("attempt to access beyond end of device\n");
 			return;
 		}
 	/* Uhhuh.. Nasty dead-lock possible here.. */
@@ -334,7 +335,9 @@
 	     || major == IDE1_MAJOR
 	     || major == FLOPPY_MAJOR
 	     || major == SCSI_DISK_MAJOR
-	     || major == SCSI_CDROM_MAJOR)
+	     || major == SCSI_CDROM_MAJOR
+	     || major == IDE2_MAJOR
+	     || major == IDE3_MAJOR)
 	    && (req = blk_dev[major].current_request))
 	{
 #ifdef CONFIG_BLK_DEV_HD
@@ -583,11 +586,11 @@
 		req->next = NULL;
 	}
 	memset(ro_bits,0,sizeof(ro_bits));
+#ifdef CONFIG_BLK_DEV_IDE
+	mem_start = ide_init(mem_start,mem_end); /* this MUST preceed hd_init */
+#endif
 #ifdef CONFIG_BLK_DEV_HD
 	mem_start = hd_init(mem_start,mem_end);
-#endif
-#ifdef CONFIG_BLK_DEV_IDE
-	mem_start = ide_init(mem_start,mem_end);
 #endif
 #ifdef CONFIG_BLK_DEV_XD
 	mem_start = xd_init(mem_start,mem_end);
diff -u --recursive --new-file v1.3.18/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v1.3.18/linux/drivers/block/xd.c	Tue Jun 27 14:11:33 1995
+++ linux/drivers/block/xd.c	Sun Aug 13 20:19:12 1995
@@ -153,7 +153,7 @@
 
 /* xd_geninit: grab the IRQ and DMA channel, initialise the drives */
 /* and set up the "raw" device entries in the table */
-static void xd_geninit (void)
+static void xd_geninit (struct gendisk *ignored)
 {
 	u_char i,controller,*address;
 
diff -u --recursive --new-file v1.3.18/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.18/linux/drivers/char/Makefile	Wed Aug  9 14:55:39 1995
+++ linux/drivers/char/Makefile	Tue Aug 15 20:01:14 1995
@@ -9,52 +9,40 @@
 # parent makes..
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 #
 # This file contains the font map for the default (hardware) font
 #
 FONTMAPFILE = cp437.uni
 
-OBJS  = tty_io.o n_tty.o console.o keyboard.o serial.o \
+L_TARGET := char.a
+M_OBJS   :=
+L_OBJS   := tty_io.o n_tty.o console.o keyboard.o serial.o \
 	tty_ioctl.o pty.o vt.o mem.o vc_screen.o \
 	defkeymap.o consolemap.o vesa_blank.o selection.o
 
-SRCS  = tty_io.c n_tty.c console.c keyboard.c serial.c \
-	tty_ioctl.c pty.c vt.c mem.c vc_screen.c \
-	defkeymap.c consolemap.c vesa_blank.c selection.c
-
 ifdef CONFIG_CYCLADES
-OBJS := $(OBJS) cyclades.o
-SRCS := $(SRCS) cyclades.c
+L_OBJS += cyclades.o
 endif
 
 ifdef CONFIG_ATIXL_BUSMOUSE
 M = y
-OBJS := $(OBJS) atixlmouse.o
-SRCS := $(SRCS) atixlmouse.c
+L_OBJS += atixlmouse.o
 endif
 
 ifdef CONFIG_BUSMOUSE
 M = y
-OBJS := $(OBJS) busmouse.o
-SRCS := $(SRCS) busmouse.c
+L_OBJS += busmouse.o
 endif
 
 ifdef CONFIG_PRINTER
-OBJS := $(OBJS) lp.o
-SRCS := $(SRCS) lp.c
+L_OBJS += lp.o
 else
-MODULES := $(MODULES) lp.o
+M_OBJS += lp.o
 endif
 
 ifdef CONFIG_MS_BUSMOUSE
 M = y
-OBJS := $(OBJS) msbusmouse.o
-SRCS := $(SRCS) msbusmouse.c
+L_OBJS += msbusmouse.o
 endif
 
 ifdef CONFIG_82C710_MOUSE
@@ -63,56 +51,29 @@
 
 ifdef CONFIG_PSMOUSE
 M = y
-OBJS := $(OBJS) psaux.o
-SRCS := $(SRCS) psaux.c
+L_OBJS += psaux.o
 endif
 
 ifdef CONFIG_QIC02_TAPE
-OBJS := $(OBJS) tpqic02.o 
-SRCS := $(SRCS) tpqic02.c
+L_OBJS += tpqic02.o 
 endif
 
 ifdef M
-OBJS := $(OBJS) mouse.o
-SRCS := $(SRCS) mouse.c
+L_OBJS += mouse.o
 endif
   
 ifdef CONFIG_SCC
-OBJS := $(OBJS) scc.o
-SRCS := $(SRCS) scc.c
+L_OBJS += scc.o
 endif
- 
-
-all: uni_hash_tbl.h char.a
-
-char.a: $(OBJS)
-	$(AR) rcs char.a $(OBJS)
-	sync	
-
-ifdef MODULES
-
-modules: $(MODULES)
-	(cd ../../modules;for i in $(MODULES); do ln -sf ../drivers/char/$$i .; done)
-
-else
 
-modules:
+include $(TOPDIR)/Rules.make
 
-endif
+fastdep: uni_hash.tbl
 
-ifdef MODULES
-dep: uni_hash_tbl.h
-	$(CPP) -M $(SRCS) > .depend
-	$(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
-else
-dep: uni_hash_tbl.h
-	$(CPP) -M $(SRCS) > .depend
-endif
+consolemap.o:
 
 conmakehash: conmakehash.c
 	$(HOSTCC) -o conmakehash conmakehash.c
 
-uni_hash_tbl.h: $(FONTMAPFILE) conmakehash
-	./conmakehash $(FONTMAPFILE) 641 283 6 > uni_hash_tbl.h
-
-include $(TOPDIR)/Rules.make
+uni_hash.tbl: $(FONTMAPFILE) conmakehash
+	./conmakehash $(FONTMAPFILE) 641 283 6 > uni_hash.tbl
diff -u --recursive --new-file v1.3.18/linux/drivers/char/conmakehash.c linux/drivers/char/conmakehash.c
--- v1.3.18/linux/drivers/char/conmakehash.c	Tue Jun 13 15:40:16 1995
+++ linux/drivers/char/conmakehash.c	Tue Aug 15 19:32:01 1995
@@ -306,11 +306,11 @@
   
   printf("\
 /*\n\
- * uni_hash_tbl.h\n\
+ * uni_hash.tbl\n\
  *\n\
  * Do not edit this file; it was automatically generated by\n\
  *\n\
- * conmakehash %s %d %d %d > uni_hash_tbl.h\n\
+ * conmakehash %s %d %d %d > uni_hash.tbl\n\
  *\n\
  */\n\
 \n\
diff -u --recursive --new-file v1.3.18/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v1.3.18/linux/drivers/char/consolemap.c	Thu Jun 29 19:02:40 1995
+++ linux/drivers/char/consolemap.c	Tue Aug 15 19:32:01 1995
@@ -294,7 +294,7 @@
  * Usually, the mapping will be loaded simultaneously with the font.
  */
 
-#include "uni_hash_tbl.h"	/* Include hash tables & parameters */
+#include "uni_hash.tbl"		/* Include hash tables & parameters */
 
 int hashtable_contents_valid = 1;
 
diff -u --recursive --new-file v1.3.18/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.3.18/linux/drivers/char/serial.c	Sun Aug 13 14:45:29 1995
+++ linux/drivers/char/serial.c	Tue Aug 15 07:05:35 1995
@@ -2442,7 +2442,7 @@
 
 /*
  * This routine is called by rs_init() to initialize a specific serial
- * port.  It determines what type of UART ship this serial port is
+ * port.  It determines what type of UART chip this serial port is
  * using: 8250, 16450, 16550, 16550A.  The important question is
  * whether or not this UART is a 16550A or not, since this will
  * determine whether or not we can use its FIFO features or not.
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v1.3.18/linux/drivers/net/3c501.c	Wed Aug  2 13:21:02 1995
+++ linux/drivers/net/3c501.c	Tue Aug 15 18:08:32 1995
@@ -676,11 +676,12 @@
 }
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_3c501 = {
-	"        " /*"3c501"*/, 
-		0, 0, 0, 0,
-	 	0x280, 5,
-	 	0, 0, 0, NULL, el1_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0x280, 5,
+	0, 0, 0, NULL, el1_probe };
 
 int io=0x280;
 int irq=5;
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v1.3.18/linux/drivers/net/3c503.c	Sun Aug 13 14:45:30 1995
+++ linux/drivers/net/3c503.c	Tue Aug 15 18:08:32 1995
@@ -40,12 +40,11 @@
 #include <asm/system.h>
 
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 
 #include "8390.h"
 #include "3c503.h"
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-				    unsigned long *mem_startp);
 
 int el2_probe(struct device *dev);
 int el2_pio_probe(struct device *dev);
@@ -486,7 +485,7 @@
 	el2pio_drv.irq       = irq;
 
 	if (io == 0)
-	  printk("3c503: You should not use auto-probing with insmod!\n");
+	    printk("3c503: You should not use auto-probing with insmod!\n");
 
 	rc2 = 0;
 	no_pio = 1;
@@ -507,11 +506,19 @@
 	if (MOD_IN_USE)
 		printk("3c503: device busy, remove delayed\n");
 	else {
+	    int ioaddr;
+
 	    if (no_pio) {
+		ioaddr = el2_drv.base_addr;
 		unregister_netdev(&el2_drv);
 	    } else {
+		ioaddr = el2pio_drv.base_addr;
 		unregister_netdev(&el2pio_drv);
 	    }
+
+	    /* If we don't do this, we can't re-insmod it later. */
+	    release_region(ioaddr, EL2_IO_EXTENT);
+
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v1.3.18/linux/drivers/net/3c505.c	Sun Aug 13 14:45:30 1995
+++ linux/drivers/net/3c505.c	Tue Aug 15 18:08:32 1995
@@ -1449,7 +1449,7 @@
 	/*
 	 * and reserve the address region
 	 */
-	request_region(dev->base_addr,16,"3c505");
+	request_region(dev->base_addr, ELP_IO_EXTENT, "3c505");
 
 	/*
 	 * initialise the device
@@ -1459,8 +1459,12 @@
 }
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_3c505 = {
-	"        " /*"3c505"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elplus_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, elplus_probe };
 
 int io = 0x300;
 int irq = 0;
@@ -1468,7 +1472,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("3c505: You should not use auto-probing with insmod!\n");
+		printk("3c505: You should not use auto-probing with insmod!\n");
 	dev_3c505.base_addr = io;
 	dev_3c505.irq       = irq;
 	if (register_netdev(&dev_3c505) != 0) {
@@ -1486,6 +1490,9 @@
 	else
 	{
 		unregister_netdev(&dev_3c505);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(dev_3c505.base_addr, ELP_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c505.h linux/drivers/net/3c505.h
--- v1.3.18/linux/drivers/net/3c505.h	Tue Jun  6 11:22:06 1995
+++ linux/drivers/net/3c505.h	Tue Aug 15 18:08:32 1995
@@ -13,6 +13,8 @@
 #define	PORT_DATA	0x04	/* read/write, 16-bit */
 #define	PORT_CONTROL	0x06	/* read/write, 8-bit */
 
+#define ELP_IO_EXTENT	0x10	/* size of used IO registers */
+
 /*
  * host control registers bits
  */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v1.3.18/linux/drivers/net/3c507.c	Sun Aug 13 14:45:30 1995
+++ linux/drivers/net/3c507.c	Tue Aug 15 18:08:32 1995
@@ -65,9 +65,6 @@
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
-
 
 /* use 0 for production, 1 for verification, 2..7 for debug */
 #ifndef NET_DEBUG
@@ -376,7 +373,7 @@
 	}
 	
 	/* We've committed to using the board, and can start filling in *dev. */
-	request_region(ioaddr, EL16_IO_EXTENT,"3c507");
+	request_region(ioaddr, EL16_IO_EXTENT, "3c507");
 	dev->base_addr = ioaddr;
 
 	outb(0x01, ioaddr + MISC_CTRL);
@@ -885,8 +882,13 @@
 }
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_3c507 = {
-	"        " /*"3c507"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, el16_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, el16_probe
+};
 
 int io = 0x300;
 int irq = 0;
@@ -894,7 +896,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("3c507: You should not use auto-probing with insmod!\n");
+		printk("3c507: You should not use auto-probing with insmod!\n");
 	dev_3c507.base_addr = io;
 	dev_3c507.irq       = irq;
 	if (register_netdev(&dev_3c507) != 0) {
@@ -912,6 +914,10 @@
 	else
 	{
 		unregister_netdev(&dev_3c507);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_3c507.irq);
+		release_region(dev_3c507.base_addr, EL16_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
@@ -925,4 +931,3 @@
  *  c-indent-level: 4
  * End:
  */
-
diff -u --recursive --new-file v1.3.18/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v1.3.18/linux/drivers/net/3c509.c	Sun Aug 13 14:45:30 1995
+++ linux/drivers/net/3c509.c	Tue Aug 15 18:08:33 1995
@@ -65,6 +65,8 @@
 #define ID_PORT 0x100
 #define	 EEPROM_READ 0x80
 
+#define EL3_IO_EXTENT	16
+
 #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
 
 
@@ -232,7 +234,7 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 	dev->if_port = if_port;
-	request_region(dev->base_addr, 16,"3c509");
+	request_region(dev->base_addr, EL3_IO_EXTENT, "3c509");
 
 	{
 		const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
@@ -703,8 +705,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_3c509 = {
-	"        " /*"3c509"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, el3_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, el3_probe };
 
 int io = 0;
 int irq = 0;
@@ -732,6 +738,8 @@
 		unregister_netdev(&dev_3c509);
 		kfree_s(dev_3c509.priv,sizeof(struct el3_private));
 		dev_3c509.priv=NULL;
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.18/linux/drivers/net/Makefile	Wed Aug  9 14:55:39 1995
+++ linux/drivers/net/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,341 +7,320 @@
 # are difficult for users to deal with.
 include CONFIG
 
-# Build MODULES by appending to this string for every driver below
-MODULES :=
-
-NETDRV_OBJS := Space.o auto_irq.o net_init.o loopback.o
-
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-
-# The point of the makefile...
-all: net.a
-
-Space.o: Space.c ../../include/linux/autoconf.h
-	$(CC) $(CFLAGS) $(OPTS) -c $<
-
-net_init.o: ../../include/linux/autoconf.h
+L_TARGET := net.a
+L_OBJS   := Space.o auto_irq.o net_init.o loopback.o
+M_OBJS   :=
+MOD_LIST_NAME := NET_MODULES
 
 ifdef CONFIG_SEEQ8005
-NETDRV_OBJS := $(NETDRV_OBJS) seeq8005.o
+L_OBJS += seeq8005.o
 endif
 
 ifdef CONFIG_IBMTR
-NETDRV_OBJS := $(NETDRV_OBJS) ibmtr.o
+L_OBJS += ibmtr.o
 else
-MODULES := $(MODULES) ibmtr.o
+M_OBJS += ibmtr.o
 endif
 
 ifdef CONFIG_SK_G16
-NETDRV_OBJS := $(NETDRV_OBJS) sk_g16.o
+L_OBJS += sk_g16.o
 endif
 
 ifdef CONFIG_NET_IPIP
-NETDRV_OBJS := $(NETDRV_OBJS) tunnel.o
+L_OBJS += tunnel.o
 else
-MODULES := $(MODULES) tunnel.o
+M_OBJS += tunnel.o
 endif
 
 ifdef CONFIG_HP100
-NETDRV_OBJS := $(NETDRV_OBJS) hp100.o
+L_OBJS += hp100.o
 else
-MODULES := $(MODULES) hp100.o
+M_OBJS += hp100.o
 endif
 
 ifdef CONFIG_WD80x3
-NETDRV_OBJS := $(NETDRV_OBJS) wd.o
+L_OBJS += wd.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) wd.o
+M_OBJS += wd.o
 endif
-wd.o:	wd.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
 
 ifdef CONFIG_EL2
-NETDRV_OBJS := $(NETDRV_OBJS) 3c503.o
+L_OBJS += 3c503.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) 3c503.o
+M_OBJS += 3c503.o
 endif
-3c503.o:	3c503.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $<
 
 ifdef CONFIG_NE2000
-NETDRV_OBJS := $(NETDRV_OBJS) ne.o
+L_OBJS += ne.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) ne.o
+M_OBJS += ne.o
 endif
-ne.o:	ne.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $<
 
 ifdef CONFIG_HPLAN
-NETDRV_OBJS := $(NETDRV_OBJS) hp.o
+L_OBJS += hp.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) hp.o
+M_OBJS += hp.o
 endif
-hp.o:	hp.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $<
 
 ifdef CONFIG_HPLAN_PLUS
-NETDRV_OBJS := $(NETDRV_OBJS) hp-plus.o
+L_OBJS += hp-plus.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) hp-plus.o
+M_OBJS += hp-plus.o
 endif
 
 ifdef CONFIG_ULTRA
-NETDRV_OBJS := $(NETDRV_OBJS) smc-ultra.o
+L_OBJS += smc-ultra.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) smc-ultra.o
+M_OBJS += smc-ultra.o
 endif
 
 ifdef CONFIG_E2100
-NETDRV_OBJS := $(NETDRV_OBJS) e2100.o
+L_OBJS += e2100.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) e2100.o
+M_OBJS += e2100.o
 endif
 
 ifdef CONFIG_PLIP
-NETDRV_OBJS := $(NETDRV_OBJS) plip.o
+L_OBJS += plip.o
 else
-MODULES := $(MODULES) plip.o
+M_OBJS += plip.o
 endif
-plip.o:	plip.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
 
 ifdef CONFIG_PPP
-NETDRV_OBJS := $(NETDRV_OBJS) ppp.o
+L_OBJS += ppp.o
 CONFIG_SLHC = CONFIG_SLHC
 else
-MODULES := $(MODULES) ppp.o
+M_OBJS += ppp.o
 endif
 
 ifdef CONFIG_SLIP
-NETDRV_OBJS := $(NETDRV_OBJS) slip.o
+L_OBJS += slip.o
 CONFIG_SLHC = CONFIG_SLHC
 else
-MODULES := $(MODULES) slip.o
+M_OBJS += slip.o
 endif
-slip.o:	slip.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
 
 ifdef CONFIG_DE650
-ETDRV_OBJS := $(NETDRV_OBJS) de650.o
+ETDRV_OBJS := $(L_OBJS) de650.o
 CONFIG_8390 = CONFIG_8390
 endif
 
 ifdef CONFIG_3C589
-NETDRV_OBJS := $(NETDRV_OBJS) 3c589.o
+L_OBJS += 3c589.o
 endif
 
 ifdef CONFIG_DUMMY
-NETDRV_OBJS := $(NETDRV_OBJS) dummy.o
+L_OBJS += dummy.o
 else
-MODULES := $(MODULES) dummy.o
+M_OBJS += dummy.o
 endif
-dummy.o: dummy.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
 
 ifdef CONFIG_DE600
-NETDRV_OBJS := $(NETDRV_OBJS) de600.o
+L_OBJS += de600.o
 else
-MODULES := $(MODULES) de600.o
+M_OBJS += de600.o
 endif
-de600.o: de600.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE600_OPTS) -c $<
 	
 ifdef CONFIG_DE620
-NETDRV_OBJS := $(NETDRV_OBJS) de620.o
+L_OBJS += de620.o
 else
-MODULES := $(MODULES) de620.o
+M_OBJS += de620.o
 endif
-de620.o: de620.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $<
 	
 ifdef CONFIG_AT1500
-NETDRV_OBJS := $(NETDRV_OBJS) lance.o
+L_OBJS += lance.o
 endif
 
 ifdef CONFIG_LANCE
-NETDRV_OBJS := $(NETDRV_OBJS) lance.o
+L_OBJS += lance.o
 endif
 
 ifdef CONFIG_AT1700
-NETDRV_OBJS := $(NETDRV_OBJS) at1700.o
+L_OBJS += at1700.o
 else
-MODULES := $(MODULES) at1700.o
+M_OBJS += at1700.o
 endif
 
 ifdef CONFIG_EL1
-NETDRV_OBJS := $(NETDRV_OBJS) 3c501.o
+L_OBJS += 3c501.o
 else
-MODULES := $(MODULES) 3c501.o
+M_OBJS += 3c501.o
 endif
 
 ifdef CONFIG_EL16
-NETDRV_OBJS := $(NETDRV_OBJS) 3c507.o
+L_OBJS += 3c507.o
 else
-MODULES ;= $(MODULES 3c507.o
+M_OBJS += 3c507.o
 endif
 
 ifdef CONFIG_EL3
-NETDRV_OBJS := $(NETDRV_OBJS) 3c509.o
+L_OBJS += 3c509.o
 else
-MODULES := $(MODULES) 3c509.o
+M_OBJS += 3c509.o
 endif
 
 ifdef CONFIG_EEXPRESS
-NETDRV_OBJS := $(NETDRV_OBJS) eexpress.o
+L_OBJS += eexpress.o
 else
-MODULES := $(MODULES) eexpress.o
+M_OBJS += eexpress.o
 endif
 
 ifdef CONFIG_EEXPRESS_PRO
-NETDRV_OBJS := $(NETDRV_OBJS) eepro.o
+L_OBJS += eepro.o
 else
-MODULES := $(MODULES) eepro.o
+M_OBJS += eepro.o
 endif
 
 ifdef CONFIG_WAVELAN
-NETDRV_OBJS := $(NETDRV_OBJS) wavelan.o
+L_OBJS += wavelan.o
 else
-MODULES := $(MODULES) wavelan.o
+M_OBJS += wavelan.o
 endif
 
 ifdef CONFIG_ZNET
-NETDRV_OBJS := $(NETDRV_OBJS) znet.o
+L_OBJS += znet.o
 endif
 
 ifdef CONFIG_DEPCA
-NETDRV_OBJS := $(NETDRV_OBJS) depca.o
+L_OBJS += depca.o
 else
-MODULES := $(MODULES) depca.o
+M_OBJS += depca.o
 endif
-depca.o: depca.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 
 ifdef CONFIG_EWRK3
-NETDRV_OBJS := $(NETDRV_OBJS) ewrk3.o
+L_OBJS += ewrk3.o
 else
-MODULES := $(MODULES) ewrk3.o
+M_OBJS += ewrk3.o
 endif
-ewrk3.o: ewrk3.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
 
 ifdef CONFIG_ATP
-NETDRV_OBJS := $(NETDRV_OBJS) atp.o
+L_OBJS += atp.o
 endif
 
 ifdef CONFIG_DE4X5
-NETDRV_OBJS := $(NETDRV_OBJS) de4x5.o
+L_OBJS += de4x5.o
 else
-MODULES := $(MODULES) de4x5.o
+M_OBJS += de4x5.o
 endif
-de4x5.o: de4x5.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
 
 ifdef CONFIG_NI52
-NETDRV_OBJS := $(NETDRV_OBJS) ni52.o
+L_OBJS += ni52.o
 endif
 
 ifdef CONFIG_NI65
-NETDRV_OBJS := $(NETDRV_OBJS) ni65.o
+L_OBJS += ni65.o
 endif
 
 ifdef CONFIG_ELPLUS
-NETDRV_OBJS := $(NETDRV_OBJS) 3c505.o
+L_OBJS += 3c505.o
 else
-MODULES := $(MODULES) 3c505.o
+M_OBJS += 3c505.o
 endif
-3c505.o: 3c505.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(ELP_OPTS) -c $<
 
 ifdef CONFIG_AC3200
-NETDRV_OBJS := $(NETDRV_OBJS) ac3200.o
+L_OBJS += ac3200.o
 CONFIG_8390 = CONFIG_8390
 else
-MODULES := $(MODULES) ac3200.o
+M_OBJS += ac3200.o
 endif
 
 ifdef CONFIG_APRICOT
-NETDRV_OBJS := $(NETDRV_OBJS) apricot.o
+L_OBJS += apricot.o
 else
-MODULES := $(MODULES) apricot.o
+M_OBJS += apricot.o
 endif
 
 ifdef CONFIG_DEC_ELCP
-NETDRV_OBJS := $(NETDRV_OBJS) tulip.o
+L_OBJS += tulip.o
 else
-MODULES := $(MODULES) tulip.o
+M_OBJS += tulip.o
 endif
 
 ifdef CONFIG_ARCNET
-NETDRV_OBJS := $(NETDRV_OBJS) arcnet.o
+L_OBJS += arcnet.o
 else
-MODULES := $(MODULES) arcnet.o
+M_OBJS += arcnet.o
 endif
 
 ifdef CONFIG_PI
-NETDRV_OBJS := $(NETDRV_OBJS) pi2.o
+L_OBJS += pi2.o
 CONFIG_PI = CONFIG_PI
 endif
-pi2.o:  pi2.c CONFIG
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(PI_OPTS) -c $<
 
 ifdef CONFIG_SLHC
-NETDRV_OBJS := $(NETDRV_OBJS) slhc.o
+L_OBJS += slhc.o
 else
-MODULES := slhc.o $(MODULES)
+M_OBJS += slhc.o
 endif
 
 ifdef CONFIG_8390
-NETDRV_OBJS := $(NETDRV_OBJS) 8390.o
+L_OBJS += 8390.o
 else
-MODULES := 8390.o $(MODULES)
+M_OBJS += 8390.o
 endif
-8390.o: 8390.c 8390.h CONFIG
 
 ifdef CONFIG_EQUALIZER
-NETDRV_OBJS := $(NETDRV_OBJS) eql.o
+L_OBJS += eql.o
 else
-MODULES := $(MODULES) eql.o
+M_OBJS += eql.o
 endif
 
-net.a: $(NETDRV_OBJS)
-	rm -f net.a
-	$(AR) rcs net.a $(NETDRV_OBJS)
+include $(TOPDIR)/Rules.make
 
 clean:
 	rm -f core *.o *.a *.s
 
-ifdef MODULES
-dep:
-	$(CPP) -M $(NETDRV_OBJS:.o=.c) > .depend
-	$(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
-else
-dep:
-	$(CPP) -M $(NETDRV_OBJS:.o=.c) > .depend
-endif
+wd.o:	wd.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $<
 
-tar:
+3c503.o:	3c503.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $<
+
+pi2.o:  pi2.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(PI_OPTS) -c $<
 
-ifdef MODULES
+3c505.o: 3c505.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(ELP_OPTS) -c $<
 
-modules: $(MODULES)
-	echo $(MODULES) > ../../modules/NET_MODULES
-	cd ../../modules; \
-		for i in $(MODULES); do ln -sf ../drivers/net/$$i .; done
+de4x5.o: de4x5.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
 
-else
+ewrk3.o: ewrk3.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
 
-modules:
+depca.o: depca.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 
-endif
+Space.o: ../../include/linux/autoconf.h
 
-include $(TOPDIR)/Rules.make
+net_init.o: ../../include/linux/autoconf.h
+
+ne.o:	ne.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $<
+
+hp.o:	hp.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $<
+
+plip.o:	plip.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $<
+
+slip.o:	slip.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+dummy.o: dummy.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+de600.o: de600.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE600_OPTS) -c $<
+
+de620.o: de620.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $<
+
+8390.o: 8390.c 8390.h CONFIG
diff -u --recursive --new-file v1.3.18/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v1.3.18/linux/drivers/net/ac3200.c	Wed Aug  9 14:55:39 1995
+++ linux/drivers/net/ac3200.c	Tue Aug 15 18:08:33 1995
@@ -44,6 +44,15 @@
 #define  AC_ENABLE		 0x01
 #define AC_CONFIG		0xC90	/* The configuration port. */
 
+#define AC_IO_EXTENT 0x10		/* IS THIS REALLY TRUE ??? */
+                                /* Actually accessed is:
+								 * AC_NIC_BASE (0-15)
+								 * AC_SA_PROM (0-5)
+								 * AC_ID_PORT (0-3)
+								 * AC_RESET_PORT
+								 * AC_CONFIG
+								 */
+
 /* Decoding of the configuration register. */
 static unsigned char config2irqmap[8] = {15, 12, 11, 10, 9, 7, 5, 3};
 static int addrmap[8] =
@@ -144,9 +153,11 @@
 
 	if (request_irq(dev->irq, ei_interrupt, 0, "ac3200")) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
-		return 0;
+		return EAGAIN;
 	}
 
+	request_region(ioaddr, AC_IO_EXTENT, "ac3200");
+
 	dev->base_addr = ioaddr;
 
 #ifdef notyet
@@ -281,8 +292,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_ac3200 = {
-	"        " /*"ac3200"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ac3200_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, ac3200_probe };
 
 int io = 0;
 int irq = 0;
@@ -306,6 +321,10 @@
 	else
 	{
 		unregister_netdev(&dev_ac3200);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_ac3200.irq);
+		release_region(dev_ac3200.base_addr, AC_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v1.3.18/linux/drivers/net/apricot.c	Wed Aug  9 14:55:39 1995
+++ linux/drivers/net/apricot.c	Tue Aug 15 18:08:33 1995
@@ -714,7 +714,7 @@
     if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0)
     	return ENODEV;
 
-    request_region(ioaddr, APRICOT_TOTAL_SIZE,"apricot");
+    request_region(ioaddr, APRICOT_TOTAL_SIZE, "apricot");
 
     dev->base_addr = ioaddr;
     ether_setup(dev);
@@ -1014,8 +1014,9 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_apricot = {
-  "        ", /* device name inserted by /linux/drivers/net/net_init.c */
+  devicename, /* device name inserted by /linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0x300, 10,
   0, 0, 0, NULL, apricot_probe };
@@ -1043,6 +1044,9 @@
     unregister_netdev(&dev_apricot);
     kfree_s((void *)dev_apricot.mem_start, sizeof(struct i596_private) + 0xf);
     dev_apricot.priv = NULL;
+
+    /* If we don't do this, we can't re-insmod it later. */
+    release_region(dev_apricot.base_addr, APRICOT_TOTAL_SIZE);
   }
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.18/linux/drivers/net/arcnet.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/arcnet.c	Tue Aug 15 18:50:14 1995
@@ -193,6 +193,7 @@
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/if_arp.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -2447,11 +2448,13 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device thiscard = {
-  "       ",/* if blank, device name inserted by /linux/drivers/net/net_init.c */
+  devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0, 0,  /* I/O address, IRQ */
-  0, 0, 0, NULL, arcnet_probe };
+  0, 0, 0, NULL, arcnet_probe
+};
 	
 	
 int io=0x0;	/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v1.3.18/linux/drivers/net/at1700.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/at1700.c	Tue Aug 15 18:08:33 1995
@@ -629,8 +629,12 @@
 }
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_at1700 = {
-	"        " /*"at1700"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, at1700_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, at1700_probe };
 
 int io = 0x260;
 int irq = 0;
@@ -638,7 +642,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("at1700: You should not use auto-probing with insmod!\n");
+		printk("at1700: You should not use auto-probing with insmod!\n");
 	dev_at1700.base_addr = io;
 	dev_at1700.irq       = irq;
 	if (register_netdev(&dev_at1700) != 0) {
@@ -656,6 +660,11 @@
 	else
 	{
 		unregister_netdev(&dev_at1700);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_at1700.irq);
+		irq2dev_map[dev_at1700.irq] = NULL;
+		release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c
--- v1.3.18/linux/drivers/net/auto_irq.c	Tue Jul 11 10:02:49 1995
+++ linux/drivers/net/auto_irq.c	Tue Aug 15 18:08:33 1995
@@ -28,7 +28,7 @@
 
 
 #ifdef version
-static char *version=
+static const char *version=
 "auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)";
 #endif
 
diff -u --recursive --new-file v1.3.18/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v1.3.18/linux/drivers/net/de4x5.c	Tue Aug  8 12:31:35 1995
+++ linux/drivers/net/de4x5.c	Tue Aug 15 18:08:33 1995
@@ -2735,8 +2735,9 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device thisDE4X5 = {
-  "        ", /* device name inserted by /linux/drivers/net/net_init.c */
+  devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0x2000, 10, /* I/O address, IRQ */
   0, 0, 0, NULL, de4x5_probe };
diff -u --recursive --new-file v1.3.18/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v1.3.18/linux/drivers/net/depca.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/depca.c	Tue Aug 15 18:08:33 1995
@@ -1817,8 +1817,9 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device thisDepca = {
-  "        ",  /* device name inserted by /linux/drivers/net/net_init.c */
+  devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0x200, 7,   /* I/O address, IRQ */
   0, 0, 0, NULL, depca_probe };
diff -u --recursive --new-file v1.3.18/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v1.3.18/linux/drivers/net/e2100.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/e2100.c	Tue Aug 15 18:08:33 1995
@@ -151,9 +151,6 @@
 	if (status != 0x21 && status != 0x23)
 		return ENODEV;
 
-	/* Grab the region so we can find a different board if IRQ select fails. */
-	request_region(ioaddr, E21_IO_EXTENT,"e2100");
-
 	/* Read the station address PROM.  */
 	for (i = 0; i < 6; i++)
 		station_addr[i] = inb(ioaddr + E21_SAPROM + i);
@@ -179,6 +176,9 @@
 	} else if (dev->irq == 2)	/* Fixup luser bogosity: IRQ2 is really IRQ9 */
 		dev->irq = 9;
 
+	/* Grab the region so we can find a different board if IRQ select fails. */
+	request_region(ioaddr, E21_IO_EXTENT, "e2100");
+
 	/* The 8390 is at the base address. */
 	dev->base_addr = ioaddr;
 
@@ -356,8 +356,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_e2100 = {
-	"        " /*"e2100"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, e2100_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, e2100_probe };
 
 int io = 0x300;
 int irq = 0;
@@ -365,7 +369,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("e2100: You should not use auto-probing with insmod!\n");
+		printk("e2100: You should not use auto-probing with insmod!\n");
 	dev_e2100.base_addr = io;
 	dev_e2100.irq       = irq;
 	if (register_netdev(&dev_e2100) != 0) {
@@ -383,6 +387,9 @@
 	else
 	{
 		unregister_netdev(&dev_e2100);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(dev_e2100.base_addr, E21_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v1.3.18/linux/drivers/net/eepro.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/eepro.c	Tue Aug 15 18:08:33 1995
@@ -404,7 +404,7 @@
 				printk(version);
 
 			/* Grab the region so we can find another board if autoIRQ fails. */
-			request_region(ioaddr, EEPRO_IO_EXTENT,"eepro");
+			request_region(ioaddr, EEPRO_IO_EXTENT, "eepro");
 
 			/* Initialize the device structure */
 			if (dev->priv == NULL)
@@ -756,9 +756,6 @@
 
 	irq2dev_map[dev->irq] = 0;
 
-	/* release the ioport-region */
-	release_region(ioaddr, 16);
-
 	/* Update the statistics here. What statistics? */
 
 	/* We are supposed to wait for 200 us after a RESET */
@@ -1133,8 +1130,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_eepro = {
-	"        " /*"eepro"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, eepro_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, eepro_probe };
 
 int io = 0x200;
 int irq = 0;
@@ -1143,7 +1144,7 @@
 init_module(void)
 {
 	if (io == 0)
-	  printk("eepro: You should not use auto-probing with insmod!\n");
+		printk("eepro: You should not use auto-probing with insmod!\n");
 	dev_eepro.base_addr = io;
 	dev_eepro.irq       = irq;
 
@@ -1162,6 +1163,9 @@
 		unregister_netdev(&dev_eepro);
 		kfree_s(dev_eepro.priv,sizeof(struct eepro_local));
 		dev_eepro.priv=NULL;
+
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(dev_eepro.base_addr, EEPRO_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.3.18/linux/drivers/net/eexpress.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/eexpress.c	Tue Aug 15 18:08:33 1995
@@ -1,4 +1,3 @@
-
 /* eexpress.c: Intel EtherExpress device driver for Linux. */
 /*
 	Written 1993 by Donald Becker.
@@ -146,6 +145,8 @@
 #define EEPROM_Ctrl		14
 #define ID_PORT		15
 
+#define EEXPRESS_IO_EXTENT 16
+
 /*	EEPROM_Ctrl bits. */
 
 #define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */
@@ -363,7 +364,7 @@
 	}
 
 	/* We've committed to using the board, and can start filling in *dev. */
-	request_region(ioaddr, 16,"eexpress");
+	request_region(ioaddr, EEXPRESS_IO_EXTENT, "eexpress");
 	dev->base_addr = ioaddr;
 
 	for (i = 0; i < 6; i++) {
@@ -654,9 +655,6 @@
 
 	irq2dev_map[dev->irq] = 0;
 
-	/* release the ioport-region */
-	release_region(ioaddr, 16);
-
 	/* Update the statistics here. */
 
 #ifdef MODULE
@@ -1002,8 +1000,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_eexpress = {
-	"        " /*"eexpress"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, express_probe };
 	
 
 int irq=0x300;
@@ -1013,7 +1015,7 @@
 init_module(void)
 {
 	if (io == 0)
-	  printk("eexpress: You should not use auto-probing with insmod!\n");
+		printk("eexpress: You should not use auto-probing with insmod!\n");
 	dev_eexpress.base_addr=io;
 	dev_eexpress.irq=irq;
 	if (register_netdev(&dev_eexpress) != 0)
@@ -1025,12 +1027,15 @@
 cleanup_module(void)
 {
 	if (MOD_IN_USE)
-		printk("express: device busy, remove delayed\n");
+		printk("eexpress: device busy, remove delayed\n");
 	else
 	{
 		unregister_netdev(&dev_eexpress);
 		kfree_s(dev_eexpress.priv,sizeof(struct net_local));
 		dev_eexpress.priv=NULL;
+
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(dev_eexpress.base_addr, EEXPRESS_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v1.3.18/linux/drivers/net/eql.c	Wed Aug  9 14:55:40 1995
+++ linux/drivers/net/eql.c	Tue Aug 15 18:50:52 1995
@@ -126,6 +126,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/if.h>
+#include <linux/if_arp.h>
 #include <linux/timer.h>
 
 #include <linux/if_eql.h>
diff -u --recursive --new-file v1.3.18/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v1.3.18/linux/drivers/net/ewrk3.c	Wed Aug  2 13:21:04 1995
+++ linux/drivers/net/ewrk3.c	Tue Aug 15 18:08:33 1995
@@ -1855,8 +1855,9 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device thisEthwrk = {
-  "        ", /* device name inserted by /linux/drivers/net/net_init.c */
+  devicename, /* device name is inserted by linux/drivers/net/net_init.c */
   0, 0, 0, 0,
   0x300, 5,  /* I/O address, IRQ */
   0, 0, 0, NULL, ewrk3_probe };
diff -u --recursive --new-file v1.3.18/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v1.3.18/linux/drivers/net/hp-plus.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/hp-plus.c	Tue Aug 15 18:08:33 1995
@@ -367,8 +367,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_hp = {
-	"        " /*"hp"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, hp_plus_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, hp_plus_probe };
 
 int io = 0x200;
 int irq = 0;
@@ -376,11 +380,11 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("HP-plus: You should not use auto-probing with insmod!\n");
+		printk("HP-plus: You should not use auto-probing with insmod!\n");
 	dev_hp.base_addr = io;
 	dev_hp.irq       = irq;
 	if (register_netdev(&dev_hp) != 0) {
-		printk("hp: register_netdev() returned non-zero.\n");
+		printk("HP-plus: register_netdev() returned non-zero.\n");
 		return -EIO;
 	}
 	return 0;
@@ -390,10 +394,15 @@
 cleanup_module(void)
 {
 	if (MOD_IN_USE)
-		printk("hp: device busy, remove delayed\n");
+		printk("HP-plus: device busy, remove delayed\n");
 	else
 	{
+		int ioaddr = dev_hp.base_addr - NIC_OFFSET;
+
 		unregister_netdev(&dev_hp);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		release_region(ioaddr, HP_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v1.3.18/linux/drivers/net/hp.c	Sun Aug 13 14:45:31 1995
+++ linux/drivers/net/hp.c	Tue Aug 15 18:08:33 1995
@@ -35,11 +35,9 @@
 #include <asm/io.h>
 
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include "8390.h"
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
-
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int hppclan_portlist[] =
 { 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
@@ -130,9 +128,6 @@
 	if (dev == NULL)
 		dev = init_etherdev(0, sizeof(struct ei_device), 0);
 
-	/* Grab the region so we can find another board if something fails. */
-	request_region(ioaddr, HP_IO_EXTENT,"hp");
-
 	printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
 
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
@@ -171,6 +166,9 @@
 		}
 	}
 
+	/* Grab the region so we can find another board if something fails. */
+	request_region(ioaddr, HP_IO_EXTENT,"hp");
+
 	if (ei_debug > 1)
 		printk(version);
 
@@ -327,8 +325,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_hp = {
-	"        " /*"hp"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, hp_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, hp_probe };
 
 int io = 300;
 int irq = 0;
@@ -336,7 +338,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("hp: You should not use auto-probing with insmod!\n");
+		printk("hp: You should not use auto-probing with insmod!\n");
 	dev_hp.base_addr = io;
 	dev_hp.irq       = irq;
 	if (register_netdev(&dev_hp) != 0) {
@@ -353,7 +355,13 @@
 		printk("hp: device busy, remove delayed\n");
 	else
 	{
+		int ioaddr = dev_hp.base_addr - NIC_OFFSET;
+
 		unregister_netdev(&dev_hp);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_hp.irq);
+		release_region(ioaddr, HP_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v1.3.18/linux/drivers/net/hp100.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/hp100.c	Tue Aug 15 18:08:33 1995
@@ -1129,8 +1129,12 @@
 
 static int hp100_port = -1;
 
+static char devicename[9] = { 0, };
 static struct device dev_hp100 = {
-  "        ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, hp100_probe
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, hp100_probe
 };
 
 int init_module( void )
diff -u --recursive --new-file v1.3.18/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v1.3.18/linux/drivers/net/ibmtr.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/ibmtr.c	Tue Aug 15 18:08:33 1995
@@ -144,7 +144,8 @@
      which references it.
  */
 
-int tok_probe(struct device *dev) {
+int tok_probe(struct device *dev)
+{
 
   unsigned char segment=0, intr=0, irq=0, i=0, j=0,
                 cardpresent=NOTOK,temp=0;
@@ -166,11 +167,12 @@
     PIOaddr=TokBaseAddrs[iAddr];  /* address to try           */
     TokBaseAddrs[iAddr] = 0;      /* (and marked already used */
     if (PIOaddr == 0) continue;   /* already tried this addr */
-    if ( check_region(PIOaddr,4) ) { /* Make sure PIO address not
-                                    already assigned elsewhere before
-                                    we muck with I/O addresses */
+    if ( check_region(PIOaddr,TR_IO_EXTENT) ) { /* Make sure PIO address not
+						   already assigned elsewhere
+						   before we muck with I/O
+						   addresses */
       if (ibmtr_debug_trace & TRC_INIT)
-                DPRINTK("check_region(%4hx,4) failed.\n",PIOaddr);
+	DPRINTK("check_region(%4hx,%d) failed.\n",PIOaddr, TR_IO_EXTENT);
       PIOaddr = 0; continue; /* clear to flag fail and try next */
     }
            /*  Query the adapter PIO base port which will return
@@ -247,12 +249,13 @@
   }
 
   /*?? Now, allocate some of the pl0 buffers for this driver.. */
-  /*?? Now, allocate some of the PIO PORTs for this driver.. */
-  request_region(PIOaddr,4,"ibmtr");  /* record PIOaddr range as busy */
 
   if (!badti)
     ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-  else { ti = badti; badti = NULL; }/*?? dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); */
+  else {
+    ti = badti; badti = NULL;
+  }/*?? dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); */
+
   memset(ti,0,sizeof(struct tok_info));
 
   ti->mmio= t_mmio;
@@ -303,17 +306,17 @@
     printk(".\n");
   }
 
-	DPRINTK("hw address: ");
-	/* Get hw address of token ring card */
-	j=0;
-	for (i=0; i<0x18; i=i+2) {
-		temp = *(char *)((ulong)AIP + (ulong)i + ti->mmio) & 0x0f; /* Tech ref states must do this */
-		printk("%1X",ti->hw_address[j]=temp);
-		if(j&1)
-			dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
-		++j;
-	}
-	printk("\n");
+  DPRINTK("hw address: ");
+  /* Get hw address of token ring card */
+  j=0;
+  for (i=0; i<0x18; i=i+2) {
+    temp = *(char *)((ulong)AIP + (ulong)i + ti->mmio) & 0x0f; /* Tech ref states must do this */
+    printk("%1X",ti->hw_address[j]=temp);
+    if(j&1)
+      dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
+    ++j;
+  }
+  printk("\n");
 
   /* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
   ti->adapter_type = *(char *)(ti->mmio + AIPADAPTYPE);
@@ -337,9 +340,9 @@
   /* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
   ti->dhb_size16mb = *(char *)(ti->mmio + AIP16MBDHB);
 
-	DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
-		ti->data_rate, ti->token_release, ti->avail_shared_ram/2, ti->shared_ram_paging, ti->dhb_size4mb,
-		ti->dhb_size16mb);
+  DPRINTK("atype=%x, drate=%x, trel=%x, asram=%dK, srp=%x, dhb(4mb=%x, 16mb=%x)\n",ti->adapter_type,
+	  ti->data_rate, ti->token_release, ti->avail_shared_ram/2, ti->shared_ram_paging,
+	  ti->dhb_size4mb, ti->dhb_size16mb);
 
   /* We must figure out how much shared memory space this adapter
      will occupy so that if there are two adapters we can fit both
@@ -359,39 +362,45 @@
     unsigned char pg_size;
 #endif
 
-	DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
+    DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
 #ifdef ENABLE_PAGING
-	switch(ti->shared_ram_paging) {
-		case 0xf: break;
-		case 0xe: ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-			 pg_size=32;   /* 16KB page size */
-			 break;
-		case 0xd: ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-			 pg_size=64;   /* 32KB page size */
-			 break;
-		case 0xc: ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-			 ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-			 DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
-       /* nb/dwm: I did this because RRR (3,2) bits are documented as
-                R/O and I can't find how to select which page size */
-       /* Also, the above conditional statement sequence is invalid */
-       /*       as page_mask will always be set by the second stmt  */
-			 badti=ti;
-			 break;
-		default:  DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
-			 badti=ti;    /* bail out if bad code */
-			 break;
-	}
-	if(ti->page_mask) {
-		if(pg_size > ti->mapped_ram_size) {
-			DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
-			         pg_size, ti->mapped_ram_size);
-			ti->page_mask = 0;    /* reset paging */
-		} else {
-			ti->mapped_ram_size=ti->avail_shared_ram; /****** ?????????? *******/
-			DPRINTK("Shared RAM paging enabled. Page size : %uK\n",((ti->page_mask^ 0xff)+1)>>2);
-		}
-	}
+    switch(ti->shared_ram_paging) {
+      case 0xf:
+        break;
+      case 0xe:
+	ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+	pg_size=32;   /* 16KB page size */
+	break;
+      case 0xd:
+	ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+	pg_size=64;   /* 32KB page size */
+	break;
+      case 0xc:
+	ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+	ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+	DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
+	/* nb/dwm: I did this because RRR (3,2) bits are documented as
+	 * R/O and I can't find how to select which page size
+	 * Also, the above conditional statement sequence is invalid
+	 *       as page_mask will always be set by the second stmt
+	 */
+	badti=ti;
+	break;
+      default:
+	DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
+	badti=ti;    /* bail out if bad code */
+	break;
+    }
+    if(ti->page_mask) {
+      if(pg_size > ti->mapped_ram_size) {
+	DPRINTK("Page size (%d) > mapped ram window (%d), can't page.\n",
+		pg_size, ti->mapped_ram_size);
+	ti->page_mask = 0;    /* reset paging */
+      } else {
+	ti->mapped_ram_size=ti->avail_shared_ram; /****** ?????????? *******/
+	DPRINTK("Shared RAM paging enabled. Page size : %uK\n",((ti->page_mask^ 0xff)+1)>>2);
+      }
+    }
 #else
 #endif
   }
@@ -431,20 +440,24 @@
   }
   irq2dev_map[irq]=dev;
 
+  /*?? Now, allocate some of the PIO PORTs for this driver.. */
+  request_region(PIOaddr,TR_IO_EXTENT,"ibmtr");  /* record PIOaddr range
+						    as busy */
+
   DPRINTK("%s",version); /* As we have passed card identification,
                             let the world know we're here! */
   dev->base_addr=PIOaddr; /* set the value for device */
 
-	dev->open=tok_open;
-	dev->stop=tok_close;
-	dev->hard_start_xmit=tok_send_packet;
-	dev->get_stats = NULL;
-	dev->get_stats = tok_get_stats;
-	dev->set_multicast_list = NULL;
-	tr_setup(dev);
-	tok_init_card((unsigned long)dev);
+  dev->open=tok_open;
+  dev->stop=tok_close;
+  dev->hard_start_xmit=tok_send_packet;
+  dev->get_stats = NULL;
+  dev->get_stats = tok_get_stats;
+  dev->set_multicast_list = NULL;
+  tr_setup(dev);
+  tok_init_card((unsigned long)dev);
 
-	return 0;  /* Return 0 to indicate we have found a Token Ring card. */
+  return 0;  /* Return 0 to indicate we have found a Token Ring card. */
 }
 
 /* query the adapter for the size of shared RAM  */
@@ -1198,15 +1211,19 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_ibmtr = {
-	"        " /*"ibmtr"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, tok_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, tok_probe };
 
 int io = 0xa20;
 
 int init_module(void)
 {
 	if (io == 0)
-	  printk("ibmtr: You should not use auto-probing with insmod!\n");
+		printk("ibmtr: You should not use auto-probing with insmod!\n");
 	dev_ibmtr.base_addr = io;
 	dev_ibmtr.irq       = 0;
 	if (register_netdev(&dev_ibmtr) != 0) {
@@ -1224,6 +1241,11 @@
 	else
 	{
 		unregister_netdev(&dev_ibmtr);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_ibmtr.irq);
+		irq2dev_map[dev_ibmtr.irq] = NULL;
+		release_region(dev_ibmtr.base_addr, TR_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/ibmtr.h linux/drivers/net/ibmtr.h
--- v1.3.18/linux/drivers/net/ibmtr.h	Tue Jun  6 11:22:09 1995
+++ linux/drivers/net/ibmtr.h	Tue Aug 15 18:08:33 1995
@@ -36,6 +36,8 @@
 #define MMIOStartLocP   0x0a20  /* Primary adapter's starting MMIO area */
 #define MMIOStartLocA   0x0a24  /* Alternate adapter's starting MMIO area */
 
+#define TR_IO_EXTENT	4	/* size of used IO range */
+
 #define GLOBAL_INT_ENABLE 0x02f0
 
 /* MMIO bits 0-4 select register */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.18/linux/drivers/net/lance.c	Tue Aug  8 12:31:36 1995
+++ linux/drivers/net/lance.c	Tue Aug 15 18:08:33 1995
@@ -36,8 +36,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-struct device *init_etherdev(struct device *dev, int sizeof_private,
-							 unsigned long *mem_startp);
 static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
 unsigned long lance_probe1(int ioaddr, unsigned long mem_start);
 
diff -u --recursive --new-file v1.3.18/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v1.3.18/linux/drivers/net/loopback.c	Tue Jul 25 18:21:21 1995
+++ linux/drivers/net/loopback.c	Tue Aug 15 18:51:43 1995
@@ -32,6 +32,7 @@
 #include <linux/fcntl.h>
 #include <linux/in.h>
 #include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
 
 #include <asm/system.h>
 #include <asm/segment.h>
diff -u --recursive --new-file v1.3.18/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.3.18/linux/drivers/net/ne.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/ne.c	Tue Aug 15 18:08:33 1995
@@ -42,6 +42,7 @@
 #include <asm/io.h>
 
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include "8390.h"
 
 /* Some defines that people can play with if so inclined. */
@@ -57,10 +58,6 @@
 
 /* ---- No user-serviceable parts below ---- */
 
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-				    unsigned long *mem_startp);
-
-
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int netcard_portlist[] =
 { 0x300, 0x280, 0x320, 0x340, 0x360, 0};
@@ -540,8 +537,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_ne2000 = {
-	"        " /*"ne2000"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ne_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, ne_probe };
 
 int io = 0x300;
 int irq = 0;
@@ -565,6 +566,10 @@
 	else
 	{
 		unregister_netdev(&dev_ne2000);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_ne2000.irq);
+		release_region(dev_ne2000.base_addr, NE_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.3.18/linux/drivers/net/net_init.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/net_init.c	Tue Aug 15 18:46:26 1995
@@ -24,6 +24,7 @@
 #include <linux/fs.h>
 #include <linux/malloc.h>
 #include <linux/if_ether.h>
+#include <linux/if_arp.h>
 #include <linux/string.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -114,8 +115,10 @@
 							dev->priv = (void*) *mem_startp;
 							*mem_startp += sizeof_priv;
 						} else
-							dev->priv = kmalloc(sizeof_priv, GFP_KERNEL);
-						memset(dev->priv, 0, sizeof_priv);
+							dev->priv = sizeof_priv
+							  ? kmalloc(sizeof_priv, GFP_KERNEL)
+							  :	NULL;
+						if (dev->priv) memset(dev->priv, 0, sizeof_priv);
 						goto found;
 					}
 			}
diff -u --recursive --new-file v1.3.18/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v1.3.18/linux/drivers/net/pi2.c	Wed Aug  2 13:21:04 1995
+++ linux/drivers/net/pi2.c	Tue Aug 15 18:56:20 1995
@@ -117,6 +117,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/timer.h>
+#include <linux/if_arp.h>
 #include "pi2.h"
 #include "z8530.h"
 #include <net/ax25.h>
diff -u --recursive --new-file v1.3.18/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.3.18/linux/drivers/net/plip.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/plip.c	Mon Aug 14 12:57:49 1995
@@ -166,10 +166,10 @@
 	enum plip_nibble_state nibble;
 	union {
 		struct {
-#if defined(LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN)
 			unsigned char lsb;
 			unsigned char msb;
-#elif defined(BIG_ENDIAN)
+#elif defined(__BIG_ENDIAN)
 			unsigned char msb;
 			unsigned char lsb;
 #else
diff -u --recursive --new-file v1.3.18/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v1.3.18/linux/drivers/net/skeleton.c	Fri Jun 30 16:22:28 1995
+++ linux/drivers/net/skeleton.c	Tue Aug 15 18:08:33 1995
@@ -21,7 +21,7 @@
 
 */
 
-static char *version =
+static const char *version =
 	"skeleton.c:v1.51 9/24/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 /* Always include 'config.h' first in case the user wants to turn on
@@ -43,6 +43,14 @@
 	under the GPL.
 */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define  MOD_INC_USE_COUNT do {} while (0)
+#define  MOD_DEC_USE_COUNT do {} while (0)
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -62,8 +70,11 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
+
+/* The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = "netcard";
 
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
@@ -119,7 +130,7 @@
 /* Support for a alternate probe manager, which will eliminate the
    boilerplate below. */
 struct netdev_entry netcard_drv =
-{"netcard", netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
+{cardname, netcard_probe1, NETCARD_IO_EXTENT, netcard_portlist};
 #else
 int
 netcard_probe(struct device *dev)
@@ -130,7 +141,7 @@
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return netcard_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
-		return ENXIO;
+		return -ENXIO;
 
 	for (i = 0; netcard_portlist[i]; i++) {
 		int ioaddr = netcard_portlist[i];
@@ -140,7 +151,7 @@
 			return 0;
 	}
 
-	return ENODEV;
+	return -ENODEV;
 }
 #endif
 
@@ -153,23 +164,30 @@
 	static unsigned version_printed = 0;
 	int i;
 
-	/* For ethernet adaptors the first three octets of the station address contains
-	   the manufacturer's unique code.  That might be a good probe method.
-	   Ideally you would add additional checks.  */ 
+	/* For ethernet adaptors the first three octets of the station address 
+	   contains the manufacturer's unique code.  That might be a good probe
+	   method. Ideally you would add additional checks.  */ 
 	if (inb(ioaddr + 0) != SA_ADDR0
 		||	 inb(ioaddr + 1) != SA_ADDR1
 		||	 inb(ioaddr + 2) != SA_ADDR2) {
-		return ENODEV;
+		return -ENODEV;
 	}
 
 	/* Allocate a new 'dev' if needed. */
-	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct net_local), 0);
+	if (dev == NULL) {
+		/* Don't allocate the private data here, it is done later
+		 * This makes it easier to free the memory when this driver
+		 * is used as a module.
+		 */
+		dev = init_etherdev(0, 0, 0);
+		if (dev == NULL)
+			return -ENOMEM;
+	}
 
 	if (net_debug  &&  version_printed++ == 0)
-		printk(version);
+		printk(KERN_DEBUG "%s", version);
 
-	printk("%s: %s found at %#3x, ", dev->name, "network card", ioaddr);
+	printk(KERN_INFO "%s: %s found at %#3x, ", dev->name, cardname, ioaddr);
 
 	/* Fill in the 'dev' fields. */
 	dev->base_addr = ioaddr;
@@ -194,26 +212,28 @@
 		dev->irq = autoirq_report(0);
 		if (net_debug >= 2)
 			printk(" autoirq is %d", dev->irq);
-  } else if (dev->irq == 2)
-	  /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
-	 or don't know which one to set. */
-	  dev->irq = 9;
-
-	{	 int irqval = request_irq(dev->irq, &net_interrupt, 0, "skeleton");
-		 if (irqval) {
-			 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
-					 dev->irq, irqval);
-			 return EAGAIN;
-		 }
-	 }
+	} else if (dev->irq == 2)
+		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+		 * or don't know which one to set.
+		 */
+		dev->irq = 9;
+
+	{
+		int irqval = request_irq(dev->irq, &net_interrupt, 0, cardname);
+		if (irqval) {
+			printk("%s: unable to get IRQ %d (irqval=%d).\n",
+				   dev->name, dev->irq, irqval);
+			return -EAGAIN;
+		}
+	}
 #endif	/* jumpered interrupt */
 #ifdef jumpered_dma
 	/* If we use a jumpered DMA channel, that should be probed for and
 	   allocated here as well.  See lance.c for an example. */
 	if (dev->dma == 0) {
-		if (request_dma(dev->dma, "netcard")) {
+		if (request_dma(dev->dma, cardname)) {
 			printk("DMA %d allocation failed.\n", dev->dma);
-			return EAGAIN;
+			return -EAGAIN;
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {
@@ -231,29 +251,33 @@
 		new_dma_status ^= dma_status;
 		new_dma_status &= ~0x10;
 		for (i = 7; i > 0; i--)
-			if (test_bit(new_dma, &new_dma_status)) {
+			if (test_bit(i, &new_dma_status)) {
 				dev->dma = i;
 				break;
 			}
 		if (i <= 0) {
 			printk("DMA probe failed.\n");
-			return EAGAIN;
+			return -EAGAIN;
 		} 
-		if (request_dma(dev->dma, "netcard")) {
+		if (request_dma(dev->dma, cardname)) {
 			printk("probed DMA %d allocation failed.\n", dev->dma);
-			return EAGAIN;
+			return -EAGAIN;
 		}
 	}
 #endif	/* jumpered DMA */
 
-	/* Grab the region so we can find another board if autoIRQ fails. */
-	request_region(ioaddr, NETCARD_IO_EXTENT,"skeleton");
-
 	/* Initialize the device structure. */
-	if (dev->priv == NULL)
+	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
+
 	memset(dev->priv, 0, sizeof(struct net_local));
 
+	/* Grab the region so that no one else tries to probe our ioports. */
+	request_region(ioaddr, NETCARD_IO_EXTENT, cardname);
+
 	dev->open		= net_open;
 	dev->stop		= net_close;
 	dev->hard_start_xmit = net_send_packet;
@@ -282,12 +306,12 @@
 
 	/* This is used if the interrupt line can turned off (shared).
 	   See 3c503.c for an example of selecting the IRQ at config-time. */
-	if (request_irq(dev->irq, &net_interrupt, 0, "skeleton")) {
+	if (request_irq(dev->irq, &net_interrupt, 0, cardname)) {
 		return -EAGAIN;
 	}
 
 	/* Always snarf the DMA channel after the IRQ, and clean up on failure. */
-	if (request_dma(dev->dma,"skeleton ethernet")) {
+	if (request_dma(dev->dma, cardname)) {
 		free_irq(dev->irq);
 		return -EAGAIN;
 	}
@@ -301,6 +325,9 @@
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	dev->start = 1;
+
+	MOD_INC_USE_COUNT;
+
 	return 0;
 }
 
@@ -316,7 +343,7 @@
 		int tickssofar = jiffies - dev->trans_start;
 		if (tickssofar < 5)
 			return 1;
-		printk("%s: transmit timed out, %s?\n", dev->name,
+		printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
 			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
 		/* Try to restart the adaptor. */
 		chipset_init(dev, 1);
@@ -335,7 +362,7 @@
 	/* 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);
+		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
 	else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
@@ -362,7 +389,7 @@
 	int ioaddr, status, boguscount = 0;
 
 	if (dev == NULL) {
-		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
 		return;
 	}
 	dev->interrupt = 1;
@@ -418,7 +445,8 @@
 
 			skb = dev_alloc_skb(pkt_len);
 			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+					   dev->name);
 				lp->stats.rx_dropped++;
 				break;
 			}
@@ -467,6 +495,8 @@
 
 	/* Update the statistics here. */
 
+	MOD_DEC_USE_COUNT;
+
 	return 0;
 
 }
@@ -503,11 +533,70 @@
 		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
 }
 
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
+static struct device this_device = {
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,  /* I/O address, IRQ */
+	0, 0, 0, NULL, netcard_probe };
+
+int io = 0x300;
+int irq = 0;
+int dma = 0;
+int mem = 0;
+
+int init_module(void)
+{
+	int result;
+
+	if (io == 0)
+		printk(KERN_WARNING "%s: You shouldn't use auto-probing with insmod!\n",
+			   cardname);
+
+	/* copy the parameters from insmod into the device structure */
+	this_device.base_addr = io;
+	this_device.irq       = irq;
+	this_device.dma       = dma;
+	this_device.mem_start = mem;
+
+	if ((result = register_netdev(&this_device)) != 0)
+		return result;
+
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+
+	unregister_netdev(&this_device);
+
+	/* If we don't do this, we can't re-insmod it later. */
+	/* Release irq/dma here, when you have jumpered versions and snarfed
+	 * them in net_probe1().
+	 */
+	/*
+	   free_irq(this_device.irq);
+	   free_dma(this_device.dma);
+	*/
+	release_region(this_device.base_addr, NETCARD_IO_EXTENT);
+
+	if (this_device.priv)
+		kfree_s(this_device.priv, sizeof(struct net_local));
+}
+
+#endif /* MODULE */
+
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+ *  compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -Wwrite-strings -Wredundant-decls -O2 -m486 -c skeleton.c"
  *  version-control: t
  *  kept-new-versions: 5
  *  tab-width: 4
+ *  c-indent-level: 4
  * End:
  */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v1.3.18/linux/drivers/net/smc-ultra.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/smc-ultra.c	Tue Aug 15 18:08:33 1995
@@ -54,9 +54,8 @@
 #include <asm/system.h>
 
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include "8390.h"
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
 
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int ultra_portlist[] =
@@ -325,8 +324,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_ultra = {
-	"        " /*"smc-ultra"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ultra_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, ultra_probe };
 
 int io = 0x200;
 int irq = 0;
@@ -334,7 +337,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("smc-ultra: You should not use auto-probing with insmod!\n");
+		printk("smc-ultra: You should not use auto-probing with insmod!\n");
 	dev_ultra.base_addr = io;
 	dev_ultra.irq       = irq;
 	if (register_netdev(&dev_ultra) != 0) {
@@ -351,7 +354,12 @@
 		printk("smc-ultra: device busy, remove delayed\n");
 	else
 	{
+		int ioaddr = dev_ultra.base_addr - ULTRA_NIC_OFFSET;
+
 		unregister_netdev(&dev_ultra);
+
+		/* If we don't do this, we can't re-insmod it later. */
+    	release_region(ioaddr, ULTRA_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v1.3.18/linux/drivers/net/tulip.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/tulip.c	Tue Aug 15 18:08:33 1995
@@ -745,8 +745,13 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_tulip = {
-	"        " /*"tulip"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, tulip_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, tulip_probe
+};
 
 int io = 0;
 int irq = 0;
diff -u --recursive --new-file v1.3.18/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v1.3.18/linux/drivers/net/wavelan.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/wavelan.c	Tue Aug 15 18:52:14 1995
@@ -16,6 +16,7 @@
 #include	<linux/types.h>
 #include	<linux/fcntl.h>
 #include	<linux/interrupt.h>
+#include	<linux/stat.h>
 #include	<linux/ptrace.h>
 #include	<linux/ioport.h>
 #include	<linux/in.h>
@@ -838,9 +839,12 @@
 		{
 			if (wavelan_debug > 0)
 				printk("%s: <-wavelan_probe(): 0\n", dev->name);
-			proc_net_register(&(struct proc_dir_entry)
-					  { PROC_NET_WAVELAN, 7, "wavelan",
-					    wavelan_get_info });
+			proc_net_register(&(struct proc_dir_entry) {
+				PROC_NET_WAVELAN, 7, "wavelan",
+				S_IFREG | S_IRUGO, 1, 0, 0,
+				0, &proc_net_inode_operations,
+				wavelan_get_info
+			});
 
 			return 0;
 		}
@@ -2170,10 +2174,13 @@
 
 #if	defined(MODULE)
 char			kernel_version[]	= UTS_RELEASE;
+static char		devicename[9]		= { 0, };
 static struct device	dev_wavelan		=
 {
-	"       " /* "wavelan" */,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, wavelan_probe
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, wavelan_probe
 };
 
 int io = 0x390; /* Default from above.. */
diff -u --recursive --new-file v1.3.18/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v1.3.18/linux/drivers/net/wd.c	Sun Aug 13 14:45:32 1995
+++ linux/drivers/net/wd.c	Tue Aug 15 18:08:34 1995
@@ -33,9 +33,8 @@
 #include <asm/system.h>
 
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include "8390.h"
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
 
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int wd_portlist[] =
@@ -397,8 +396,12 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char devicename[9] = { 0, };
 static struct device dev_wd80x3 = {
-	"        " /*"wd80x3"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, wd_probe };
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, wd_probe };
 
 int io = 0x300;
 int irq = 0;
@@ -407,7 +410,7 @@
 int init_module(void)
 {
 	if (io == 0)
-	  printk("wd: You should not use auto-probing with insmod!\n");
+		printk("wd: You should not use auto-probing with insmod!\n");
 	dev_wd80x3.base_addr = io;
 	dev_wd80x3.irq       = irq;
 	dev_wd80x3.mem_start = mem;
@@ -425,10 +428,11 @@
 	{
 		int ioaddr = dev_wd80x3.base_addr - WD_NIC_OFFSET;
 
-    	free_irq(dev_wd80x3.irq);
-    	release_region(ioaddr, WD_IO_EXTENT);
-
 		unregister_netdev(&dev_wd80x3);
+
+		/* If we don't do this, we can't re-insmod it later. */
+		free_irq(dev_wd80x3.irq);
+		release_region(ioaddr, WD_IO_EXTENT);
 	}
 }
 #endif /* MODULE */
diff -u --recursive --new-file v1.3.18/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v1.3.18/linux/drivers/pci/Makefile	Tue Jul 11 10:02:50 1995
+++ linux/drivers/pci/Makefile	Tue Aug 15 15:07:02 1995
@@ -9,24 +9,7 @@
 # parent makefile.
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-OBJS := pci.o
-SRCS := pci.c
-
-all: pci.a
-
-pci.a: $(OBJS)
-	rm -f pci.a
-	$(AR) rcs pci.a $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M $(SRCS) > .depend
-
-modules:
+L_OBJS   := pci.o
+L_TARGET := pci.a
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.18/linux/drivers/pci/pci.c	Wed Aug  9 14:55:41 1995
+++ linux/drivers/pci/pci.c	Sun Aug 13 20:19:10 1995
@@ -714,6 +714,7 @@
 
 		if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI) {
 			unsigned int buses;
+			unsigned short cr;
 
 			/*
 			 * Insert it into the tree of buses.
@@ -735,6 +736,8 @@
 			 * Clear all status bits and turn off memory,
 			 * I/O and master enables.
 			 */
+			pcibios_read_config_word(bus->number, devfn,
+						  PCI_COMMAND, &cr);
 			pcibios_write_config_word(bus->number, devfn,
 						  PCI_COMMAND, 0x0000);
 			pcibios_write_config_word(bus->number, devfn,
@@ -763,6 +766,8 @@
 			  | ((unsigned int)(child->subordinate) << 16);
 			pcibios_write_config_dword(bus->number, devfn, 0x18,
 						   buses);
+			pcibios_write_config_word(bus->number, devfn,
+						  PCI_COMMAND, cr);
 		}
 	}
 	/*
diff -u --recursive --new-file v1.3.18/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.18/linux/drivers/scsi/Makefile	Tue Jul 25 18:21:22 1995
+++ linux/drivers/scsi/Makefile	Tue Aug 15 15:07:02 1995
@@ -6,16 +6,17 @@
 # unless it's something special (ie not a .c file).
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 ifdef CONFIG_KERNEL_ELF
 # This is used for ELF - it needs to migrate or be moved.
 LD_RFLAG = -m elf_i386
 endif
 
+L_TARGET := scsi.a
+L_OBJS   := 
+M_OBJS   := 
+MOD_LIST_NAME := SCSI_MODULES
+SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
+
 AHA152X	= -DDEBUG_AHA152X -DAUTOCONF -DSKIP_BIOSTEST -DIRQ=11
 
 ifeq (${CFLAGS},)
@@ -25,8 +26,6 @@
 
 include ../../.config
 
-.EXPORT_ALL_VARIABLES:
-
 SYMTAB_OBJS = scsi_syms.o
 
 TOPDIR = ../..
@@ -34,195 +33,159 @@
 
 endif
 
-SCSI_OBJS =
-SCSI_SRCS =
-SCSI_DEP =
-SCSI_MODULE_OBJS =
-
-SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c scsi_proc.c
-
 ifdef CONFIG_SCSI
-SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+L_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 else
 ifdef CONFIG_MODVERSIONS
 # Create this before we build anything else.
 SCSI_MODULE_VER := scsi_syms.ver
 endif
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_mod.o
+M_OBJS += scsi_mod.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) st.c
 ifdef CONFIG_CHR_DEV_ST
-SCSI_OBJS := $(SCSI_OBJS) st.o
+L_OBJS += st.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) st.o
+M_OBJS += st.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
 ifdef CONFIG_BLK_DEV_SD
-SCSI_OBJS := $(SCSI_OBJS) sd.o sd_ioctl.o
+L_OBJS += sd.o sd_ioctl.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sd_mod.o
+M_OBJS += sd_mod.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
 ifdef CONFIG_BLK_DEV_SR
-SCSI_OBJS := $(SCSI_OBJS) sr.o sr_ioctl.o
+L_OBJS += sr.o sr_ioctl.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sr_mod.o
+M_OBJS += sr_mod.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) sg.c
 ifdef CONFIG_CHR_DEV_SG
-SCSI_OBJS := $(SCSI_OBJS) sg.o
+L_OBJS += sg.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sg.o
+M_OBJS += sg.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) qlogic.c
 ifdef CONFIG_SCSI_QLOGIC
-SCSI_OBJS := $(SCSI_OBJS) qlogic.o
+L_OBJS += qlogic.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) qlogic.o
+M_OBJS += qlogic.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) aha152x.c
 ifdef CONFIG_SCSI_AHA152X
-SCSI_OBJS := $(SCSI_OBJS) aha152x.o
+L_OBJS += aha152x.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha152x.o
+M_OBJS += aha152x.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) aha1542.c
 ifdef CONFIG_SCSI_AHA1542
-SCSI_OBJS := $(SCSI_OBJS) aha1542.o
+L_OBJS += aha1542.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o
+M_OBJS += aha1542.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) aha1740.c
 ifdef CONFIG_SCSI_AHA1740
-SCSI_OBJS := $(SCSI_OBJS) aha1740.o
+L_OBJS += aha1740.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1740.o
+M_OBJS += aha1740.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
-SCSI_DEP := $(SCSI_DEP) aic7xxx_seq.h
 ifdef CONFIG_SCSI_AIC7XXX
-SCSI_OBJS := $(SCSI_OBJS) aic7xxx.o
+L_OBJS += aic7xxx.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aic7xxx.o
+M_OBJS += aic7xxx.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) buslogic.c
 ifdef CONFIG_SCSI_BUSLOGIC
-SCSI_OBJS := $(SCSI_OBJS) buslogic.o
+L_OBJS += buslogic.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) buslogic.o
+M_OBJS += buslogic.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) eata_dma.c
 ifdef CONFIG_SCSI_EATA_DMA
-SCSI_OBJS := $(SCSI_OBJS) eata_dma.o
+L_OBJS += eata_dma.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_dma.o
+M_OBJS += eata_dma.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) eata_pio.c
 ifdef CONFIG_SCSI_EATA_PIO
-SCSI_OBJS := $(SCSI_OBJS) eata_pio.o
+L_OBJS += eata_pio.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_pio.o
+M_OBJS += eata_pio.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
 ifdef CONFIG_SCSI_U14_34F
-SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
+L_OBJS += u14-34f.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) u14-34f.o
+M_OBJS += u14-34f.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
 ifdef CONFIG_SCSI_DEBUG
-SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
+L_OBJS += scsi_debug.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o
+M_OBJS += scsi_debug.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) fdomain.c
 ifdef CONFIG_SCSI_FUTURE_DOMAIN
-SCSI_OBJS := $(SCSI_OBJS) fdomain.o
+L_OBJS += fdomain.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) fdomain.o
+M_OBJS += fdomain.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) in2000.c
 ifdef CONFIG_SCSI_IN2000
-SCSI_OBJS := $(SCSI_OBJS) in2000.o
+L_OBJS += in2000.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o
+M_OBJS += in2000.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
 ifdef CONFIG_SCSI_GENERIC_NCR5380
-SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o
+L_OBJS += g_NCR5380.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
 ifdef CONFIG_SCSI_NCR53C7xx
-SCSI_OBJS := $(SCSI_OBJS) 53c7,8xx.o 
+L_OBJS += 53c7,8xx.o 
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) 53c7,8xx.o
+M_OBJS += 53c7,8xx.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) pas16.c
 ifdef CONFIG_SCSI_PAS16
-SCSI_OBJS := $(SCSI_OBJS) pas16.o
+L_OBJS += pas16.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) seagate.c
 ifdef CONFIG_SCSI_SEAGATE
-SCSI_OBJS := $(SCSI_OBJS) seagate.o
+L_OBJS += seagate.o
 else
 ifdef CONFIG_SCSI_FD_8xx
-SCSI_OBJS := $(SCSI_OBJS) seagate.o
+L_OBJS += seagate.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) seagate.o
+M_OBJS += seagate.o
 endif
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) wd7000.c
 ifdef CONFIG_SCSI_7000FASST
-SCSI_OBJS := $(SCSI_OBJS) wd7000.o
+L_OBJS += wd7000.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) wd7000.o
+M_OBJS += wd7000.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) t128.c
 ifdef CONFIG_SCSI_T128
-SCSI_OBJS := $(SCSI_OBJS) t128.o
+L_OBJS += t128.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
 ifdef CONFIG_SCSI_ULTRASTOR
-SCSI_OBJS := $(SCSI_OBJS) ultrastor.o
+L_OBJS += ultrastor.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) ultrastor.o
+M_OBJS += ultrastor.o
 endif
 
-SCSI_SRCS := $(SCSI_SRCS) eata.c
 ifdef CONFIG_SCSI_EATA
-SCSI_OBJS := $(SCSI_OBJS) eata.o
+L_OBJS += eata.o
 else
-SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata.o
+M_OBJS += eata.o
 endif
 
-
-scsi.a: $(SCSI_OBJS)
-	rm -f scsi.a
-	$(AR) rcs scsi.a $(SCSI_OBJS)
-	sync
+include $(TOPDIR)/Rules.make
 
 aha152x.o: aha152x.c
 	$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
@@ -230,6 +193,7 @@
 aic7xxx_asm:	aic7xxx_asm.c
 	$(CC) $(CFLAGS) -o $@ aic7xxx_asm.c
 
+aic7xxx.c: aic7xxx_seq.h
 aic7xxx_seq.h:	aic7xxx_asm aic7xxx.seq
 	./aic7xxx_asm -o $@ aic7xxx.seq
 
@@ -259,15 +223,4 @@
 
 $(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c)
 
-modules: $(SCSI_MODULE_VER) $(SCSI_MODULE_OBJS)
-	echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
-	(cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
-
-dep:	$(SCSI_DEP)
-	$(CPP) -M $(AHA152X) constants.c $(SCSI_OBJS:.o=.c) > .depend
-	$(CPP) -M -DMODULE $(patsubst scsi_mod.c,scsi.c hosts.c scsi_ioctl.c \
-					constants.c scsicam.c scsi_proc.c, \
-			   $(patsubst sd_mod.c,sd.c sd_ioctl.c, \
-			   $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c)))) >> .depend
-
-include $(TOPDIR)/Rules.make
+modules: $(SCSI_MODULE_VER)
diff -u --recursive --new-file v1.3.18/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.18/linux/drivers/scsi/sd.c	Tue Jul 11 10:02:51 1995
+++ linux/drivers/scsi/sd.c	Sun Aug 13 20:19:12 1995
@@ -149,7 +149,7 @@
     }
 }
 
-static void sd_geninit(void);
+static void sd_geninit(struct gendisk *);
 
 static struct file_operations sd_fops = {
     NULL,                        /* lseek - default */
@@ -181,7 +181,7 @@
     NULL                         /* next */
 };
 
-static void sd_geninit (void)
+static void sd_geninit (struct gendisk *ignored)
 {
     int i;
     
diff -u --recursive --new-file v1.3.18/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.3.18/linux/drivers/sound/Makefile	Tue Jul 11 10:02:51 1995
+++ linux/drivers/sound/Makefile	Tue Aug 15 15:07:02 1995
@@ -9,11 +9,6 @@
 TARGET_OS	= linux
 USRINCDIR	= /usr/include
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
 OBJS   = soundcard.o audio.o dmabuf.o sb_dsp.o dev_table.o \
 	 opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \
 	 pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
diff -u --recursive --new-file v1.3.18/linux/fs/Makefile linux/fs/Makefile
--- v1.3.18/linux/fs/Makefile	Tue Jul 11 10:02:55 1995
+++ linux/fs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,109 +7,85 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv smbfs
+L_TARGET := filesystems.a
+L_OBJS    = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+O_TARGET := fs.o
+O_OBJS    = open.o read_write.o inode.o devices.o file_table.o buffer.o \
+		super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
+		ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
+		dcache.o $(BINFMTS) 
+
+MOD_LIST_NAME := FS_MODULES
+ALL_SUB_DIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv smbfs
 
 ifdef CONFIG_MINIX_FS
-FS_SUBDIRS := $(FS_SUBDIRS) minix
+SUB_DIRS += minix
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) minix
+MOD_SUB_DIRS += minix
 endif
 
 ifdef CONFIG_EXT_FS
-FS_SUBDIRS := $(FS_SUBDIRS) ext
+SUB_DIRS += ext
 endif
 
 ifdef CONFIG_EXT2_FS
-FS_SUBDIRS := $(FS_SUBDIRS) ext2
+SUB_DIRS += ext2
 endif
 
 ifdef CONFIG_MSDOS_FS
-FS_SUBDIRS := $(FS_SUBDIRS) msdos
+SUB_DIRS += msdos
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) msdos
+MOD_SUB_DIRS += msdos
 endif
 
 ifdef CONFIG_PROC_FS
-FS_SUBDIRS := $(FS_SUBDIRS) proc
+SUB_DIRS += proc
 endif
 
 ifdef CONFIG_ISO9660_FS
-FS_SUBDIRS := $(FS_SUBDIRS) isofs
+SUB_DIRS += isofs
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) isofs
+MOD_SUB_DIRS += isofs
 endif
 
 ifdef CONFIG_NFS_FS
-FS_SUBDIRS := $(FS_SUBDIRS) nfs
+SUB_DIRS += nfs
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) nfs
+MOD_SUB_DIRS += nfs
 endif
 
 ifdef CONFIG_XIA_FS
-FS_SUBDIRS := $(FS_SUBDIRS) xiafs
+SUB_DIRS += xiafs
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) xiafs
+MOD_SUB_DIRS += xiafs
 endif
 
 ifdef CONFIG_UMSDOS_FS
-FS_SUBDIRS := $(FS_SUBDIRS) umsdos
+SUB_DIRS += umsdos
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) umsdos
+MOD_SUB_DIRS += umsdos
 endif
 
 ifdef CONFIG_SYSV_FS
-FS_SUBDIRS := $(FS_SUBDIRS) sysv
+SUB_DIRS += sysv
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) sysv
+MOD_SUB_DIRS += sysv
 endif
 
 ifdef CONFIG_SMB_FS
-FS_SUBDIRS := $(FS_SUBDIRS) smbfs
+SUB_DIRS += smbfs
 else
-MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) smbfs
+MOD_SUB_DIRS += smbfs
 endif
 
 ifdef CONFIG_HPFS_FS
-FS_SUBDIRS := $(FS_SUBDIRS) hpfs
+SUB_DIRS += hpfs
 endif
 
 ifdef CONFIG_BINFMT_ELF
-BINFMTS := $(BINFMTS) binfmt_elf.o
+BINFMTS += binfmt_elf.o
 else
-MODULE_OBJS := $(MODULE_OBJS) binfmt_elf.o
+MOD_SUB_DIRS += binfmt_elf.o
 endif
-
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \
-	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o readdir.o \
-	select.o fifo.o locks.o filesystems.o dcache.o $(BINFMTS)
-
-all: fs.o filesystems.a
-
-fs.o: $(OBJS)
-	$(LD) -r -o fs.o $(OBJS)
-
-filesystems.a: dummy
-	rm -f filesystems.a
-	set -e; for i in $(FS_SUBDIRS); do \
-	  test ! -d $$i || \
-	    { $(MAKE) -C $$i; $(AR) rcs filesystems.a $$i/$$i.o; }; done
-
-modules: $(MODULE_OBJS)
-	for i in $(MODULE_FS_SUBDIRS); do $(MAKE) -C $$i modules; done
-	cd ../modules;for i in $(MODULE_OBJS); do ln -sf ../fs/$$i .; done
-	cd ../modules;for i in $(MODULE_FS_SUBDIRS); \
-	do echo $$i.o; ln -sf ../fs/$$i/$$i.o .; done > ../modules/FS_MODULES
-
-depend dep:
-	$(CPP) -M *.c > .depend
-	set -e; for i in $(FS_SUBDIRS); do \
-	  test ! -d $$i || $(MAKE) -C $$i dep; done
-	set -e; for i in $(MODULE_FS_SUBDIRS); do \
-	  test ! -d $$i || $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE" dep; done
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/ext/Makefile linux/fs/ext/Makefile
--- v1.3.18/linux/fs/ext/Makefile	Tue Jul 11 10:02:55 1995
+++ linux/fs/ext/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,18 +7,9 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	freelists.o truncate.o namei.o inode.o \
-	file.o dir.o symlink.o fsync.o
-
-ext.o: $(OBJS)
-	$(LD) -r -o ext.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := ext.o
+O_OBJS   := freelists.o truncate.o namei.o inode.o file.o dir.o \
+		symlink.o fsync.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/ext2/Makefile linux/fs/ext2/Makefile
--- v1.3.18/linux/fs/ext2/Makefile	Tue Jul 11 10:02:57 1995
+++ linux/fs/ext2/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,18 +7,9 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o \
-	inode.o ioctl.o namei.o super.o symlink.o truncate.o
-
-ext2.o: $(OBJS)
-	$(LD) -r -o ext2.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := ext2.o
+O_OBJS   := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+		ioctl.o namei.o super.o symlink.o truncate.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v1.3.18/linux/fs/ext2/dir.c	Wed Aug  2 13:21:15 1995
+++ linux/fs/ext2/dir.c	Tue Aug 15 15:50:08 1995
@@ -104,7 +104,7 @@
 	struct buffer_head * bh, * tmp, * bha[16];
 	struct ext2_dir_entry * de;
 	struct super_block * sb;
-	int err, version;
+	int err;
 
 	if (!inode || !S_ISDIR(inode->i_mode))
 		return -EBADF;
@@ -189,6 +189,8 @@
 				 * version stamp to detect whether or
 				 * not the directory has been modified
 				 * during the copy operation. */
+				unsigned long version;
+				dcache_add(inode, de->name, de->name_len, de->inode);
 				version = inode->i_version;
 				error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
 				if (error)
diff -u --recursive --new-file v1.3.18/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile
--- v1.3.18/linux/fs/hpfs/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/hpfs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,17 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	hpfs_fs.o hpfs_caps.o
-
-hpfs.o: $(OBJS)
-	$(LD) -r -o hpfs.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := hpfs.o
+O_OBJS   := hpfs_fs.o hpfs_caps.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/isofs/Makefile linux/fs/isofs/Makefile
--- v1.3.18/linux/fs/isofs/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/isofs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,20 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	namei.o inode.o file.o dir.o util.o rock.o symlink.o
-
-isofs.o: $(OBJS)
-	$(LD) -r -o isofs.o $(OBJS)
-
-modules: isofs.o
-	ln -sf ../fs/isofs/isofs.o $(TOPDIR)/modules
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := isofs.o
+O_OBJS   := namei.o inode.o file.o dir.o util.o rock.o symlink.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/minix/Makefile linux/fs/minix/Makefile
--- v1.3.18/linux/fs/minix/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/minix/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,20 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	bitmap.o truncate.o namei.o inode.o \
-	file.o dir.o symlink.o fsync.o
-
-minix.o: $(OBJS)
-	$(LD) -r -o minix.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules: minix.o
+O_TARGET := minix.o
+O_OBJS   := bitmap.o truncate.o namei.o inode.o file.o dir.o symlink.o fsync.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/msdos/Makefile linux/fs/msdos/Makefile
--- v1.3.18/linux/fs/msdos/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/msdos/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,20 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o
-
-msdos.o: $(OBJS)
-	$(LD) -r -o msdos.o $(OBJS)
-
-modules: msdos.o
-	ln -sf ../fs/msdos/msdos.o $(TOPDIR)/modules
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := msdos.o
+O_OBJS   := buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/nfs/Makefile linux/fs/nfs/Makefile
--- v1.3.18/linux/fs/nfs/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/nfs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,20 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	proc.o sock.o inode.o file.o dir.o \
-	symlink.o mmap.o
-
-nfs.o: $(OBJS)
-	$(LD) -r -o nfs.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules: nfs.o
+O_TARGET := nfs.o
+O_OBJS   := proc.o sock.o inode.o file.o dir.o symlink.o mmap.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v1.3.18/linux/fs/proc/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/proc/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,17 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
-
-proc.o: $(OBJS)
-	$(LD) -r -o proc.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := proc.o
+O_OBJS   := inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/proc/base.c linux/fs/proc/base.c
--- v1.3.18/linux/fs/proc/base.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/proc/base.c	Tue Aug 15 14:40:41 1995
@@ -13,14 +13,11 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 
-static int proc_readbase(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookupbase(struct inode *,const char *,int,struct inode **);
-
 static struct file_operations proc_base_operations = {
 	NULL,			/* lseek - default */
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
-	proc_readbase,		/* readdir */
+	proc_readdir,		/* readdir */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
@@ -32,10 +29,10 @@
 /*
  * proc directories can do almost nothing..
  */
-struct inode_operations proc_base_inode_operations = {
+static struct inode_operations proc_base_inode_operations = {
 	&proc_base_operations,	/* default base directory file-ops */
 	NULL,			/* create */
-	proc_lookupbase,	/* lookup */
+	proc_lookup,		/* lookup */
 	NULL,			/* link */
 	NULL,			/* unlink */
 	NULL,			/* symlink */
@@ -50,105 +47,97 @@
 	NULL			/* permission */
 };
 
-static struct proc_dir_entry base_dir[] = {
-	{ PROC_PID_INO,		1, "." },
-	{ PROC_ROOT_INO,	2, ".." },
-	{ PROC_PID_MEM,		3, "mem" },
-	{ PROC_PID_CWD,		3, "cwd" },
-	{ PROC_PID_ROOT,	4, "root" },
-	{ PROC_PID_EXE,		3, "exe" },
-	{ PROC_PID_FD,		2, "fd" },
-	{ PROC_PID_ENVIRON,	7, "environ" },
-	{ PROC_PID_CMDLINE,	7, "cmdline" },
-	{ PROC_PID_STAT,	4, "stat" },
-	{ PROC_PID_STATM,	5, "statm" },
-	{ PROC_PID_MAPS,	4, "maps" }
-};
-
-#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
-
-int proc_match(int len,const char * name,struct proc_dir_entry * de)
-{
-	if (!de || !de->low_ino)
-		return 0;
-	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
-	if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
-		return 1;
-	if (de->namelen != len)
-		return 0;
-	return !memcmp(name, de->name, len);
-}
-
-static int proc_lookupbase(struct inode * dir,const char * name, int len,
-	struct inode ** result)
+static void proc_pid_fill_inode(struct inode * inode)
 {
-	struct proc_dir_entry * de = NULL;
-	unsigned int pid, ino;
-	int i;
-
-	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		iput(dir);
-		return -ENOENT;
-	}
-	ino = dir->i_ino;
-	pid = ino >> 16;
-	for (i = 0; i < NR_BASE_DIRENTRY; i++) {
-		if (!proc_match(len, name, base_dir+i))
-			continue;
-		de = base_dir+i;
-		break;
-	}
-	if (!de) {
-		iput(dir);
-		return -ENOENT;
+	struct task_struct * p;
+	int pid = inode->i_ino >> 16;
+	int ino = inode->i_ino & 0xffff;
+
+	for_each_task(p) {
+		if (p->pid == pid) {
+			if (p->dumpable || ino == PROC_PID_INO) {
+				inode->i_uid = p->euid;
+				inode->i_gid = p->gid;
+			}
+			return;
+		}
 	}
-	if (de->low_ino == 1)
-		ino = 1;
-	else
-		ino = (pid << 16) + de->low_ino;
-	for (i = 0 ; i < NR_TASKS ; i++)
-		if (task[i] && task[i]->pid == pid)
-			break;
-	if (!pid || i >= NR_TASKS) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!(*result = iget(dir->i_sb,ino))) {
-		iput(dir);
-		return -ENOENT;
-	}
-	iput(dir);
-	(*result)->u.generic_ip = de;
-	return 0;
 }
 
-static int proc_readbase(struct inode * inode, struct file * filp,
-	void * dirent, filldir_t filldir)
-{
-	struct proc_dir_entry * de;
-	unsigned int pid, ino;
-	int i;
+/*
+ * This is really a pseudo-entry, and only links
+ * backwards to the parent with no link from the
+ * root directory to this. This way we can have just
+ * one entry for every /proc/<pid>/ directory.
+ */
+struct proc_dir_entry proc_pid = {
+	PROC_PID_INO, 5, "<pid>",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &proc_base_inode_operations,
+	NULL, proc_pid_fill_inode,
+	NULL, &proc_root, NULL
+};
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-	ino = inode->i_ino;
-	pid = ino >> 16;
-	for (i = 0 ; i < NR_TASKS ; i++)
-		if (task[i] && task[i]->pid == pid)
-			break;
-	if (!pid || i >= NR_TASKS)
-		return 0;
-	while (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
-		de = base_dir + filp->f_pos;
-		ino = de->low_ino;
-		if (ino != 1)
-			ino |= (pid << 16);
-		if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino) < 0)
-			break;
-		filp->f_pos++;
-	}
-	return 0;
-}
+void proc_base_init(void)
+{
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_MEM, 3, "mem",
+		S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
+		0, &proc_mem_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_CWD, 3, "cwd",
+		S_IFLNK | S_IRWXU, 1, 0, 0,
+		0, &proc_link_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_ROOT, 4, "root",
+		S_IFLNK | S_IRWXU, 1, 0, 0,
+		0, &proc_link_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_EXE, 3, "exe",
+		S_IFLNK | S_IRWXU, 1, 0, 0,
+		0, &proc_link_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_FD, 2, "fd",
+		S_IFDIR | S_IRUSR | S_IXUSR, 1, 0, 0,
+		0, &proc_fd_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_ENVIRON, 7, "environ",
+		S_IFREG | S_IRUSR, 1, 0, 0,
+		0, &proc_array_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_CMDLINE, 7, "cmdline",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_array_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_STAT, 4, "stat",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_array_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_STATM, 5, "statm",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_array_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+	proc_register(&proc_pid, &(struct proc_dir_entry) {
+		PROC_PID_MAPS, 4, "maps",
+		S_IFIFO | S_IRUGO, 1, 0, 0,
+		0, &proc_arraylong_inode_operations,
+		NULL, proc_pid_fill_inode,
+	});
+};
diff -u --recursive --new-file v1.3.18/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v1.3.18/linux/fs/proc/fd.c	Thu Jun  8 20:06:10 1995
+++ linux/fs/proc/fd.c	Tue Aug 15 10:52:03 1995
@@ -75,7 +75,7 @@
 			*result = dir;
 			return 0;
 		}
-		if (!(*result = iget(sb,(pid << 16)+PROC_PID_INO))) {
+		if (!(*result = proc_get_inode(sb, (pid << 16)+PROC_PID_INO, &proc_pid))) {
 			iput(dir);
 			return -ENOENT;
 		}
@@ -109,7 +109,7 @@
 
 	ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
-	if (!(*result = iget(sb,ino)))
+	if (!(*result = proc_get_inode(sb, ino, NULL)))
 		return -ENOENT;
 	return 0;
 }
diff -u --recursive --new-file v1.3.18/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v1.3.18/linux/fs/proc/inode.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/proc/inode.c	Tue Aug 15 14:47:50 1995
@@ -18,16 +18,15 @@
 #include <asm/segment.h>
 
 extern unsigned long prof_len;
-extern void proc_net_init(void);
 
-void proc_put_inode(struct inode *inode)
+static void proc_put_inode(struct inode *inode)
 {
 	if (inode->i_nlink)
 		return;
 	inode->i_size = 0;
 }
 
-void proc_put_super(struct super_block *sb)
+static void proc_put_super(struct super_block *sb)
 {
 	lock_super(sb);
 	sb->s_dev = 0;
@@ -75,23 +74,46 @@
 	return 1;
 }
 
+struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
+{
+	struct inode * inode = iget(s, ino);
+	if (inode) {
+		inode->u.generic_ip = (void *) de;
+		if (de) {
+			if (de->mode) {
+				inode->i_mode = de->mode;
+				inode->i_uid = de->uid;
+				inode->i_gid = de->gid;
+			}
+			if (de->size)
+				inode->i_size = de->size;
+			if (de->ops)
+				inode->i_op = de->ops;
+			if (de->nlink)
+				inode->i_nlink = de->nlink;
+			if (de->fill_inode)
+				de->fill_inode(inode);
+		}
+	}
+	return inode;
+}			
 
 struct super_block *proc_read_super(struct super_block *s,void *data, 
 				    int silent)
 {
+	proc_root_init();
 	lock_super(s);
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
 	unlock_super(s);
-	if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) {
+	if (!(s->s_mounted = proc_get_inode(s, PROC_ROOT_INO, &proc_root))) {
 		s->s_dev = 0;
 		printk("get root inode failed\n");
 		return NULL;
 	}
 	parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
-	proc_net_init();
 	return s;
 }
 
@@ -139,31 +161,6 @@
 		for (i = 1 ; i < NR_TASKS ; i++)
 			if (task[i])
 				inode->i_nlink++;
-		inode->i_op = &proc_root_inode_operations;
-		return;
-	}
-
-/* #ifdef CONFIG_IP_ACCT */
-	/* this file may be opened R/W by root to reset the accounting */
-	if (ino == PROC_NET_IPACCT) {
-		inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
-		inode->i_op = &proc_net_inode_operations;
-		return;
-	}
-/* #endif */
-/* #ifdef CONFIG_IP_FIREWALL */
-	/* these files may be opened R/W by root to reset the counters */
-	if ((ino == PROC_NET_IPFWFWD) || (ino == PROC_NET_IPFWBLK)) {
-		inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
-		inode->i_op = &proc_net_inode_operations;
-		return;
-	}
-/* #endif */
-
-	/* other files within /proc/net */
-	if ((ino >= PROC_NET_UNIX) && (ino < PROC_NET_LAST)) {
-		inode->i_mode = S_IFREG | S_IRUGO;
-		inode->i_op = &proc_net_inode_operations;
 		return;
 	}
 
@@ -203,9 +200,7 @@
 				inode->i_op = &proc_kmsg_inode_operations;
 				break;
 			case PROC_NET:
-				inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
 				inode->i_nlink = 2;
-				inode->i_op = &proc_netdir_inode_operations;
 				break;
 			case PROC_SCSI:
                                 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
@@ -239,8 +234,6 @@
 	switch (ino) {
 		case PROC_PID_INO:
 			inode->i_nlink = 4;
-			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-			inode->i_op = &proc_base_inode_operations;
 			return;
 		case PROC_PID_MEM:
 			inode->i_op = &proc_mem_inode_operations;
diff -u --recursive --new-file v1.3.18/linux/fs/proc/net.c linux/fs/proc/net.c
--- v1.3.18/linux/fs/proc/net.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/proc/net.c	Tue Aug 15 14:41:48 1995
@@ -36,111 +36,48 @@
 #include <linux/config.h>
 #include <linux/mm.h>
 
-static struct proc_dir_entry *net_dir = NULL;
-
-int proc_net_register(struct proc_dir_entry *dp)
-{
-	dp->next = net_dir;
-	net_dir = dp;
-	return 0;
-}
-
-int proc_net_unregister(int ino)
-{
-	struct proc_dir_entry **p = &net_dir, *dp;
-
-	while ((dp = *p) != NULL) {
-		if (dp->low_ino == ino) {
-			*p = dp->next;
-			dp->next = NULL;
-			return 0;
-		}
-		p = &dp->next;
-	}
-	return -EINVAL;
-}	
-
-static int dir_get_info(char * a, char ** b, off_t d, int e, int f)
-{
-	return -EISDIR;
-}
-
-void proc_net_init(void)
-{
-	static struct proc_dir_entry
-	  nd_thisdir = { PROC_NET, 1, ".", dir_get_info },
-	  nd_rootdir = { PROC_ROOT_INO, 2, "..", dir_get_info };
-	static int already = 0;
-
-	if (already) return;
-	already = 1;
-
-	proc_net_register(&nd_thisdir);
-	proc_net_register(&nd_rootdir);
-}
-
-
-static int proc_lookupnet(struct inode * dir,const char * name, int len,
-			  struct inode ** result)
-{
-	struct proc_dir_entry *de;
-
-	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		iput(dir);
-		return -ENOENT;
-	}
-	for (de = net_dir ; de ; de = de->next) {
-		struct inode * inode;
-		if (!proc_match(len, name, de))
-			continue;
-		inode = iget(dir->i_sb, de->low_ino);
-		iput(dir);
-		if (!inode)
-			return -ENOENT;
-		inode->u.generic_ip = de;
-		if (de->fill_inode)
-			de->fill_inode(inode);
-		*result = inode;
-		return 0;
-	}
-	iput(dir);
-	return -ENOENT;
-}
-
-static int proc_readnetdir(struct inode * inode, struct file * filp,
-	void * dirent, filldir_t filldir)
-{
-	struct proc_dir_entry * de;
-	unsigned int ino;
-	int i;
-
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-	ino = inode->i_ino;
-	de = net_dir;
-	i = filp->f_pos;
-	for (;;) {
-		if (!de)
-			return 0;
-		if (!i)
-			break;
-		de = de->next;
-		i--;
-	}
-
-	do {
-		if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
-			return 0;
-		filp->f_pos++;
-		de = de->next;
-	} while (de);
+static struct file_operations proc_netdir_operations = {
+	NULL,			/* lseek - default */
+	NULL,			/* read - bad */
+	NULL,			/* write - bad */
+	proc_readdir,		/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
 
-	return 0;
-}
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_netdir_inode_operations = {
+	&proc_netdir_operations,	/* default net directory file-ops */
+	NULL,			/* create */
+	proc_lookup,		/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
 
+struct proc_dir_entry proc_net = {
+	PROC_NET, 3, "net",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &proc_netdir_inode_operations,
+	NULL, NULL,
+	NULL,
+	NULL, NULL	
+};
 
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
@@ -212,40 +149,6 @@
 	&proc_net_operations,	/* default net file-ops */
 	NULL,			/* create */
 	NULL,			/* lookup */
-	NULL,			/* link */
-	NULL,			/* unlink */
-	NULL,			/* symlink */
-	NULL,			/* mkdir */
-	NULL,			/* rmdir */
-	NULL,			/* mknod */
-	NULL,			/* rename */
-	NULL,			/* readlink */
-	NULL,			/* follow_link */
-	NULL,			/* bmap */
-	NULL,			/* truncate */
-	NULL			/* permission */
-};
-
-static struct file_operations proc_netdir_operations = {
-	NULL,			/* lseek - default */
-	NULL,			/* read - bad */
-	NULL,			/* write - bad */
-	proc_readnetdir,	/* readdir */
-	NULL,			/* select - default */
-	NULL,			/* ioctl - default */
-	NULL,			/* mmap */
-	NULL,			/* no special open code */
-	NULL,			/* no special release code */
-	NULL			/* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_netdir_inode_operations = {
-	&proc_netdir_operations,	/* default net directory file-ops */
-	NULL,			/* create */
-	proc_lookupnet,		/* lookup */
 	NULL,			/* link */
 	NULL,			/* unlink */
 	NULL,			/* symlink */
diff -u --recursive --new-file v1.3.18/linux/fs/proc/root.c linux/fs/proc/root.c
--- v1.3.18/linux/fs/proc/root.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/proc/root.c	Tue Aug 15 14:55:47 1995
@@ -14,14 +14,19 @@
 #include <linux/stat.h>
 #include <linux/config.h>
 
-static int proc_readroot(struct inode *, struct file *, void *, filldir_t);
-static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
+/*
+ * Offset of the first process in the /proc root directory..
+ */
+#define FIRST_PROCESS_ENTRY 256
+
+static int proc_root_readdir(struct inode *, struct file *, void *, filldir_t);
+static int proc_root_lookup(struct inode *,const char *,int,struct inode **);
 
 static struct file_operations proc_root_operations = {
 	NULL,			/* lseek - default */
 	NULL,			/* read - bad */
 	NULL,			/* write - bad */
-	proc_readroot,		/* readdir */
+	proc_root_readdir,	/* readdir */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
@@ -33,10 +38,10 @@
 /*
  * proc directories can do almost nothing..
  */
-struct inode_operations proc_root_inode_operations = {
+static struct inode_operations proc_root_inode_operations = {
 	&proc_root_operations,	/* default base directory file-ops */
 	NULL,			/* create */
-	proc_lookuproot,	/* lookup */
+	proc_root_lookup,	/* lookup */
 	NULL,			/* link */
 	NULL,			/* unlink */
 	NULL,			/* symlink */
@@ -51,125 +56,368 @@
 	NULL			/* permission */
 };
 
-static struct proc_dir_entry root_dir[] = {
-	{ PROC_ROOT_INO,	1, "." },
-	{ PROC_ROOT_INO,	2, ".." },
-	{ PROC_LOADAVG,		7, "loadavg" },
-	{ PROC_UPTIME,		6, "uptime" },
-	{ PROC_MEMINFO,		7, "meminfo" },
-	{ PROC_KMSG,		4, "kmsg" },
-	{ PROC_VERSION,		7, "version" },
+/*
+ * This is the root "inode" in the /proc tree..
+ */
+struct proc_dir_entry proc_root = {
+	PROC_ROOT_INO, 5, "/proc",
+	S_IFDIR | S_IRUGO | S_IXUGO, 3, 0, 0,
+	0, &proc_root_inode_operations,
+	NULL, NULL,
+	NULL,
+	&proc_root, NULL
+};
+
+int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
+{
+	dp->next = dir->subdir;
+	dp->parent = dir;
+	dir->subdir = dp;
+	if (S_ISDIR(dp->mode))
+		dir->nlink++;
+	return 0;
+}
+
+int proc_unregister(struct proc_dir_entry * dir, int ino)
+{
+	struct proc_dir_entry **p = &dir->subdir, *dp;
+
+	while ((dp = *p) != NULL) {
+		if (dp->low_ino == ino) {
+			*p = dp->next;
+			dp->next = NULL;
+			if (S_ISDIR(dp->mode))
+				dir->nlink--;
+			return 0;
+		}
+		p = &dp->next;
+	}
+	return -EINVAL;
+}	
+
+/*
+ * /proc/self:
+ */
+static int proc_self_followlink(struct inode * dir, struct inode * inode,
+			int flag, int mode, struct inode ** res_inode)
+{
+	iput(dir);
+	*res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
+	iput(inode);
+	if (!*res_inode)
+		return -ENOENT;
+	return 0;
+}
+
+static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
+{
+	int len;
+	char tmp[30];
+
+	iput(inode);
+	len = 1 + sprintf(tmp, "%d", current->pid);
+	if (buflen < len)
+		len = buflen;
+	memcpy_tofs(buffer, tmp, len);
+	return len;
+}
+
+static struct inode_operations proc_self_inode_operations = {
+	NULL,			/* no file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	proc_self_readlink,	/* readlink */
+	proc_self_followlink,	/* follow_link */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+void proc_root_init(void)
+{
+	static int done = 0;
+
+	if (done)
+		return;
+	done = 1;
+	proc_base_init();
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_LOADAVG, 7, "loadavg",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_UPTIME, 6, "uptime",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_MEMINFO, 7, "meminfo",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_KMSG, 4, "kmsg",
+		S_IFREG | S_IRUSR, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_VERSION, 7, "version",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
 #ifdef CONFIG_PCI
-	{ PROC_PCI,             3, "pci" },
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_PCI, 3, "pci",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
 #endif
-	{ PROC_CPUINFO,		7, "cpuinfo" },
-	{ PROC_SELF,		4, "self" },	/* will change inode # */
-	{ PROC_NET,		3, "net" },
-   	{ PROC_SCSI,	        4, "scsi" },
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_CPUINFO, 7, "cpuinfo",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_SELF, 4, "self",
+		S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
+		64, &proc_self_inode_operations,
+	});
+	proc_register(&proc_root, &proc_net);
+	proc_register(&proc_root, &proc_scsi);
 #ifdef CONFIG_DEBUG_MALLOC
-	{ PROC_MALLOC,		6, "malloc" },
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_MALLOC, 6, "malloc",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
 #endif
-	{ PROC_KCORE,		5, "kcore" },
-   	{ PROC_MODULES,		7, "modules" },
-   	{ PROC_STAT,		4, "stat" },
-   	{ PROC_DEVICES,		7, "devices" },
-	{ PROC_INTERRUPTS,	10,"interrupts" },
-   	{ PROC_FILESYSTEMS,	11,"filesystems" },
-   	{ PROC_KSYMS,		5, "ksyms" },
-   	{ PROC_DMA,		3, "dma" },
-	{ PROC_IOPORTS,		7, "ioports" },
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_KCORE, 5, "kcore",
+		S_IFREG | S_IRUSR, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_MODULES, 7, "modules",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_STAT, 4, "stat",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_DEVICES, 7, "devices",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_INTERRUPTS, 10,"interrupts",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_FILESYSTEMS, 11,"filesystems",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_KSYMS, 5, "ksyms",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_DMA, 3, "dma",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_IOPORTS, 7, "ioports",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
 #ifdef CONFIG_PROFILE
-	{ PROC_PROFILE,		7, "profile" },
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_PROFILE, 7, "profile",
+		S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+	});
 #endif
-};
+}
+
 
-#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
+int proc_match(int len,const char * name,struct proc_dir_entry * de)
+{
+	if (!de || !de->low_ino)
+		return 0;
+	/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+	if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
+		return 1;
+	if (de->namelen != len)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
 
-static int proc_lookuproot(struct inode * dir,const char * name, int len,
+int proc_lookup(struct inode * dir,const char * name, int len,
 	struct inode ** result)
 {
-	struct proc_dir_entry * de = NULL;
-	unsigned int pid, c;
-	int i, ino;
+	struct proc_dir_entry * de;
+	int ino;
 
 	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode)) {
 		iput(dir);
-		return -ENOENT;
-	}
-	for (i = 0; i < NR_ROOT_DIRENTRY; i++) {
-		if (!proc_match(len,name,root_dir+i))
-			continue;
-		de = root_dir + i;
-		break;
+		return -ENOTDIR;
 	}
-	if (de) {
-		ino = de->low_ino;
-		if (ino == PROC_ROOT_INO) {
-			*result = dir;
+
+	de = (struct proc_dir_entry *) dir->u.generic_ip;
+	if (!de)
+		return -EINVAL;
+
+	/* Special case "." and "..": they aren't on the directory list */
+	*result = dir;
+	if (!len)
+		return 0;
+	if (name[0] == '.') {
+		if (len == 1)
+			return 0;
+		if (name[1] == '.' && len == 2) {
+			struct inode * inode;
+			inode = proc_get_inode(dir->i_sb, de->parent->low_ino, de->parent);
+			iput(dir);
+			if (!inode)
+				return -EINVAL;
+			*result = inode;
 			return 0;
 		}
-		if (ino == PROC_SELF) /* self modifying inode ... */
-			ino = (current->pid << 16) + 2;
-	} else {
-		pid = 0;
-		while (len-- > 0) {
-			c = *name - '0';
-			name++;
-			if (c > 9) {
-				pid = 0;
-				break;
-			}
-			pid *= 10;
-			pid += c;
-			if (pid & 0xffff0000) {
-				pid = 0;
-				break;
-			}
+	}
+
+	*result = NULL;
+	for (de = de->subdir; de ; de = de->next) {
+		if (proc_match(len, name, de))
+			break;
+	}
+	if (!de)
+		return -ENOENT;
+
+	ino = de->low_ino | (dir->i_ino & ~(0xffff));
+
+	if (!(*result = proc_get_inode(dir->i_sb, ino, de))) {
+		iput(dir);
+		return -EINVAL;
+	}
+	iput(dir);
+	return 0;
+}
+
+static int proc_root_lookup(struct inode * dir,const char * name, int len,
+	struct inode ** result)
+{
+	unsigned int pid, c;
+	int i, ino;
+
+	int retval = proc_lookup(dir, name, len, result);
+	if (retval != -ENOENT)
+		return retval;
+	
+	pid = 0;
+	while (len-- > 0) {
+		c = *name - '0';
+		name++;
+		if (c > 9) {
+			pid = 0;
+			break;
 		}
-		for (i = 0 ; i < NR_TASKS ; i++)
-			if (task[i] && task[i]->pid == pid)
-				break;
-		if (!pid || i >= NR_TASKS) {
-			iput(dir);
-			return -ENOENT;
+		pid *= 10;
+		pid += c;
+		if (pid & 0xffff0000) {
+			pid = 0;
+			break;
 		}
-		ino = (pid << 16) + 2;
 	}
-	if (!(*result = iget(dir->i_sb,ino))) {
+	for (i = 0 ; i < NR_TASKS ; i++)
+		if (task[i] && task[i]->pid == pid)
+			break;
+	if (!pid || i >= NR_TASKS) {
 		iput(dir);
 		return -ENOENT;
 	}
+	ino = (pid << 16) + PROC_PID_INO;
+	if (!(*result = proc_get_inode(dir->i_sb, ino, &proc_pid))) {
+		iput(dir);
+		return -EINVAL;
+	}
 	iput(dir);
-	(*result)->u.generic_ip = de;
 	return 0;
 }
 
+/*
+ * This returns non-zero if at EOF, so that the /proc
+ * root directory can use this and check if it should
+ * continue with the <pid> entries..
+ *
+ * Note that the VFS-layer doesn't care about the return
+ * value of the readdir() call, as long as it's non-negative
+ * for success..
+ */
+int proc_readdir(struct inode * inode, struct file * filp,
+	void * dirent, filldir_t filldir)
+{
+	struct proc_dir_entry * de;
+	unsigned int ino;
+	int i;
+
+	if (!inode || !S_ISDIR(inode->i_mode))
+		return -ENOTDIR;
+	ino = inode->i_ino;
+	de = (struct proc_dir_entry *) inode->u.generic_ip;
+	if (!de)
+		return -EINVAL;
+	i = filp->f_pos;
+	switch (i) {
+		case 0:
+			if (filldir(dirent, ".", 1, i, ino) < 0)
+				return 0;
+			i++;
+			filp->f_pos++;
+			/* fall through */
+		case 1:
+			if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
+				return 0;
+			i++;
+			filp->f_pos++;
+			/* fall through */
+		default:
+			ino &= ~0xffff;
+			de = de->subdir;
+			i -= 2;
+			for (;;) {
+				if (!de)
+					return 1;
+				if (!i)
+					break;
+				de = de->next;
+				i--;
+			}
+
+			do {
+				if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
+					return 0;
+				filp->f_pos++;
+				de = de->next;
+			} while (de);
+	}
+	return 1;
+}
+
 #define NUMBUF 10
 
-static int proc_readroot(struct inode * inode, struct file * filp,
+static int proc_root_readdir(struct inode * inode, struct file * filp,
 	void * dirent, filldir_t filldir)
 {
 	char buf[NUMBUF];
 	unsigned int nr,pid;
 	unsigned long i,j;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
 	nr = filp->f_pos;
-	while (nr < NR_ROOT_DIRENTRY) {
-		struct proc_dir_entry * de = root_dir + nr;
-
-		if (filldir(dirent, de->name, de->namelen, nr, de->low_ino) < 0)
-			return 0;
-		filp->f_pos++;
-		nr++;
+	if (nr < FIRST_PROCESS_ENTRY) {
+		int error = proc_readdir(inode, filp, dirent, filldir);
+		if (error <= 0)
+			return error;
+		filp->f_pos = nr = FIRST_PROCESS_ENTRY;
 	}
 
-	for (nr -= NR_ROOT_DIRENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
+	for (nr -= FIRST_PROCESS_ENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
 		struct task_struct * p = task[nr];
 
 		if (!p || !(pid = p->pid))
@@ -183,7 +431,7 @@
 			i /= 10;
 		} while (i);
 
-		if (filldir(dirent, buf+j, NUMBUF-j, nr+NR_ROOT_DIRENTRY, (pid << 16)+2) < 0)
+		if (filldir(dirent, buf+j, NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
 			break;
 	}
 	return 0;
diff -u --recursive --new-file v1.3.18/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v1.3.18/linux/fs/proc/scsi.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/proc/scsi.c	Tue Aug 15 14:41:58 1995
@@ -80,6 +80,15 @@
     NULL	    /* permission  */
 };
 
+struct proc_dir_entry proc_scsi = {
+	PROC_SCSI, 4, "scsi",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+	0, &proc_scsi_inode_operations,
+	NULL, NULL,
+	NULL,
+	&proc_root, NULL
+};
+
 struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3]; 
 struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4]; 
 
@@ -158,7 +167,7 @@
     for (; de->name ; de++) {
 	if (!proc_match(len, name, de))
 	    continue;
-	*result = iget(dir->i_sb, de->low_ino);
+	*result = proc_get_inode(dir->i_sb, de->low_ino, de);
 	iput(dir);
 	if (!*result)
 	    return(-ENOENT);
diff -u --recursive --new-file v1.3.18/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- v1.3.18/linux/fs/smbfs/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/smbfs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,20 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	proc.o sock.o inode.o file.o dir.o \
-	ioctl.o mmap.o
-
-smbfs.o: $(OBJS)
-	$(LD) -r -o smbfs.o $(OBJS)
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules: smbfs.o
+O_TARGET := smbfs.o
+O_OBJS   := proc.o sock.o inode.o file.o dir.o ioctl.o mmap.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/sysv/Makefile linux/fs/sysv/Makefile
--- v1.3.18/linux/fs/sysv/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/sysv/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,21 +7,9 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
-	fsync.o truncate.o
-
-sysv.o: $(OBJS)
-	$(LD) -r -o sysv.o $(OBJS)
-
-modules: sysv.o
-	ln -sf ../fs/sysv/sysv.o $(TOPDIR)/modules
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := sysv.o
+O_OBJS   := ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
+		fsync.o truncate.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile
--- v1.3.18/linux/fs/umsdos/Makefile	Tue Jul 11 10:02:58 1995
+++ linux/fs/umsdos/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,30 +7,18 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
+O_TARGET := umsdos.o
+O_OBJS   := dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o \
+		rdir.o symlink.o #check.o
+M_OBJS   := $(O_TARGET)
 
-OBJS=	dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o\
-	rdir.o symlink.o #check.o
-
-umsdos.o: $(OBJS)
-	$(LD) -r -o umsdos.o $(OBJS)
-
-modules: umsdos.o
-	ln -sf ../fs/umsdos/umsdos.o $(TOPDIR)/modules
+include $(TOPDIR)/Rules.make
 
 clean:
 	rm -f core *.o *.a *.s
 
-dep:
-	$(CPP) -M *.c > .depend
-
 p:
 	proto *.c >/usr/include/linux/umsdos_fs.p
 
 doc:
 	nadoc -i -p umsdos.doc - /tmp/umsdos.mpg
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/fs/xiafs/Makefile linux/fs/xiafs/Makefile
--- v1.3.18/linux/fs/xiafs/Makefile	Tue Jul 11 10:02:59 1995
+++ linux/fs/xiafs/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,21 +7,8 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS=	bitmap.o truncate.o namei.o inode.o \
-	file.o dir.o symlink.o fsync.o
-
-xiafs.o: $(OBJS)
-	$(LD) -r -o xiafs.o $(OBJS)
-
-modules: xiafs.o
-	ln -sf ../fs/xiafs/xiafs.o $(TOPDIR)/modules
-
-dep:
-	$(CPP) -M *.c > .depend
+O_TARGET := xiafs.o
+O_OBJS   := bitmap.o truncate.o namei.o inode.o file.o dir.o symlink.o fsync.o
+M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v1.3.18/linux/include/asm-alpha/byteorder.h	Fri Jun  2 13:51:16 1995
+++ linux/include/asm-alpha/byteorder.h	Mon Aug 14 12:57:03 1995
@@ -6,12 +6,12 @@
 #undef htonl
 #undef htons
 
-#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN
 #endif
 
-#ifndef LITTLE_ENDIAN_BITFIELD
-#define LITTLE_ENDIAN_BITFIELD
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
 #endif
 
 extern unsigned long int	ntohl(unsigned long int);
diff -u --recursive --new-file v1.3.18/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h
--- v1.3.18/linux/include/asm-i386/byteorder.h	Sat Apr 29 10:19:32 1995
+++ linux/include/asm-i386/byteorder.h	Mon Aug 14 12:56:05 1995
@@ -6,12 +6,12 @@
 #undef htonl
 #undef htons
 
-#ifndef LITTLE_ENDIAN
-#define LITTLE_ENDIAN 1234
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
 #endif
 
-#ifndef LITTLE_ENDIAN_BITFIELD
-#define LITTLE_ENDIAN_BITFIELD
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
 #endif
 
 extern unsigned long int	ntohl(unsigned long int);
diff -u --recursive --new-file v1.3.18/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v1.3.18/linux/include/asm-i386/io.h	Thu Jun 29 19:02:54 1995
+++ linux/include/asm-i386/io.h	Mon Aug 14 07:36:45 1995
@@ -89,9 +89,9 @@
 
 #define __OUT(s,s1,x) \
 __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \
-__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); } \
+__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \
 __OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \
-__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); SLOW_DOWN_IO; }
+__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; }
 
 #define __IN1(s) \
 extern inline unsigned int __in##s(unsigned short port) { unsigned int _v;
@@ -101,9 +101,9 @@
 
 #define __IN(s,s1,i...) \
 __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \
-__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); return _v; } \
+__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \
-__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; }
+__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; }
 
 #define __INS(s) \
 extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
diff -u --recursive --new-file v1.3.18/linux/include/asm-mips/byteorder.h linux/include/asm-mips/byteorder.h
--- v1.3.18/linux/include/asm-mips/byteorder.h	Mon Apr 17 13:47:56 1995
+++ linux/include/asm-mips/byteorder.h	Mon Aug 14 12:56:33 1995
@@ -7,11 +7,11 @@
 #undef htons
 
 #ifdef MIPSEL
-#define LITTLE_ENDIAN
-#define LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN_BITFIELD
 #elif MIPSEB
-#define BIG_ENDIAN
-#define BIG_ENDIAN_BITFIELD
+#define __BIG_ENDIAN
+#define __BIG_ENDIAN_BITFIELD
 #else
 #error "MIPS but neither MIPSEL nor MIPSEB?"
 #endif
diff -u --recursive --new-file v1.3.18/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v1.3.18/linux/include/asm-sparc/bitops.h	Tue Jun 27 14:11:45 1995
+++ linux/include/asm-sparc/bitops.h	Mon Aug 14 12:57:34 1995
@@ -35,13 +35,13 @@
  *  31     24  23     16  15      8  7       0
  */
 
-/* #define LITTLE_ENDIAN_BITOPS */
+/* #define __LITTLE_ENDIAN_BITOPS */
 
 extern __inline__ unsigned int set_bit(unsigned int nr, void *vaddr)
 {
 
 
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
 
         int retval;
@@ -101,7 +101,7 @@
 
 extern __inline__ unsigned int clear_bit(unsigned int nr, void *vaddr)
 {
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
 
         int retval;
@@ -162,7 +162,7 @@
 
 extern __inline__ unsigned int change_bit(unsigned int nr, void *vaddr)
 {
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
 
         int retval;
@@ -225,7 +225,7 @@
 
 extern __inline__ unsigned int test_bit(int nr, void *vaddr)
 {
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
         unsigned char mask;
         unsigned char *addr = (unsigned char *)vaddr;
@@ -254,7 +254,7 @@
 
   cnt = 0;
 
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
   for(int byte_bit = 24; byte_bit >=0; byte_bit -= 8)
 	  for(int bit = 0; bit<8; bit++)
@@ -283,7 +283,7 @@
 extern __inline__ unsigned long
 find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
-#ifdef LITTLE_ENDIAN_BITOPS
+#ifdef __LITTLE_ENDIAN_BITOPS
 
 	/* FOO, needs to be written */
 
diff -u --recursive --new-file v1.3.18/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h
--- v1.3.18/linux/include/asm-sparc/byteorder.h	Mon Apr 17 13:47:56 1995
+++ linux/include/asm-sparc/byteorder.h	Mon Aug 14 12:59:16 1995
@@ -6,8 +6,8 @@
 #undef htonl
 #undef htons
 
-#define BIG_ENDIAN
-#define BIG_ENDIAN_BITFIELD
+#define __BIG_ENDIAN
+#define __BIG_ENDIAN_BITFIELD
 
 extern unsigned long int	ntohl(unsigned long int);
 extern unsigned short int	ntohs(unsigned short int);
diff -u --recursive --new-file v1.3.18/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v1.3.18/linux/include/linux/genhd.h	Wed Aug  2 13:21:16 1995
+++ linux/include/linux/genhd.h	Sun Aug 13 20:19:12 1995
@@ -18,6 +18,7 @@
 #define EXTENDED_PARTITION 5
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
+#define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
 #define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
 #define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
 	
@@ -47,9 +48,9 @@
 	int max_p;			/* maximum partitions per device */
 	int max_nr;			/* maximum number of real devices */
 
-	void (*init)(void);		/* Initialization called before we do our thing */
+	void (*init)(struct gendisk *);	/* Initialization called before we do our thing */
 	struct hd_struct *part;		/* partition table */
-	int *sizes;			/* size of device in blocks */
+	int *sizes;			/* device size in blocks, copied to blk_size[] */
 	int nr_real;			/* number of real devices */
 
 	void *real_devices;		/* internal use */
diff -u --recursive --new-file v1.3.18/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v1.3.18/linux/include/linux/hdreg.h	Tue Jul 11 10:02:59 1995
+++ linux/include/linux/hdreg.h	Tue Aug 15 20:09:43 1995
@@ -5,12 +5,14 @@
 
 /*
  * This file contains some defines for the AT-hd-controller.
- * Various sources. Check out some definitions (see comments with
- * a ques).
+ * Various sources.  
  */
 
+#define HD_IRQ 14		/* the standard disk interrupt */
+
+/* ide.c has it's own port definitions in "ide.h" */
+
 /* Hd controller regs. Ref: IBM AT Bios-listing */
-/* For a second IDE interface, xor all addresses with 0x80 */
 #define HD_DATA		0x1f0	/* _CTL when writing */
 #define HD_ERROR	0x1f1	/* see err-bits */
 #define HD_NSECTOR	0x1f2	/* nr of sectors to read/write */
@@ -26,6 +28,8 @@
 #define HD_CMD		0x3f6	/* used for resets */
 #define HD_ALTSTATUS	0x3f6	/* same as HD_STATUS but doesn't clear irq */
 
+/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */
+
 /* Bits of HD_STATUS */
 #define ERR_STAT	0x01
 #define INDEX_STAT	0x02
@@ -45,10 +49,13 @@
 #define WIN_INIT		0x60
 #define WIN_SEEK 		0x70
 #define WIN_DIAGNOSE		0x90
-#define WIN_SPECIFY		0x91
+#define WIN_SPECIFY		0x91	/* set drive geometry translation */
 #define WIN_SETIDLE1		0xE3
 #define WIN_SETIDLE2		0x97
 
+#define WIN_DOORLOCK		0xde	/* lock door on removeable drives */
+#define WIN_DOORUNLOCK		0xdf	/* unlock door on removeable drives */
+
 #define WIN_PIDENTIFY		0xA1	/* identify ATA-PI device	*/
 #define WIN_MULTREAD		0xC4	/* read multiple sectors	*/
 #define WIN_MULTWRITE		0xC5	/* write multiple sectors	*/
@@ -147,11 +154,7 @@
 void hd_setup(char *, int *);
 #endif	/* CONFIG_BLK_DEV_HD */
 #ifdef CONFIG_BLK_DEV_IDE
-void ide_setup(char *, int *);
-void hda_setup(char *, int *);
-void hdb_setup(char *, int *);
-void hdc_setup(char *, int *);
-void hdd_setup(char *, int *);
+void ide_setup(char *);
 #endif	/* CONFIG_BLK_DEV_IDE */
 
 #endif	/* _LINUX_HDREG_H */
diff -u --recursive --new-file v1.3.18/linux/include/linux/if.h linux/include/linux/if.h
--- v1.3.18/linux/include/linux/if.h	Tue Jun  6 11:22:11 1995
+++ linux/include/linux/if.h	Tue Aug 15 18:37:01 1995
@@ -148,9 +148,4 @@
 #define	ifc_buf	ifc_ifcu.ifcu_buf		/* buffer address	*/
 #define	ifc_req	ifc_ifcu.ifcu_req		/* array of structures	*/
 
-
-/* BSD UNIX expects to find these here, so here we go: */
-#include <linux/if_arp.h>
-#include <linux/route.h>
-
 #endif /* _LINUX_IF_H */
diff -u --recursive --new-file v1.3.18/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v1.3.18/linux/include/linux/if_ether.h	Fri Jul  7 08:54:54 1995
+++ linux/include/linux/if_ether.h	Tue Aug 15 18:45:49 1995
@@ -20,7 +20,6 @@
 #ifndef _LINUX_IF_ETHER_H
 #define _LINUX_IF_ETHER_H
 
-
 /* 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	 */
diff -u --recursive --new-file v1.3.18/linux/include/linux/in.h linux/include/linux/in.h
--- v1.3.18/linux/include/linux/in.h	Thu Jul 13 16:20:21 1995
+++ linux/include/linux/in.h	Tue Aug 15 18:28:49 1995
@@ -108,6 +108,7 @@
 
 /* Address to loopback in software to local host.  */
 #define	INADDR_LOOPBACK		0x7f000001	/* 127.0.0.1   */
+#define	IN_LOOPBACK(a)		((((long int) (a)) & 0xff000000) == 0x7f000000)
 
 /* Defines for Multicast INADDR */
 #define INADDR_UNSPEC_GROUP   	0xe0000000      /* 224.0.0.0   */
diff -u --recursive --new-file v1.3.18/linux/include/linux/ip.h linux/include/linux/ip.h
--- v1.3.18/linux/include/linux/ip.h	Mon Apr 17 13:47:56 1995
+++ linux/include/linux/ip.h	Tue Aug 15 18:27:00 1995
@@ -34,10 +34,10 @@
 	__u8	len;
 	__u8	ptr;
 	union {
-#if defined(LITTLE_ENDIAN_BITFIELD)
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u8	flags:4,
 		overflow:4;
-#elif defined(BIG_ENDIAN_BITFIELD)
+#elif defined(__BIG_ENDIAN_BITFIELD)
 	__u8	overflow:4,
 		flags:4;
 #else
@@ -72,10 +72,10 @@
 
 
 struct iphdr {
-#if defined(LITTLE_ENDIAN_BITFIELD)
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u8	ihl:4,
 		version:4;
-#elif defined (BIG_ENDIAN_BITFIELD)
+#elif defined (__BIG_ENDIAN_BITFIELD)
 	__u8	version:4,
   		ihl:4;
 #else
diff -u --recursive --new-file v1.3.18/linux/include/linux/major.h linux/include/linux/major.h
--- v1.3.18/linux/include/linux/major.h	Fri Jul  7 08:54:54 1995
+++ linux/include/linux/major.h	Sun Aug 13 20:19:12 1995
@@ -20,7 +20,7 @@
  *  0 - unnamed                unnamed                minor 0 = true nodev
  *  1 - /dev/mem               ramdisk
  *  2 -                        floppy
- *  3 -                        hd
+ *  3 -                        ide0 or hd
  *  4 - /dev/tty*
  *  5 - /dev/tty; /dev/cua*
  *  6 - lp
@@ -39,7 +39,7 @@
  * 19 - cyclades /dev/ttyC*
  * 20 - cyclades /dev/cub*     mitsumi (mcdx) cdrom
  * 21 - scsi generic
- * 22 -                        (at2disk)
+ * 22 -                        ide1
  * 23 -                        mitsumi cdrom
  * 24 -	                       sony535 cdrom
  * 25 -                        matsushita cdrom       minors 0..3
@@ -48,6 +48,8 @@
  * 28 -                        matsushita cdrom 4     minors 0..3
  * 29 -                        aztech/orchid/okano/wearnes cdrom
  * 32 -                        philips/lms cm206 cdrom
+ * 33 -                        ide2
+ * 34 -                        ide3
  */
 
 #define UNNAMED_MAJOR	0
@@ -87,6 +89,8 @@
 #define MATSUSHITA_CDROM4_MAJOR 28
 #define AZTECH_CDROM_MAJOR 29
 #define CM206_CDROM_MAJOR 32
+#define IDE2_MAJOR	33
+#define IDE3_MAJOR	34
 
 /*
  * Tests for SCSI devices.
diff -u --recursive --new-file v1.3.18/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.18/linux/include/linux/proc_fs.h	Sun Aug 13 14:45:35 1995
+++ linux/include/linux/proc_fs.h	Tue Aug 15 20:10:20 1995
@@ -135,22 +135,57 @@
 	unsigned short low_ino;
 	unsigned short namelen;
 	const char *name;
+	mode_t mode;
+	nlink_t nlink;
+	uid_t uid;
+	gid_t gid;
+	unsigned long size;
+	struct inode_operations * ops;
 	int (*get_info)(char *, char **, off_t, int, int);
 	void (*fill_inode)(struct inode *);
 	struct proc_dir_entry *next, *parent, *subdir;
 };
 
+extern struct proc_dir_entry proc_root;
+extern struct proc_dir_entry proc_net;
+extern struct proc_dir_entry proc_scsi;
+extern struct proc_dir_entry proc_pid;
+extern struct proc_dir_entry proc_pid_fd;
+
+extern void proc_root_init(void);
+extern void proc_base_init(void);
+extern void proc_net_init(void);
+
+extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
+extern int proc_unregister(struct proc_dir_entry *, int);
+
+static inline int proc_net_register(struct proc_dir_entry * x)
+{
+	return proc_register(&proc_net, x);
+}
+
+static inline int proc_net_unregister(int x)
+{
+	return proc_unregister(&proc_net, x);
+}
+
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
-extern void proc_put_inode(struct inode *);
-extern void proc_put_super(struct super_block *);
+extern struct inode * proc_get_inode(struct super_block *, int, struct proc_dir_entry *);
 extern void proc_statfs(struct super_block *, struct statfs *, int);
 extern void proc_read_inode(struct inode *);
 extern void proc_write_inode(struct inode *);
 extern int proc_match(int, const char *, struct proc_dir_entry *);
-extern int proc_net_register(struct proc_dir_entry *);
-extern int proc_net_unregister(int);
 
-extern struct inode_operations proc_root_inode_operations;
+/*
+ * These are generic /proc routines that use the internal
+ * "struct proc_dir_entry" tree to traverse the filesystem.
+ *
+ * The /proc root directory has extended versions to take care
+ * of the /proc/<pid> subdirectories.
+ */
+extern int proc_readdir(struct inode *, struct file *, void *, filldir_t);
+extern int proc_lookup(struct inode *, const char *, int, struct inode **);
+
 extern struct inode_operations proc_base_inode_operations;
 extern struct inode_operations proc_net_inode_operations;
 extern struct inode_operations proc_netdir_inode_operations;
diff -u --recursive --new-file v1.3.18/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v1.3.18/linux/include/linux/skbuff.h	Thu Jul 13 16:20:21 1995
+++ linux/include/linux/skbuff.h	Tue Aug 15 20:10:20 1995
@@ -133,7 +133,7 @@
 extern int			skb_device_locked(struct sk_buff *skb);
 extern unsigned char *		skb_put(struct sk_buff *skb, int len);
 extern unsigned char *		skb_push(struct sk_buff *skb, int len);
-extern int			skb_pull(struct sk_buff *skb, int len);
+extern unsigned char *		skb_pull(struct sk_buff *skb, int len);
 extern int			skb_headroom(struct sk_buff *skb);
 extern int			skb_tailroom(struct sk_buff *skb);
 extern void			skb_reserve(struct sk_buff *skb, int len);
@@ -324,13 +324,13 @@
 	return skb->data;
 }
 
-extern __inline__ int skb_pull(struct sk_buff *skb, int len)
+extern __inline__ unsigned char * skb_pull(struct sk_buff *skb, int len)
 {
-	if(len>skb->len)
-		len=skb->len;
+	if(len > skb->len)
+		return NULL;
 	skb->data+=len;
 	skb->len-=len;
-	return len;
+	return skb->data;
 }
 
 extern __inline__ int skb_headroom(struct sk_buff *skb)
diff -u --recursive --new-file v1.3.18/linux/include/linux/tcp.h linux/include/linux/tcp.h
--- v1.3.18/linux/include/linux/tcp.h	Mon Jun 12 12:27:28 1995
+++ linux/include/linux/tcp.h	Mon Aug 14 12:59:16 1995
@@ -26,7 +26,7 @@
 	__u16	dest;
 	__u32	seq;
 	__u32	ack_seq;
-#if defined(LITTLE_ENDIAN_BITFIELD)
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u16	res1:4,
 		doff:4,
 		fin:1,
@@ -36,7 +36,7 @@
 		ack:1,
 		urg:1,
 		res2:2;
-#elif defined(BIG_ENDIAN_BITFIELD)
+#elif defined(__BIG_ENDIAN_BITFIELD)
 	__u16	doff:4,
 		res1:4,
 		res2:2,
diff -u --recursive --new-file v1.3.18/linux/include/linux/xd.h linux/include/linux/xd.h
--- v1.3.18/linux/include/linux/xd.h	Tue Aug  8 12:31:42 1995
+++ linux/include/linux/xd.h	Sun Aug 13 20:19:12 1995
@@ -107,7 +107,7 @@
 void xd_setup (char *command,int *integers);
 static u_char xd_detect (u_char *controller,u_char **address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
-static void xd_geninit (void);
+static void xd_geninit (struct gendisk *);
 
 static int xd_open (struct inode *inode,struct file *file);
 static void do_xd_request (void);
diff -u --recursive --new-file v1.3.18/linux/include/net/ax25.h linux/include/net/ax25.h
--- v1.3.18/linux/include/net/ax25.h	Wed Aug  9 14:55:43 1995
+++ linux/include/net/ax25.h	Tue Aug 15 20:12:07 1995
@@ -158,7 +158,7 @@
 extern ax25_address *ax25_findbyuid(uid_t);
 extern void ax25_queue_xmit(struct sk_buff *, struct device *, int);
 
-#include "ax25call.h"
+#include <net/ax25call.h>
 
 /* ax25_in.c */
 extern int  ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int);
diff -u --recursive --new-file v1.3.18/linux/include/net/eth.h linux/include/net/eth.h
--- v1.3.18/linux/include/net/eth.h	Thu Jul 13 16:20:21 1995
+++ linux/include/net/eth.h	Thu Jan  1 02:00:00 1970
@@ -1,37 +0,0 @@
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  NET  is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		Definitions for the Ethernet handlers.
- *
- * Version:	@(#)eth.h	1.0.4	05/13/93
- *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
- *		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 _ETH_H
-#define _ETH_H
-
-
-#include <linux/if_ether.h>
-
-
-extern char		*eth_print(unsigned char *ptr);
-extern void		eth_dump(struct ethhdr *eth);
-extern int		eth_header(struct sk_buff *skb, struct device *dev,
-				   unsigned short type, void *daddr,
-				   void *saddr, unsigned len);
-extern int		eth_rebuild_header(void *buff, struct device *dev,
-				   unsigned long dst, struct sk_buff *skb);
-extern void		eth_add_arp(unsigned long addr, struct sk_buff *skb,
-				    struct device *dev);
-extern unsigned short	eth_type_trans(struct sk_buff *skb, struct device *dev);
-extern void		eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
-
-#endif	/* _ETH_H */
diff -u --recursive --new-file v1.3.18/linux/include/net/ip.h linux/include/net/ip.h
--- v1.3.18/linux/include/net/ip.h	Wed Aug  9 14:55:43 1995
+++ linux/include/net/ip.h	Tue Aug 15 20:16:43 1995
@@ -27,10 +27,10 @@
 #include <linux/netdevice.h>
 
 #ifndef _SNMP_H
-#include "snmp.h"
+#include <net/snmp.h>
 #endif
 
-#include "sock.h"	/* struct sock */
+#include <net/sock.h>	/* struct sock */
 
 /* IP flags. */
 #define IP_CE		0x8000		/* Flag: "Congestion"		*/
diff -u --recursive --new-file v1.3.18/linux/include/net/ipx.h linux/include/net/ipx.h
--- v1.3.18/linux/include/net/ipx.h	Tue Jun  6 11:22:17 1995
+++ linux/include/net/ipx.h	Tue Aug 15 20:12:07 1995
@@ -12,7 +12,7 @@
 #define _NET_INET_IPX_H_
 
 #include <linux/skbuff.h>
-#include "datalink.h"
+#include <net/datalink.h>
 #include <linux/ipx.h>
 
 typedef struct
@@ -44,7 +44,7 @@
 
 typedef struct sock ipx_socket;
 
-#include "ipxcall.h"
+#include <net/ipxcall.h>
 extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
 extern void ipxrtr_device_down(struct device *dev);
 
diff -u --recursive --new-file v1.3.18/linux/include/net/netrom.h linux/include/net/netrom.h
--- v1.3.18/linux/include/net/netrom.h	Sun Aug 13 14:45:35 1995
+++ linux/include/net/netrom.h	Tue Aug 15 15:22:24 1995
@@ -97,7 +97,7 @@
 extern int  nr_rx_ip(struct sk_buff *, struct device *);
 extern int  nr_init(struct device *);
 
-#include "nrcall.h"
+#include <net/nrcall.h>
 
 /* nr_in.c */
 extern int  nr_process_rx_frame(struct sock *, struct sk_buff *);
diff -u --recursive --new-file v1.3.18/linux/include/net/sock.h linux/include/net/sock.h
--- v1.3.18/linux/include/net/sock.h	Sun Aug 13 14:45:35 1995
+++ linux/include/net/sock.h	Tue Aug 15 20:12:08 1995
@@ -37,15 +37,15 @@
 #include <linux/config.h>
 
 #include <linux/skbuff.h>	/* struct sk_buff */
-#include "protocol.h"		/* struct inet_protocol */
+#include <net/protocol.h>		/* struct inet_protocol */
 #ifdef CONFIG_AX25
-#include "ax25.h"
+#include <net/ax25.h>
 #ifdef CONFIG_NETROM
-#include "netrom.h"
+#include <net/netrom.h>
 #endif
 #endif
 #ifdef CONFIG_IPX
-#include "ipx.h"
+#include <net/ipx.h>
 #endif
 #ifdef CONFIG_ATALK
 #include <linux/atalk.h>
diff -u --recursive --new-file v1.3.18/linux/init/main.c linux/init/main.c
--- v1.3.18/linux/init/main.c	Tue Aug  8 12:31:42 1995
+++ linux/init/main.c	Sun Aug 13 20:19:12 1995
@@ -160,13 +160,7 @@
 #ifdef CONFIG_SCSI
 	{ "max_scsi_luns=", scsi_luns_setup },
 #endif
-#ifdef CONFIG_BLK_DEV_IDE
-	{ "hda=", hda_setup },
-	{ "hdb=", hdb_setup },
-	{ "hdc=", hdc_setup },
-	{ "hdd=", hdd_setup },
-	{ "hd=",  ide_setup },
-#elif defined(CONFIG_BLK_DEV_HD)
+#if defined(CONFIG_BLK_DEV_HD)
 	{ "hd=", hd_setup },
 #endif
 #ifdef CONFIG_CHR_DEV_ST
@@ -253,6 +247,13 @@
 	int i = 0;
 	int ints[11];
 
+#ifdef CONFIG_BLK_DEV_IDE
+	/* ide driver needs the basic string, rather than pre-processed values */
+	if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) {
+		ide_setup(line);
+		return 1;
+	}
+#endif
 	while (bootsetups[i].str) {
 		int n = strlen(bootsetups[i].str);
 		if (!strncmp(line,bootsetups[i].str,n)) {
diff -u --recursive --new-file v1.3.18/linux/ipc/Makefile linux/ipc/Makefile
--- v1.3.18/linux/ipc/Makefile	Tue Jul 11 10:02:59 1995
+++ linux/ipc/Makefile	Tue Aug 15 15:07:02 1995
@@ -7,25 +7,11 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	=  util.o 
-SRCS	=  util.c
+O_TARGET := ipc.o
+O_OBJS   := util.o
 
 ifdef CONFIG_SYSVIPC
-OBJS	:= $(OBJS) msg.o sem.o shm.o 
-SRCS	:= $(SRCS) msg.c sem.c shm.c
+O_OBJS += msg.o sem.o shm.o
 endif
-
-ipc.o: $(OBJS) 
-	$(LD) -r -o ipc.o $(OBJS) 
-
-dep:
-	$(CPP) -M $(SRCS) > .depend
-
-modules:
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/kernel/Makefile linux/kernel/Makefile
--- v1.3.18/linux/kernel/Makefile	Tue Jul 11 10:03:00 1995
+++ linux/kernel/Makefile	Tue Aug 15 15:07:02 1995
@@ -9,31 +9,19 @@
 
 .S.s:
 	$(CPP) -traditional $< -o $*.s
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
 
-OBJS  = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
+O_TARGET := kernel.o
+O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
 	module.o exit.o signal.o itimer.o info.o time.o softirq.o \
 	resource.o
-
 SYMTAB_OBJS = ksyms.o
+O_OBJS     += $(SYMTAB_OBJS)
 
-all: kernel.o
+$(O_TARGET): $(SYMTAB_OBJS:.o=.ver)
 
-include ../versions.mk
+include $(TOPDIR)/Rules.make
 
-kernel.o: $(SYMTAB_OBJS:.o=.ver) $(SYMTAB_OBJS) $(OBJS)
-	$(LD) -r -o kernel.o $(SYMTAB_OBJS) $(OBJS)
-	sync
+include ../versions.mk
 
 sched.o: sched.c
 	$(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
-
-dep:
-	$(CPP) -M *.c > .depend
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.18/linux/kernel/ksyms.c	Wed Aug  9 14:55:43 1995
+++ linux/kernel/ksyms.c	Tue Aug 15 18:08:34 1995
@@ -37,7 +37,6 @@
 #ifdef CONFIG_NET
 #include <linux/net.h>
 #include <linux/netdevice.h>
-#include <net/eth.h>
 #ifdef CONFIG_INET
 #include <linux/ip.h>
 #include <linux/etherdevice.h>
@@ -458,8 +457,8 @@
 	X(msdos_write_inode),
 #endif
 #ifdef CONFIG_PROC_FS
-	X(proc_net_register),
-	X(proc_net_unregister),
+	X(proc_register),
+	X(proc_unregister),
 #endif
 	/********************************************************
 	 * Do not add anything below this line,
diff -u --recursive --new-file v1.3.18/linux/kernel/ksyms.ver linux/kernel/ksyms.ver
--- v1.3.18/linux/kernel/ksyms.ver	Tue Jun  6 11:22:14 1995
+++ linux/kernel/ksyms.ver	Tue Aug 15 15:07:03 1995
@@ -192,3 +192,197 @@
 #define __down	_set_ver(__down, 75aa9e96)
 #endif /* _KSYMS_VER_ */
 #endif /* CONFIG_MODVERSIONS !__GENKSYMS__ */
+/**** This file is generated by genksyms  DO NOT EDIT! ****/
+#if defined(CONFIG_MODVERSIONS) && !defined(__GENKSYMS__)
+#ifndef _KSYMS_VER_
+#define _KSYMS_VER_
+#define rename_module_symbol	_set_ver(rename_module_symbol, b81c73c1)
+#define register_symtab	_set_ver(register_symtab, e910ea66)
+#define EISA_bus	_set_ver(EISA_bus, 7e37737c)
+#define wp_works_ok	_set_ver(wp_works_ok, f37f99e9)
+#define verify_area	_set_ver(verify_area, 4cfda560)
+#define do_mmap	_set_ver(do_mmap, 677e7ee1)
+#define do_munmap	_set_ver(do_munmap, 6221f117)
+#define zeromap_page_range	_set_ver(zeromap_page_range, 7c395a26)
+#define unmap_page_range	_set_ver(unmap_page_range, 0110085f)
+#define insert_vm_struct	_set_ver(insert_vm_struct, 1f4e4882)
+#define merge_segments	_set_ver(merge_segments, 6854be5a)
+#define __get_free_pages	_set_ver(__get_free_pages, 5243d78b)
+#define free_pages	_set_ver(free_pages, 96448859)
+#define kmalloc	_set_ver(kmalloc, d31fb2cb)
+#define kfree_s	_set_ver(kfree_s, 1e72eb79)
+#define vmalloc	_set_ver(vmalloc, 667f3e25)
+#define vfree	_set_ver(vfree, 6df52add)
+#define getname	_set_ver(getname, 81487159)
+#define putname	_set_ver(putname, b19e8126)
+#define __iget	_set_ver(__iget, ee2b6320)
+#define iput	_set_ver(iput, 59241ced)
+#define namei	_set_ver(namei, 00478bcd)
+#define lnamei	_set_ver(lnamei, fcfddbb1)
+#define open_namei	_set_ver(open_namei, 414b2b0f)
+#define close_fp	_set_ver(close_fp, 1d4c15d8)
+#define check_disk_change	_set_ver(check_disk_change, b66ed457)
+#define invalidate_buffers	_set_ver(invalidate_buffers, c65255f1)
+#define fsync_dev	_set_ver(fsync_dev, a221190d)
+#define permission	_set_ver(permission, 0ebf7474)
+#define inode_setattr	_set_ver(inode_setattr, 0c80a3c1)
+#define inode_change_ok	_set_ver(inode_change_ok, 5d1cb326)
+#define generic_mmap	_set_ver(generic_mmap, d4ff59f3)
+#define set_blocksize	_set_ver(set_blocksize, f45fda38)
+#define getblk	_set_ver(getblk, d40228ac)
+#define bread	_set_ver(bread, c73bf0f0)
+#define breada	_set_ver(breada, eb8e858c)
+#define brelse	_set_ver(brelse, 4c27ac3d)
+#define ll_rw_block	_set_ver(ll_rw_block, f3aa4dd3)
+#define __wait_on_buffer	_set_ver(__wait_on_buffer, e8fcc968)
+#define dcache_lookup	_set_ver(dcache_lookup, 83336566)
+#define dcache_add	_set_ver(dcache_add, fe71f11e)
+#define register_chrdev	_set_ver(register_chrdev, da99513f)
+#define unregister_chrdev	_set_ver(unregister_chrdev, 61ea5ee8)
+#define register_blkdev	_set_ver(register_blkdev, 4699a621)
+#define unregister_blkdev	_set_ver(unregister_blkdev, d39bbca9)
+#define tty_register_driver	_set_ver(tty_register_driver, fcc8591c)
+#define tty_unregister_driver	_set_ver(tty_unregister_driver, c78132a8)
+#define tty_std_termios	_set_ver(tty_std_termios, cf350678)
+#define block_read	_set_ver(block_read, a7fe4f51)
+#define block_write	_set_ver(block_write, 902674c9)
+#define block_fsync	_set_ver(block_fsync, 182888d8)
+#define wait_for_request	_set_ver(wait_for_request, 9ca2932e)
+#define blksize_size	_set_ver(blksize_size, dea1eb55)
+#define hardsect_size	_set_ver(hardsect_size, ed1ee14f)
+#define blk_size	_set_ver(blk_size, f60b5398)
+#define blk_dev	_set_ver(blk_dev, dbf5fdd4)
+#define is_read_only	_set_ver(is_read_only, b0c5f83e)
+#define set_device_ro	_set_ver(set_device_ro, 8fb69e13)
+#define bmap	_set_ver(bmap, 73bb8bdd)
+#define sync_dev	_set_ver(sync_dev, 9bca536d)
+#define get_blkfops	_set_ver(get_blkfops, 83827791)
+#define register_serial	_set_ver(register_serial, 3425f38c)
+#define unregister_serial	_set_ver(unregister_serial, c013d717)
+#define tty_hangup	_set_ver(tty_hangup, e3487df0)
+#define tty_wait_until_sent	_set_ver(tty_wait_until_sent, da85d428)
+#define tty_check_change	_set_ver(tty_check_change, 705eaab0)
+#define tty_hung_up_p	_set_ver(tty_hung_up_p, f99ac1e4)
+#define register_filesystem	_set_ver(register_filesystem, 1c7110ef)
+#define unregister_filesystem	_set_ver(unregister_filesystem, 5e353af7)
+#define register_binfmt	_set_ver(register_binfmt, 66ece706)
+#define unregister_binfmt	_set_ver(unregister_binfmt, 41822618)
+#define lookup_exec_domain	_set_ver(lookup_exec_domain, 32f10d48)
+#define register_exec_domain	_set_ver(register_exec_domain, eda4711f)
+#define unregister_exec_domain	_set_ver(unregister_exec_domain, 78ea447c)
+#define request_irq	_set_ver(request_irq, 9e81629c)
+#define free_irq	_set_ver(free_irq, f487dc0c)
+#define enable_irq	_set_ver(enable_irq, 54e09f5f)
+#define disable_irq	_set_ver(disable_irq, b4449c1f)
+#define bh_active	_set_ver(bh_active, 98fb5ca1)
+#define bh_mask	_set_ver(bh_mask, 1abf3d3f)
+#define add_timer	_set_ver(add_timer, f13cb728)
+#define del_timer	_set_ver(del_timer, c7aff713)
+#define tq_timer	_set_ver(tq_timer, 46cf583e)
+#define tq_immediate	_set_ver(tq_immediate, 46cf583e)
+#define tq_scheduler	_set_ver(tq_scheduler, 46cf583e)
+#define tq_last	_set_ver(tq_last, 457cf547)
+#define timer_active	_set_ver(timer_active, 5a6747ee)
+#define timer_table	_set_ver(timer_table, 9e03b650)
+#define request_dma	_set_ver(request_dma, 2a687646)
+#define free_dma	_set_ver(free_dma, 5d4b914c)
+#define disable_hlt	_set_ver(disable_hlt, 794487ee)
+#define enable_hlt	_set_ver(enable_hlt, 9c7077bd)
+#define check_region	_set_ver(check_region, b91154fb)
+#define request_region	_set_ver(request_region, 138b0a1e)
+#define release_region	_set_ver(release_region, f41d6d31)
+#define wake_up	_set_ver(wake_up, e8d71419)
+#define wake_up_interruptible	_set_ver(wake_up_interruptible, 64c8cb92)
+#define sleep_on	_set_ver(sleep_on, 67a00cee)
+#define interruptible_sleep_on	_set_ver(interruptible_sleep_on, 6a5fc80d)
+#define schedule	_set_ver(schedule, 01000e51)
+#define current	_set_ver(current, fc1cb29b)
+#define jiffies	_set_ver(jiffies, 2f7c7437)
+#define xtime	_set_ver(xtime, e70c0be0)
+#define loops_per_sec	_set_ver(loops_per_sec, 40a14192)
+#define need_resched	_set_ver(need_resched, dfc016ea)
+#define kill_proc	_set_ver(kill_proc, 911f760a)
+#define kill_pg	_set_ver(kill_pg, 0a758a45)
+#define kill_sl	_set_ver(kill_sl, 49625e94)
+#define panic	_set_ver(panic, 400c0de3)
+#define printk	_set_ver(printk, ad1148ba)
+#define sprintf	_set_ver(sprintf, f9003107)
+#define vsprintf	_set_ver(vsprintf, e605cb6b)
+#define simple_strtoul	_set_ver(simple_strtoul, bdb8c1e3)
+#define system_utsname	_set_ver(system_utsname, 066845bc)
+#define sys_call_table	_set_ver(sys_call_table, 79fa4011)
+#define do_signal	_set_ver(do_signal, 86f9bc59)
+#define send_sig	_set_ver(send_sig, 5cddd8d9)
+#define setup_arg_pages	_set_ver(setup_arg_pages, fe68d94a)
+#define copy_strings	_set_ver(copy_strings, 232aee96)
+#define create_tables	_set_ver(create_tables, ba788fa2)
+#define do_execve	_set_ver(do_execve, 8c99dc0a)
+#define flush_old_exec	_set_ver(flush_old_exec, c737e178)
+#define open_inode	_set_ver(open_inode, 27302cb6)
+#define read_exec	_set_ver(read_exec, a80a2dd0)
+#define si_meminfo	_set_ver(si_meminfo, bb05fc9a)
+#define sock_register	_set_ver(sock_register, d68e1649)
+#define sock_unregister	_set_ver(sock_unregister, 72c332bd)
+#define inet_add_protocol	_set_ver(inet_add_protocol, 55292121)
+#define inet_del_protocol	_set_ver(inet_del_protocol, 73908a1b)
+#define slhc_init	_set_ver(slhc_init, e490a4b8)
+#define slhc_free	_set_ver(slhc_free, 39ab902b)
+#define slhc_remember	_set_ver(slhc_remember, db333be6)
+#define slhc_compress	_set_ver(slhc_compress, e753e2d2)
+#define slhc_uncompress	_set_ver(slhc_uncompress, 81cc1144)
+#define register_netdevice_notifier	_set_ver(register_netdevice_notifier, e7aace7c)
+#define unregister_netdevice_notifier	_set_ver(unregister_netdevice_notifier, be114416)
+#define floppy_track_buffer	_set_ver(floppy_track_buffer, c6e3f7c2)
+#define register_netdev	_set_ver(register_netdev, 0d8d1bb4)
+#define unregister_netdev	_set_ver(unregister_netdev, 25a99579)
+#define ether_setup	_set_ver(ether_setup, 4eafef91)
+#define alloc_skb	_set_ver(alloc_skb, b6b523ba)
+#define kfree_skb	_set_ver(kfree_skb, 0b938572)
+#define dev_kfree_skb	_set_ver(dev_kfree_skb, aa1fe7f4)
+#define netif_rx	_set_ver(netif_rx, d8051cb2)
+#define dev_rint	_set_ver(dev_rint, 040d3f4b)
+#define dev_tint	_set_ver(dev_tint, 860b350b)
+#define irq2dev_map	_set_ver(irq2dev_map, 10bdcd8a)
+#define dev_add_pack	_set_ver(dev_add_pack, 6d7d9be4)
+#define dev_remove_pack	_set_ver(dev_remove_pack, 784fa59f)
+#define dev_get	_set_ver(dev_get, 72ed90fd)
+#define dev_ioctl	_set_ver(dev_ioctl, 08760203)
+#define dev_queue_xmit	_set_ver(dev_queue_xmit, 4a478225)
+#define dev_base	_set_ver(dev_base, 0a8809f0)
+#define dev_close	_set_ver(dev_close, 9bdad56d)
+#define arp_find	_set_ver(arp_find, a141bd11)
+#define n_tty_ioctl	_set_ver(n_tty_ioctl, 538e5fa6)
+#define tty_register_ldisc	_set_ver(tty_register_ldisc, 8fdde939)
+#define kill_fasync	_set_ver(kill_fasync, 890501b6)
+#define in_scan_scsis	_set_ver(in_scan_scsis, 21874a88)
+#define scsi_register_module	_set_ver(scsi_register_module, 8eff1010)
+#define scsi_unregister_module	_set_ver(scsi_unregister_module, d913b8f0)
+#define scsi_free	_set_ver(scsi_free, 475dddfa)
+#define scsi_malloc	_set_ver(scsi_malloc, 1cce3f92)
+#define scsi_register	_set_ver(scsi_register, d6e77069)
+#define scsi_unregister	_set_ver(scsi_unregister, 3b0b616b)
+#define scsicam_bios_param	_set_ver(scsicam_bios_param, 3d965248)
+#define scsi_init_malloc	_set_ver(scsi_init_malloc, e5167cbc)
+#define scsi_init_free	_set_ver(scsi_init_free, 8b2721f8)
+#define print_command	_set_ver(print_command, 6f14cd75)
+#define print_msg	_set_ver(print_msg, 0465f877)
+#define print_status	_set_ver(print_status, 32f84646)
+#define set_writetime	_set_ver(set_writetime, 52131916)
+#define sys_tz	_set_ver(sys_tz, aa3c9782)
+#define __wait_on_super	_set_ver(__wait_on_super, 61a5c00a)
+#define file_fsync	_set_ver(file_fsync, d30a190f)
+#define clear_inode	_set_ver(clear_inode, da2b0e9f)
+#define refile_buffer	_set_ver(refile_buffer, 8c69e123)
+#define ___strtok	_set_ver(___strtok, 8b55d69c)
+#define init_fifo	_set_ver(init_fifo, 082629c7)
+#define super_blocks	_set_ver(super_blocks, e1f1ee99)
+#define chrdev_inode_operations	_set_ver(chrdev_inode_operations, 6ba1faa3)
+#define blkdev_inode_operations	_set_ver(blkdev_inode_operations, ed443696)
+#define read_ahead	_set_ver(read_ahead, bbcd3768)
+#define get_hash_table	_set_ver(get_hash_table, 3b5f3c55)
+#define get_empty_inode	_set_ver(get_empty_inode, 554bdc75)
+#define insert_inode_hash	_set_ver(insert_inode_hash, 59b8c371)
+#define event	_set_ver(event, a6aac9c1)
+#define __down	_set_ver(__down, 75aa9e96)
+#endif /* _KSYMS_VER_ */
+#endif /* CONFIG_MODVERSIONS !__GENKSYMS__ */
diff -u --recursive --new-file v1.3.18/linux/lib/Makefile linux/lib/Makefile
--- v1.3.18/linux/lib/Makefile	Tue Jul 11 10:03:00 1995
+++ linux/lib/Makefile	Tue Aug 15 15:07:03 1995
@@ -6,20 +6,8 @@
 # unless it's something special (ie not a .c file).
 #
 
-.s.o:
-	$(AS) -c -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-OBJS  = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \
-	execve.o wait.o string.o vsprintf.o
-
-lib.a: $(OBJS)
-	$(AR) rcs lib.a $(OBJS)
-	sync
-
-modules:
-dep:
-	$(CPP) -M *.c > .depend
+L_TARGET := lib.a
+L_OBJS   := ctype.o _exit.o open.o close.o errno.o write.o dup.o \
+            setsid.o execve.o wait.o string.o vsprintf.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/mm/Makefile linux/mm/Makefile
--- v1.3.18/linux/mm/Makefile	Tue Jul 11 10:03:00 1995
+++ linux/mm/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,20 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	= memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o
-
-mm.o: $(OBJS)
-	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-	$(CPP) -M *.c > .depend
-
+O_TARGET := mm.o
+O_OBJS	 := memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/802/Makefile linux/net/802/Makefile
--- v1.3.18/linux/net/802/Makefile	Wed Aug  9 14:55:43 1995
+++ linux/net/802/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,44 +7,24 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-
-OBJS	:= p8023.o
+O_TARGET := 802.o
+O_OBJS	  = p8023.o
 
 ifdef CONFIG_TR
-
-OBJS	:= $(OBJS) tr.o
-
+O_OBJS += tr.o
 endif
 
 ifdef CONFIG_IPX
-
-OBJS	:= $(OBJS) p8022.o psnap.o
-
+O_OBJS += p8022.o psnap.o
 endif
 
 ifdef CONFIG_ATALK
 ifndef CONFIG_IPX
-
-OBJS	:= $(OBJS) p8022.o psnap.o
-
+O_OBJS += p8022.o psnap.o
 endif
 endif
 
-802.o:		$(OBJS)
-		$(LD) -r -o 802.o $(OBJS)
-
-
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/Makefile linux/net/Makefile
--- v1.3.18/linux/net/Makefile	Wed Aug  9 14:55:43 1995
+++ linux/net/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,32 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-SUBDIRS     := 802 ax25 core ethernet ipv4 ipx unix appletalk netrom
-
-SUBOBJS     := $(foreach f,$(SUBDIRS),$f/$f.o)
-
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-OBJS	=  socket.o protocols.o
-
-all:		network.a
-
-network.a:	subdirs $(OBJS)
-		rm -f $@
-		$(AR) rcs $@ $(OBJS) $(SUBOBJS)
-
-subdirs:	dummy
-		set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
-
-dep:
-		$(CPP) -M *.c > .depend
-		set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
-
-modules: dummy
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i modules; done
-
+MOD_SUB_DIRS := ipv4
+ALL_SUB_DIRS := 802 ax25 core ethernet ipv4 ipx unix appletalk netrom
+SUB_DIRS     := $(ALL_SUB_DIRS)
+L_TARGET     := network.a
+L_OBJS	     :=  socket.o protocols.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/appletalk/Makefile linux/net/appletalk/Makefile
--- v1.3.18/linux/net/appletalk/Makefile	Wed Aug  9 14:55:43 1995
+++ linux/net/appletalk/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,23 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
+O_TARGET := appletalk.o
+O_OBJS	 := aarp.o ddp.o
 
-
-OBJS	:= aarp.o ddp.o
-
-
-appletalk.o:	$(OBJS)
-		$(LD) -r -o appletalk.o $(OBJS)
-
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v1.3.18/linux/net/appletalk/aarp.c	Mon Jul 31 15:59:03 1995
+++ linux/net/appletalk/aarp.c	Mon Aug 14 15:49:55 1995
@@ -584,7 +584,7 @@
 	 *	Frame size ok ?
 	 */
 	 
-	if(skb_pull(skb,sizeof(*ea))<sizeof(*ea))
+	if(!skb_pull(skb,sizeof(*ea)))
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
diff -u --recursive --new-file v1.3.18/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.18/linux/net/appletalk/ddp.c	Sun Aug 13 14:45:35 1995
+++ linux/net/appletalk/ddp.c	Tue Aug 15 14:45:20 1995
@@ -1864,12 +1864,23 @@
 	register_netdevice_notifier(&ddp_notifier);
 	aarp_proto_init();
 
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_ATALK, 9, "appletalk", atalk_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_AT_ROUTE, 11,"atalk_route", atalk_rt_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_ATIF, 11,"atalk_iface", atalk_if_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_ATALK, 9, "appletalk",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		atalk_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_AT_ROUTE, 11,"atalk_route",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		atalk_rt_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_ATIF, 11,"atalk_iface",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		atalk_if_get_info
+	});
 
 	printk("Appletalk BETA 0.11 for Linux NET3.030\n");
 }
diff -u --recursive --new-file v1.3.18/linux/net/ax25/Makefile linux/net/ax25/Makefile
--- v1.3.18/linux/net/ax25/Makefile	Wed Aug  9 14:55:43 1995
+++ linux/net/ax25/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,29 +7,15 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
 
-
-OBJS	:= af_ax25.o
+O_TARGET := ax25.o
+O_OBJS	 := af_ax25.o
 
 ifdef CONFIG_AX25
-
-OBJS	:= $(OBJS) ax25_in.o ax25_out.o ax25_route.o ax25_subr.o ax25_timer.o
-
+OBJS	+= ax25_in.o ax25_out.o ax25_route.o ax25_subr.o ax25_timer.o
 endif
 
-ax25.o:		$(OBJS)
-		$(LD) -r -o ax25.o $(OBJS)
-
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.18/linux/net/ax25/af_ax25.c	Sun Aug 13 14:45:35 1995
+++ linux/net/ax25/af_ax25.c	Tue Aug 15 14:45:20 1995
@@ -2031,12 +2031,24 @@
 	dev_add_pack(&bpq_packet_type);
 	register_netdevice_notifier(&ax25_dev_notifier);
 			  
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_AX25_ROUTE, 10, "ax25_route", ax25_rt_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_AX25, 4, "ax25", ax25_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_AX25_CALLS, 10, "ax25_calls", ax25_cs_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_AX25_ROUTE, 10, "ax25_route",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ax25_rt_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_AX25, 4, "ax25",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ax25_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_AX25_CALLS, 10, "ax25_calls",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ax25_cs_get_info
+	});
 
 	printk("GW4PTS/G4KLX AX.25 for Linux. Version 0.30 ALPHA for Linux NET3.030 (Linux 1.3.0)\n");
 }
diff -u --recursive --new-file v1.3.18/linux/net/core/Makefile linux/net/core/Makefile
--- v1.3.18/linux/net/core/Makefile	Wed Aug  9 14:55:44 1995
+++ linux/net/core/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,32 +7,13 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-
-OBJS	:= sock.o dev.o dev_mcast.o skbuff.o datagram.o iovec.o
+O_TARGET := core.o
 
 ifdef CONFIG_NET
-
-core.o:		$(OBJS)
-		$(LD) -r -o core.o $(OBJS)
-
-else
-
-core.o:
-		$(AR) rcs core.o
-
+O_OBJS	 := sock.o dev.o dev_mcast.o skbuff.o datagram.o iovec.o
 endif
 
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.18/linux/net/core/dev.c	Sun Aug 13 14:45:36 1995
+++ linux/net/core/dev.c	Tue Aug 15 14:45:20 1995
@@ -70,6 +70,7 @@
 #include <net/sock.h>
 #include <net/arp.h>
 #include <linux/proc_fs.h>
+#include <linux/stat.h>
 
 /*
  *	The list of packet types we will receive (as opposed to discard)
@@ -1320,8 +1321,12 @@
 			dev2 = dev;
 		}
 	}
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_DEV, 3, "dev", dev_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_DEV, 3, "dev",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		dev_get_info
+	});
 
 }
 
diff -u --recursive --new-file v1.3.18/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v1.3.18/linux/net/core/skbuff.c	Fri Jul  7 13:42:58 1995
+++ linux/net/core/skbuff.c	Mon Aug 14 15:49:05 1995
@@ -379,14 +379,14 @@
 	return skb->data;
 }
 
-int skb_pull(struct sk_buff *skb, int len)
+unsigned char * skb_pull(struct sk_buff *skb, int len)
 {
 	IS_SKB(skb);
 	if(len>skb->len)
-		len=skb->len;
+		return 0;
 	skb->data+=len;
 	skb->len-=len;
-	return len;
+	return skb->data;
 }
 
 int skb_headroom(struct sk_buff *skb)
diff -u --recursive --new-file v1.3.18/linux/net/ethernet/Makefile linux/net/ethernet/Makefile
--- v1.3.18/linux/net/ethernet/Makefile	Wed Aug  9 14:55:44 1995
+++ linux/net/ethernet/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,46 +7,23 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
+O_TARGET := ethernet.o
 
 OBJS	:= eth.o 
 
 ifdef CONFIG_IPX
-
 OBJ2	:= pe2.o
-
 endif
 
 ifdef CONFIG_ATALK
-
 OBJ2	:= pe2.o
-
 endif
 
-OBJS	:= $(OBJS) $(OBJ2)
-
 ifdef CONFIG_NET
-
-ethernet.o:	$(OBJS)
-		$(LD) -r -o ethernet.o $(OBJS)
-
-else
-
-ethernet.o:
-		$(AR) rcs ethernet.o
-
+O_OBJS	:= $(OBJS) $(OBJ2)
 endif
 
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
-		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
+	tar -cvf /dev/f1 .
diff -u --recursive --new-file v1.3.18/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v1.3.18/linux/net/ethernet/eth.c	Tue Jul 18 16:28:59 1995
+++ linux/net/ethernet/eth.c	Mon Aug 14 12:24:22 1995
@@ -239,23 +239,27 @@
 {
 	struct ethhdr *eth;
 	struct iphdr *iph;
+	int ip_length;
 
 	IS_SKB(dest);
 	eth=(struct ethhdr *)dest->data;
-	memcpy(dest->data,src,34);	/* ethernet is always >= 60 */
-	length-=34;
 	if(eth->h_proto!=htons(ETH_P_IP))
 	{
-		memcpy(dest->data+34,src+34,length);
+		memcpy(dest->data,src,length);
 		return;
 	}
 	/*
 	 * We have to watch for padded packets. The csum doesn't include the
 	 * padding, and there is no point in copying the padding anyway.
+	 * We have to use the smaller of length and ip_length because it
+	 * can happen that ip_length > length.
 	 */
+	memcpy(dest->data,src,34);	/* ethernet is always >= 34 */
+	length -= 34;
 	iph=(struct iphdr*)(src+14);	/* 14 = Rx_addr+Tx_addr+type_field */
-	if (ntohs(iph->tot_len)-sizeof(struct iphdr) <= length)
-		length=ntohs(iph->tot_len)-sizeof(struct iphdr);
+	ip_length = ntohs(iph->tot_len) - sizeof(struct iphdr);
+	if (ip_length <= length)
+		length=ip_length;
 
 	dest->csum=csum_partial_copy(src+34,dest->data+34,length,base);
 	dest->ip_summed=1;
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v1.3.18/linux/net/ipv4/Makefile	Wed Aug  9 14:55:44 1995
+++ linux/net/ipv4/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,58 +7,23 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
+O_TARGET := ipv4.o
 IPV4_OBJS	:= utils.o route.o proc.o timer.o protocol.o packet.o \
 		   arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o \
 		   igmp.o ip_fw.o ipip.o
 
-MODULES	:=
-
 ifdef CONFIG_INET_RARP
 IPV4_OBJS := $(IPV4_OBJS) rarp.o
 else
-MODULES := $(MODULES) rarp.o
+M_OBJS := rarp.o
+MOD_LIST_NAME := IPV4_MODULES
 endif
 
 ifdef CONFIG_INET
-
-ipv4.o:		$(IPV4_OBJS)
-		$(LD) -r -o ipv4.o $(IPV4_OBJS)
-
-else
-
-ipv4.o:
-		$(AR) rcs ipv4.o
-
+O_OBJS := $(IPV4_OBJS)
 endif
 
-ifdef MODULES
-dep:
-		$(CPP) -M $(IPV4_OBJS:.o=.c) > .depend
-		$(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
-else
-dep:
-		$(CPP) -M $(IPV4_OBJS:.o=.c) > .depend
-endif
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-ifdef MODULES
-
-modules: $(MODULES)
-	echo $(MODULES) > ../../modules/IPV4_MODULES
-	cd ../../modules; \
-		for i in $(MODULES); do ln -sf ../net/ipv4/$$i .; done
-
-else
-
-modules:
-
-endif
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.18/linux/net/ipv4/af_inet.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/af_inet.c	Tue Aug 15 14:45:20 1995
@@ -66,6 +66,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
+#include <linux/stat.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -1607,20 +1608,48 @@
 #endif
 
 #ifdef CONFIG_INET_RARP
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_RARP, 4, "rarp", rarp_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_RARP, 4, "rarp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		rarp_get_info
+	});
 	rarp_ioctl_hook = rarp_ioctl;
 #endif
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_RAW, 3, "raw", raw_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_SNMP, 4, "snmp", snmp_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_SOCKSTAT, 8, "sockstat", afinet_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_TCP, 3, "tcp", tcp_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_UDP, 3, "udp", udp_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_ROUTE, 5, "route", rt_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_RAW, 3, "raw",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		raw_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_SNMP, 4, "snmp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		snmp_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_SOCKSTAT, 8, "sockstat",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		afinet_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_TCP, 3, "tcp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		tcp_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_UDP, 3, "udp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		udp_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_ROUTE, 5, "route",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		rt_get_info
+	});
 }
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.18/linux/net/ipv4/arp.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/arp.c	Tue Aug 15 14:45:20 1995
@@ -87,6 +87,7 @@
 #endif
 #endif
 #include <linux/proc_fs.h>
+#include <linux/stat.h>
 
 
 /*
@@ -687,9 +688,10 @@
 	memcpy(&tip,arp_ptr,4);
   
 /* 
- *	Check for bad requests for 127.0.0.1.  If this is one such, delete it.
+ *	Check for bad requests for 127.x.x.x and requests for multicast
+ *	addresses.  If this is one such, delete it.
  */
-	if(tip == INADDR_LOOPBACK)
+	if (IN_LOOPBACK(tip) || IN_MULTICAST(tip))
 	{
 		kfree_skb(skb, FREE_READ);
 		return 0;
@@ -1460,7 +1462,11 @@
 	/* Register for device down reports */
 	register_netdevice_notifier(&arp_dev_notifier);
 
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_ARP,	3, "arp", arp_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_ARP, 3, "arp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		arp_get_info
+	});
 }
 
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.18/linux/net/ipv4/ip.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/ip.c	Tue Aug 15 14:45:20 1995
@@ -2820,8 +2820,12 @@
 	ip_udp_init();*/
 
 #ifdef CONFIG_IP_MULTICAST
-	proc_net_register(&(struct proc_dir_entry)
-		  { PROC_NET_IGMP, 4, "igmp", ip_mc_procinfo });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IGMP, 4, "igmp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_mc_procinfo
+	});
 #endif
 }
 
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.18/linux/net/ipv4/ip_fw.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/ip_fw.c	Tue Aug 15 14:45:20 1995
@@ -1550,17 +1550,33 @@
 void ip_fw_init(void)
 {
 #ifdef CONFIG_IP_ACCT
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPACCT, 7, "ip_acct", ip_acct_procinfo });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPACCT, 7, "ip_acct",
+		S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_acct_procinfo
+	});
 #endif
 #ifdef CONFIG_IP_FIREWALL
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPFWBLK, 8, "ip_block", ip_fw_blk_procinfo });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPFWFWD, 10, "ip_forward", ip_fw_fwd_procinfo });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPFWBLK, 8, "ip_block",
+		S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_fw_blk_procinfo
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPFWFWD, 10, "ip_forward",
+		S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_fw_fwd_procinfo
+	});
 #endif
 #ifdef CONFIG_IP_MASQUERADE
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPMSQHST, 13, "ip_masquerade", ip_msqhst_procinfo });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPMSQHST, 13, "ip_masquerade",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_msqhst_procinfo
+	});
 #endif
 }
diff -u --recursive --new-file v1.3.18/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v1.3.18/linux/net/ipv4/rarp.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/rarp.c	Tue Aug 15 14:45:20 1995
@@ -199,8 +199,8 @@
 /*
  *	We shouldn't use this type conversion. Check later.
  */
-	struct arphdr *rarp = (struct arphdr *)skb_pull(skb,sizeof(struct arphdr));
-	unsigned char *rarp_ptr = skb->data;
+	struct arphdr *rarp = (struct arphdr *) skb->data;
+	unsigned char *rarp_ptr = skb_pull(skb,sizeof(struct arphdr));
 	struct rarp_table *entry;
 	long sip,tip;
 	unsigned char *sha,*tha;            /* s for "source", t for "target" */
@@ -545,8 +545,12 @@
 void
 rarp_init(void)
 {
-	proc_net_register(&(struct proc_dir_entry)
-		  { PROC_NET_RARP, 4, "rarp", rarp_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_RARP, 4, "rarp",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		rarp_get_info
+	});
 	rarp_ioctl_hook = rarp_ioctl;
 }
 
diff -u --recursive --new-file v1.3.18/linux/net/ipx/Makefile linux/net/ipx/Makefile
--- v1.3.18/linux/net/ipx/Makefile	Wed Aug  9 14:55:45 1995
+++ linux/net/ipx/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,24 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
+O_TARGET := ipx.o
+O_OBJS   := af_ipx.o
 
-
-OBJS	:= af_ipx.o
-
-
-ipx.o:		$(OBJS)
-		$(LD) -r -o ipx.o $(OBJS)
-
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v1.3.18/linux/net/ipx/af_ipx.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipx/af_ipx.c	Tue Aug 15 14:45:20 1995
@@ -1969,12 +1969,24 @@
 	
 	register_netdevice_notifier(&ipx_dev_notifier);
 
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPX, 3, "ipx", ipx_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPX_INTERFACE, 13, "ipx_interface", ipx_interface_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_IPX_ROUTE, 9, "ipx_route", ipx_rt_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPX, 3, "ipx",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ipx_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPX_INTERFACE, 13, "ipx_interface",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ipx_interface_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPX_ROUTE, 9, "ipx_route",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ipx_rt_get_info
+	});
 		
 	printk("Swansea University Computer Society IPX 0.31 for NET3.030\n");
 	printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
diff -u --recursive --new-file v1.3.18/linux/net/netrom/Makefile linux/net/netrom/Makefile
--- v1.3.18/linux/net/netrom/Makefile	Wed Aug  9 14:55:45 1995
+++ linux/net/netrom/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,29 +7,14 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-
-
-OBJS	:= af_netrom.o
+O_TARGET := netrom.o
+O_OBJS	 := af_netrom.o
 
 ifdef CONFIG_AX25
-
-OBJS	:= $(OBJS) nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
-
+O_OBJS	+= nr_dev.o nr_in.o nr_out.o nr_route.o nr_subr.o nr_timer.o
 endif
 
-netrom.o:		$(OBJS)
-		$(LD) -r -o netrom.o $(OBJS)
-
-dep:
-		$(CPP) -M *.c > .depend
+include $(TOPDIR)/Rules.make
 
 tar:
 		tar -cvf /dev/f1 .
-
-modules:
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v1.3.18/linux/net/netrom/af_netrom.c	Sun Aug 13 14:45:37 1995
+++ linux/net/netrom/af_netrom.c	Tue Aug 15 14:45:20 1995
@@ -1392,13 +1392,21 @@
 	nr_default.tries      = NR_DEFAULT_N2;
 	nr_default.window     = NR_DEFAULT_WINDOW;
 
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_NR, 2, "nr", nr_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_NR_NEIGH, 8, "nr_neigh", nr_neigh_get_info });
-proc_net_register(&(struct proc_dir_entry)
-	{ PROC_NET_NR_NODES, 8, "nr_nodes", nr_nodes_get_info });
-
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_NR, 2, "nr",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		nr_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_NR_NEIGH, 8, "nr_neigh",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		nr_neigh_get_info
+	});
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_NR_NODES, 8, "nr_nodes",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		nr_nodes_get_info
+	});
 }
 
 #endif
diff -u --recursive --new-file v1.3.18/linux/net/unix/Makefile linux/net/unix/Makefile
--- v1.3.18/linux/net/unix/Makefile	Wed Aug  9 14:55:45 1995
+++ linux/net/unix/Makefile	Tue Aug 15 15:07:03 1995
@@ -7,24 +7,10 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
+O_TARGET := unix.o
+O_OBJS	 := af_unix.o
 
+include $(TOPDIR)/Rules.make
 
-OBJS	:= af_unix.o
-
-
-unix.o:	$(OBJS)
-		$(LD) -r -o unix.o $(OBJS)
-
-dep:
-		$(CPP) -M *.c > .depend
-
-modules:
 tar:
 		tar -cvf /dev/f1 .
-
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.18/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.18/linux/net/unix/af_unix.c	Sun Aug 13 14:45:37 1995
+++ linux/net/unix/af_unix.c	Tue Aug 15 14:45:20 1995
@@ -1016,8 +1016,12 @@
 {
 	printk("NET3: Unix domain sockets 0.07 BETA for Linux NET3.030.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
-	proc_net_register(&(struct proc_dir_entry)
-			  { PROC_NET_UNIX,  4, "unix", unix_get_info });
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_UNIX,  4, "unix",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		unix_get_info
+	});
 }
 /*
  * Local variables:
diff -u --recursive --new-file v1.3.18/linux/scripts/Configure linux/scripts/Configure
--- v1.3.18/linux/scripts/Configure	Thu Jan  1 02:00:00 1970
+++ linux/scripts/Configure	Tue Aug 15 15:07:03 1995
@@ -0,0 +1,147 @@
+#! /bin/sh
+#
+# This script is used to configure the linux kernel.
+#
+# It was inspired by the challenge in the original Configure script
+# to ``do something better'', combined with the actual need to ``do
+# something better'' because the old configure script wasn't flexible
+# enough.
+#
+# Please send comments / questions / bug fixes to raymondc@microsoft.com.
+#
+# Each line in the config file is a command.
+#
+# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
+# with an empty IFS.
+
+#
+# Make sure we're really running bash.
+#
+# I would really have preferred to write this script in a language with
+# better string handling, but alas, bash is the only scripting language
+# that I can be reasonable sure everybody has on their linux machine.
+#
+[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
+
+# Disable filename globbing once and for all.
+# Enable function cacheing.
+set -f -h
+
+#
+# readln reads a line into $ans.
+#
+#	readln prompt default
+#
+function readln () {
+	if [ "$DEFAULT" = "-d" ]; then
+		echo "$1"
+		ans=$2
+	else
+		echo -n "$1"
+		IFS='@' read ans </dev/tty || exit 1
+		[ -z "$ans" ] && ans=$2
+	fi
+}
+
+#
+# comment does some pretty-printing
+#
+#	comment 'xxx'
+# 
+function comment () {
+	echo "*"; echo "* $1" ; echo "*"
+	(echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG
+	(echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H
+}
+
+#
+# bool processes a boolean argument
+#
+#	bool question define default
+#
+function bool () {
+	ans=""
+	def=$(eval echo "\${$2:-$3}")
+	while [ "$ans" != "y" -a "$ans" != "n" ]; do
+		readln "$1 ($2) [$def] " "$def"
+	done
+	if [ "$ans" = "y" ]; then
+		echo "$2=y" >>$CONFIG
+		echo "#define $2 1" >>$CONFIG_H
+	else
+		echo "# $2 is not set" >>$CONFIG
+		echo "#undef  $2" >>$CONFIG_H
+	fi
+	eval "$2=$ans"
+}
+
+#
+# int processes an integer argument
+#
+#	int question define default
+#
+function int () {
+	# Slimier hack to get bash to rescan a line.
+	ans="x"
+	def=$(eval echo "\${$2:-$3}")
+	while [ $[$ans+0] != "$ans" ]; do
+		readln "$1 ($2) [$def] " "$def"
+	done
+	echo "$2=$ans" >>$CONFIG
+	echo "#define $2 ($ans)" >>$CONFIG_H
+	eval "$2=$ans"
+}
+
+CONFIG=.tmpconfig
+CONFIG_H=.tmpconfig.h
+trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
+
+#
+# Make sure we start out with a clean slate.
+#
+echo "#" > $CONFIG
+echo "# Automatically generated make config: don't edit" >> $CONFIG
+echo "#" >> $CONFIG
+
+echo "/*" > $CONFIG_H
+echo " * Automatically generated C config: don't edit" >> $CONFIG_H
+echo " */" >> $CONFIG_H
+
+DEFAULT=""
+if [ "$1" = "-d" ] ; then
+	DEFAULT="-d"
+	shift
+fi
+
+CONFIG_IN=./config.in
+if [ "$1" != "" ] ; then
+	CONFIG_IN=$1
+fi
+
+if [ -f ./.config ] ; then
+	. ./.config
+	sed -e 's/# \(.*\) is not.*/\1=n/' <./.config >/tmp/conf.$$
+	. /tmp/conf.$$
+	rm /tmp/conf.$$
+fi
+. $CONFIG_IN
+
+if [ "$CONFIG_SOUND" = "y" ] ; then
+	$MAKE -C drivers/sound config || exit 1
+fi
+
+rm -f .config.old
+if [ -f .config ]; then
+	mv .config .config.old
+fi
+mv .tmpconfig .config
+mv .tmpconfig.h include/linux/autoconf.h
+
+echo
+echo "The linux kernel is now hopefully configured for your setup."
+echo "Check the top-level Makefile for additional configuration,"
+echo "and do a 'make dep ; make clean' if you want to be sure all"
+echo "the files are correctly re-made"
+echo
+
+exit 0
diff -u --recursive --new-file v1.3.18/linux/scripts/depend.awk linux/scripts/depend.awk
--- v1.3.18/linux/scripts/depend.awk	Thu Jan  1 02:00:00 1970
+++ linux/scripts/depend.awk	Tue Aug 15 19:26:55 1995
@@ -0,0 +1,101 @@
+# This is an awk script which does dependencies. We do NOT want it to
+# recursivly follow #include directives.
+#
+# The HPATH environment variable should be set to indicate where to look
+# for include files.  The -I infront of the path is optional.
+
+#
+# Surely there is a more elegant way to see if a file exists.  Anyone know
+# what it is?
+#
+function fileExists(f,    TMP, dummy, result) {
+	if(result=FILEHASH[f]) {
+		if(result=="Yes") {
+			return "Yes"
+		} else {return ""}
+	}
+	ERRNO=""
+	getline dummy < f
+	if(!length(ERRNO)) {
+		close(f)
+		return FILEHASH[f]="Yes"
+	} else {
+		FILEHASH[f]="No"
+		return ""
+	}
+}
+
+BEGIN{
+	hasdep=0
+	if(!(TOPDIR=ENVIRON["TOPDIR"])) {
+		print "Environment variable TOPDIR is not set"
+		exit 1
+	}
+	split(ENVIRON["HPATH"],parray," ")
+	for(path in parray) {
+	    sub("^-I","",parray[path])
+	    sub("[/ ]*$","",parray[path])
+	}
+}
+
+/^#[ 	]*include[ 	]*[<"][^ 	]*[>"]/{
+	found=0
+	if(LASTFILE!=FILENAME) {
+		if (hasdep) {
+			print cmd
+		}
+		hasdep=0
+		cmd=""
+		LASTFILE=FILENAME
+		depname=FILENAME
+		relpath=FILENAME
+		sub("\\.c",".o: ",depname)
+		sub("\\.S",".o: ",depname)
+		if (depname==FILENAME) {
+			cmd="\n\t@touch "depname
+		}
+		sub("\\.h",".h: ",depname)
+		if(relpath ~ "^\\." ) {
+			sub("[^/]*$","",  relpath)
+			relpath=relpath"/"
+			sub("//","/",  relpath)
+		} else {
+			relpath=""
+		}
+	}
+	fname=$0
+	sub("^#[ 	]*include[ 	]*[<\"]","",fname)
+	sub("[>\"].*","",fname)
+	if(fileExists(relpath""fname)) {
+		found=1
+		if (!hasdep) {
+			printf "%s", depname
+		}
+		hasdep=1
+		printf " \\\n   %s", relpath""fname
+		if(fname ~ "^\\." ) {
+			if(!relpath in ARGV) {
+				ARGV[ARGC]=relpath""fname
+				++ARGC
+			}
+		}
+	} else {
+		for(path in  parray) {
+			if(fileExists(parray[path]"/"fname)) {
+				shortp=parray[path]
+				found=1
+				if (!hasdep) {
+					printf "%s", depname
+				}
+				hasdep=1
+				printf " \\\n   %s", parray[path]"/"fname
+			}
+		}
+	}
+}
+
+END{
+	if (hasdep) {
+		print cmd
+	}
+}
diff -u --recursive --new-file v1.3.18/linux/scripts/hfiles.sh linux/scripts/hfiles.sh
--- v1.3.18/linux/scripts/hfiles.sh	Thu Jan  1 02:00:00 1970
+++ linux/scripts/hfiles.sh	Tue Aug 15 15:07:03 1995
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# This script looks to see if a directory contains .h files
+#
+for dir in $@; do
+	for hfile in $dir/*.h; do
+		if [ -f $hfile ]; then echo $dir; fi
+		break
+	done
+done
+exit 0
diff -u --recursive --new-file v1.3.18/linux/scripts/pathdown.sh linux/scripts/pathdown.sh
--- v1.3.18/linux/scripts/pathdown.sh	Thu Jan  1 02:00:00 1970
+++ linux/scripts/pathdown.sh	Tue Aug 15 15:07:03 1995
@@ -0,0 +1,13 @@
+#!/bin/sh
+UP=
+DN=${PWD:?}
+TP=${TOPDIR:?}
+
+while [ ! $TP/$UP/. -ef $DN ] ;do
+	UP=`basename $PWD`/$UP
+	cd ..
+	if [ "$PWD" = "/" ]; then echo "Lost"; exit 1; fi
+done
+
+echo $UP
+exit 0
