diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Sun Sep 15 19:19:29 2002
+++ b/CREDITS	Sun Sep 15 19:19:29 2002
@@ -743,7 +743,7 @@
 D: Dell PowerEdge server, SCSI layer, misc drivers, and other patches
 S: Dell Computer Corporation
 S: One Dell Way
-S: Round Rock, TX  78681
+S: Round Rock, TX  78682
 S: USA
 
 N: Eddie C. Dost
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Sun Sep 15 19:19:28 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Sun Sep 15 19:19:28 2002
@@ -161,7 +161,7 @@
      </sect1>
 
      <sect1><title>MTRR Handling</title>
-!Earch/i386/kernel/mtrr.c
+!Earch/i386/kernel/cpu/mtrr/main.c
      </sect1>
      <sect1><title>PCI Support Library</title>
 !Edrivers/pci/pci.c
diff -Nru a/Documentation/filesystems/directory-locking b/Documentation/filesystems/directory-locking
--- a/Documentation/filesystems/directory-locking	Sun Sep 15 19:20:05 2002
+++ b/Documentation/filesystems/directory-locking	Sun Sep 15 19:20:05 2002
@@ -80,14 +80,14 @@
 own descendent.  Moreover, there is exactly one cross-directory rename
 (see above).
 
-	Consider the object blocking the cross-directory rename.  One of
-its descendents is locked by cross-directory rename (otherwise we would again
-have an infinite set of of contended objects).  But that means that means
-that cross-directory rename is taking locks out of order.  Due to (2) the
-order hadn't changed since we had acquired filesystem lock.  But locking
-rules for cross-directory rename guarantee that we do not try to acquire
-lock on descendent before the lock on ancestor.  Contradiction.  I.e.
-deadlock is impossible.  Q.E.D.
+	Consider the object blocking the cross-directory rename.  One
+of its descendents is locked by cross-directory rename (otherwise we
+would again have an infinite set of of contended objects).  But that
+means that cross-directory rename is taking locks out of order.  Due
+to (2) the order hadn't changed since we had acquired filesystem lock.
+But locking rules for cross-directory rename guarantee that we do not
+try to acquire lock on descendent before the lock on ancestor.
+Contradiction.  I.e.  deadlock is impossible.  Q.E.D.
 
 
 	These operations are guaranteed to avoid loop creation.  Indeed,
diff -Nru a/Documentation/filesystems/porting b/Documentation/filesystems/porting
--- a/Documentation/filesystems/porting	Sun Sep 15 19:19:29 2002
+++ b/Documentation/filesystems/porting	Sun Sep 15 19:19:29 2002
@@ -69,7 +69,7 @@
 Most likely there is no need to change anything, but if you relied on
 global exclusion between renames for some internal purpose - you need to
 change your internal locking.  Otherwise exclusion warranties remain the
-same (i.e. parents are victim are locked, etc.).
+same (i.e. parents and victim are locked, etc.).
 
 ---
 [informational]
diff -Nru a/Documentation/input/ff.txt b/Documentation/input/ff.txt
--- a/Documentation/input/ff.txt	Sun Sep 15 19:19:56 2002
+++ b/Documentation/input/ff.txt	Sun Sep 15 19:19:56 2002
@@ -1,7 +1,7 @@
 Force feedback for Linux.
 By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
-You can redistribute this file, provided you include shape.fig and
-interactive.fig.
+You may redistribute this file. Please remember to include shape.fig and
+interactive.fig as well.
 ----------------------------------------------------------------------------
 
 0. Introduction
@@ -90,12 +90,14 @@
 - FF_Y		has an Y axis (usually joysticks)
 - FF_WHEEL	has a wheel (usually sterring wheels)
 - FF_CONSTANT	can render constant force effects
-- FF_PERIODIC	can render periodic effects (sine, ramp, square...)
+- FF_PERIODIC	can render periodic effects (sine, triangle, square...)
+- FF_RAMP       can render ramp effects
 - FF_SPRING	can simulate the presence of a spring
 - FF_FRICTION	can simulate friction 
 - FF_DAMPER	can simulate damper effects
 - FF_RUMBLE	rumble effects (normally the only effect supported by rumble
 		pads)
+- FF_INERTIA    can simulate inertia
 
 
 int ioctl(int fd, EVIOCGEFFECTS, int *n);
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sun Sep 15 19:19:29 2002
+++ b/Makefile	Sun Sep 15 19:19:29 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 34
+SUBLEVEL = 35
 EXTRAVERSION =
 
 # *DOCUMENTATION*
@@ -164,6 +164,9 @@
 
 SUBDIRS		:= init kernel mm fs ipc lib drivers sound net security
 
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
 
 noconfig_targets := xconfig menuconfig config oldconfig randconfig \
 		    defconfig allyesconfig allnoconfig allmodconfig \
@@ -271,7 +274,7 @@
 
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
-quiet_cmd_link_vmlinux = LD     $@
+quiet_cmd_link_vmlinux = LD      $@
 cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
 		--start-group \
 		$(CORE_FILES) \
@@ -318,8 +321,12 @@
 #	This can be used by arch/$ARCH/Makefile to preprocess
 #	their vmlinux.lds.S file
 
-arch/$(ARCH)/vmlinux.lds.s: arch/$(ARCH)/vmlinux.lds.S
-	$(CPP) $(CPPFLAGS) $(CPPFLAGS_$@) -P -C -U$(ARCH) $< -o $@
+AFLAGS_vmlinux.lds.o += -P -C -U$(ARCH)
+
+arch/$(ARCH)/vmlinux.lds.s: arch/$(ARCH)/vmlinux.lds.S FORCE
+	$(call if_changed_dep,as_s_S)
+
+targets += arch/$(ARCH)/vmlinux.lds.s
 
 # Single targets
 # ---------------------------------------------------------------------------
@@ -782,12 +789,33 @@
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
 
+a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
+	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+
+quiet_cmd_as_s_S = CPP     $(echo_target)
+cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
+
 # read all saved command lines
 
-cmd_files := $(wildcard .*.cmd)
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
 ifneq ($(cmd_files),)
   include $(cmd_files)
 endif
+
+# execute the command and also postprocess generated .d dependencies
+# file
+
+if_changed_dep = $(if $(strip $? $(filter-out FORCE $(wildcard $^),$^)\
+		          $(filter-out $(cmd_$(1)),$(cmd_$@))\
+			  $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+	@set -e; \
+	$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';) \
+	$(cmd_$(1)); \
+	$(TOPDIR)/scripts/fixdep $(depfile) $@ $(TOPDIR) '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
+	rm -f $(depfile); \
+	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
 
 # Usage: $(call if_changed_rule,foo)
 # will check if $(cmd_foo) changed, or any of the prequisites changed,
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Sun Sep 15 19:19:34 2002
+++ b/Rules.make	Sun Sep 15 19:19:34 2002
@@ -174,7 +174,7 @@
 # files (fix-dep filters them), so touch modversions.h if any of the .ver
 # files changes
 
-quiet_cmd_cc_ver_c = MKVER  include/linux/modules/$(RELDIR)/$*.ver
+quiet_cmd_cc_ver_c = MKVER   include/linux/modules/$(RELDIR)/$*.ver
 cmd_cc_ver_c = $(CPP) $(c_flags) $< | $(GENKSYMS) $(genksyms_smp_prefix) \
 		 -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
 
@@ -271,26 +271,26 @@
 	  -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \
 	  $(export_flags) 
 
-quiet_cmd_cc_s_c = CC     $(echo_target)
+quiet_cmd_cc_s_c = CC      $(echo_target)
 cmd_cc_s_c       = $(CC) $(c_flags) -S -o $@ $< 
 
 %.s: %.c FORCE
 	$(call if_changed_dep,cc_s_c)
 
-quiet_cmd_cc_i_c = CPP    $(echo_target)
+quiet_cmd_cc_i_c = CPP     $(echo_target)
 cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 
 %.i: %.c FORCE
 	$(call if_changed_dep,cc_i_c)
 
-quiet_cmd_cc_o_c = CC     $(echo_target)
+quiet_cmd_cc_o_c = CC      $(echo_target)
 cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
 
 %.o: %.c FORCE
 	$(call if_changed_dep,cc_o_c)
 
-quiet_cmd_cc_lst_c = '  Generating $(echo_target)'
-cmd_cc_lst_c     = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
+quiet_cmd_cc_lst_c = MKLST   $(echo_target)
+cmd_cc_lst_c       = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
 
 %.lst: %.c FORCE
 	$(call if_changed_dep,cc_lst_c)
@@ -306,13 +306,13 @@
 a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
 
-quiet_cmd_as_s_S = CPP    $(echo_target)
+quiet_cmd_as_s_S = CPP     $(echo_target)
 cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
 
 %.s: %.S FORCE
 	$(call if_changed_dep,as_s_S)
 
-quiet_cmd_as_o_S = AS     $(echo_target)
+quiet_cmd_as_o_S = AS      $(echo_target)
 cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
 
 %.o: %.S FORCE
@@ -330,7 +330,7 @@
 # Rule to compile a set of .o files into one .o file
 #
 ifdef O_TARGET
-quiet_cmd_link_o_target = LD     $(echo_target)
+quiet_cmd_link_o_target = LD      $(echo_target)
 # If the list of objects to link is empty, just create an empty O_TARGET
 cmd_link_o_target = $(if $(strip $(obj-y)),\
 		      $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
@@ -346,7 +346,7 @@
 # Rule to compile a set of .o files into one .a file
 #
 ifdef L_TARGET
-quiet_cmd_link_l_target = AR     $(echo_target)
+quiet_cmd_link_l_target = AR      $(echo_target)
 cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
 
 $(L_TARGET): $(obj-y) FORCE
@@ -359,7 +359,7 @@
 # Rule to link composite objects
 #
 
-quiet_cmd_link_multi = LD     $(echo_target)
+quiet_cmd_link_multi = LD      $(echo_target)
 cmd_link_multi = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
 
 # We would rather have a list of rules like
@@ -381,7 +381,7 @@
 host-progs-multi      := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m)))
 host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs))
 
-quiet_cmd_host_cc__c  = HOSTCC $(echo_target)
+quiet_cmd_host_cc__c  = HOSTCC  $(echo_target)
 cmd_host_cc__c        = $(HOSTCC) -Wp,-MD,$(depfile) \
 			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
 			$(HOST_LOADLIBES) -o $@ $<
@@ -389,14 +389,14 @@
 $(host-progs-single): %: %.c FORCE
 	$(call if_changed_dep,host_cc__c)
 
-quiet_cmd_host_cc_o_c = HOSTCC $(echo_target)
+quiet_cmd_host_cc_o_c = HOSTCC  $(echo_target)
 cmd_host_cc_o_c       = $(HOSTCC) -Wp,-MD,$(depfile) \
 			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
 
 $(host-progs-multi-objs): %.o: %.c FORCE
 	$(call if_changed_dep,host_cc_o_c)
 
-quiet_cmd_host_cc__o  = HOSTLD $(echo_target)
+quiet_cmd_host_cc__o  = HOSTLD  $(echo_target)
 cmd_host_cc__o        = $(HOSTCC) $(HOSTLDFLAGS) -o $@ $($@-objs) \
 			$(HOST_LOADLIBES)
 
@@ -411,9 +411,11 @@
 # Shipped files
 # ===========================================================================
 
+quiet_cmd_shipped = SHIPPED $(echo_target)
+cmd_shipped = cat $< > $@
+
 %:: %_shipped
-	@echo '  CP     $(echo_target)'
-	@cp $< $@
+	$(call cmd,shipped)
 
 # Commands useful for building a boot image
 # ===========================================================================
@@ -421,7 +423,7 @@
 #	Use as following:
 #
 #	target: source(s) FORCE
-#		$(if_changed,ld/objcopy)
+#		$(if_changed,ld/objcopy/gzip)
 #
 #	and add target to EXTRA_TARGETS so that we know we have to
 #	read in the saved command line
@@ -429,20 +431,20 @@
 # Linking
 # ---------------------------------------------------------------------------
 
-quiet_cmd_ld = LD     $(echo_target)
+quiet_cmd_ld = LD      $(echo_target)
 cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$@) \
 	       $(filter-out FORCE,$^) -o $@ 
 
 # Objcopy
 # ---------------------------------------------------------------------------
 
-quiet_cmd_objcopy = OBJCPY $(echo_target)
+quiet_cmd_objcopy = OBJCOPY $(echo_target)
 cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
 # Gzip
 # ---------------------------------------------------------------------------
 
-quiet_cmd_gzip = GZIP   $(echo_target)
+quiet_cmd_gzip = GZIP    $(echo_target)
 cmd_gzip = gzip -f -9 < $< > $@
 
 # ===========================================================================
diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile
--- a/arch/alpha/Makefile	Sun Sep 15 19:19:28 2002
+++ b/arch/alpha/Makefile	Sun Sep 15 19:19:28 2002
@@ -128,9 +128,6 @@
 
 vmlinux: arch/alpha/vmlinux.lds.s
 
-arch/$(ARCH)/vmlinux.lds.s: arch/$(ARCH)/vmlinux.lds.S
-	$(CPP) $(CPPFLAGS) $(CPPFLAGS_$@) -D__ASSEMBLY__ -P -C -U$(ARCH) $< -o $@
-
 bootpfile:
 	@$(MAKEBOOT) bootpfile
 
diff -Nru a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c
--- a/arch/alpha/kernel/init_task.c	Sun Sep 15 19:19:29 2002
+++ b/arch/alpha/kernel/init_task.c	Sun Sep 15 19:19:29 2002
@@ -8,7 +8,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 struct task_struct init_task = INIT_TASK(init_task);
 
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Sun Sep 15 19:19:28 2002
+++ b/arch/alpha/kernel/pci.c	Sun Sep 15 19:19:28 2002
@@ -343,7 +343,7 @@
 }
 
 int
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	/* Nothing to do, since we enable all devices at startup.  */
 	return 0;
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c	Sun Sep 15 19:19:45 2002
+++ b/arch/alpha/kernel/signal.c	Sun Sep 15 19:19:45 2002
@@ -592,108 +592,19 @@
 do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
 	  unsigned long r0, unsigned long r19)
 {
+	siginfo_t info;
+	int signr;
 	unsigned long single_stepping = ptrace_cancel_bpt(current);
 
 	if (!oldset)
 		oldset = &current->blocked;
 
-	while (1) {
-		unsigned long signr;
-		struct k_sigaction *ka;
-		siginfo_t info;
-
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
-
-		if (!signr)
-			break;
-
-		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
-			/* Let the debugger run.  */
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current, SIGCHLD);
-			schedule();
-			single_stepping |= ptrace_cancel_bpt(current);
-
-			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-
-			/* The debugger continued.  Ignore SIGSTOP.  */
-			if (signr == SIGSTOP)
-				continue;
-
-			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->parent->pid;
-				info.si_uid = current->parent->uid;
-			}
-
-			/* If the (new) signal is now blocked, requeue it.  */
-			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
-				continue;
-			}
-		}
-
-		ka = &current->sig->action[signr-1];
-		if (ka->sa.sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* Check for SIGCHLD: it's special.  */
-			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
-				/* nothing */;
-			continue;
-		}
-
-		if (ka->sa.sa_handler == SIG_DFL) {
-			int exit_code = signr & 0x7f;
-
-			/* Init gets no signals it doesn't want.  */
-			if (current->pid == 1)
-				continue;
-
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (is_orphaned_pgrp(current->pgrp))
-					continue;
-				/* FALLTHRU */
-
-			case SIGSTOP:
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->parent->sig->action[SIGCHLD-1]
-				      .sa.sa_flags & SA_NOCLDSTOP))
-					notify_parent(current, SIGCHLD);
-				schedule();
-				single_stepping |= ptrace_cancel_bpt(current);
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGABRT: case SIGFPE: case SIGSEGV:
-			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
-				if (do_coredump(signr, regs))
-					exit_code |= 0x80;
-				/* FALLTHRU */
-
-			default:
-				lock_kernel();
-				sig_exit(signr, exit_code, &info);
-				/* NOTREACHED */
-			}
-			continue;
-		}
+	signr = get_signal_to_deliver(&info, regs);
 
+	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
+		struct k_sigaction *ka = &current->sig->action[signr-1];
+
 		if (r0) syscall_restart(r0, r19, regs, ka);
 		handle_signal(signr, ka, &info, oldset, regs, sw);
 		if (single_stepping) 
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Sun Sep 15 19:19:30 2002
+++ b/arch/i386/config.in	Sun Sep 15 19:19:30 2002
@@ -210,6 +210,10 @@
    define_bool CONFIG_X86_PAE y
 fi
 
+if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
+   bool 'Allocate 3rd-level pagetables from highmem' CONFIG_HIGHPTE
+fi
+
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 
diff -Nru a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
--- a/arch/i386/kernel/acpi.c	Sun Sep 15 19:20:23 2002
+++ b/arch/i386/kernel/acpi.c	Sun Sep 15 19:20:23 2002
@@ -166,6 +166,7 @@
 	return 0;
 }
 
+#ifndef CONFIG_ACPI_HT_ONLY
 
 static int __init
 acpi_parse_lapic_nmi (
@@ -185,12 +186,16 @@
 	return 0;
 }
 
+#endif /*CONFIG_ACPI_HT_ONLY*/
+
 #endif /*CONFIG_X86_LOCAL_APIC*/
 
 #ifdef CONFIG_X86_IO_APIC
 
 int acpi_ioapic;
 
+#ifndef CONFIG_ACPI_HT_ONLY
+
 static int __init
 acpi_parse_ioapic (
 	acpi_table_entry_header *header)
@@ -251,6 +256,7 @@
 	return 0;
 }
 
+#endif /*!CONFIG_ACPI_HT_ONLY*/ 
 #endif /*CONFIG_X86_IO_APIC*/
 
 
@@ -361,18 +367,21 @@
 		return result;
 	}
 
+#ifndef CONFIG_ACPI_HT_ONLY
 	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
 	if (result < 0) {
 		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 		/* TBD: Cleanup to allow fallback to MPS */
 		return result;
 	}
+#endif /*!CONFIG_ACPI_HT_ONLY*/
 
 	acpi_lapic = 1;
 
 #endif /*CONFIG_X86_LOCAL_APIC*/
 
 #ifdef CONFIG_X86_IO_APIC
+#ifndef CONFIG_ACPI_HT_ONLY
 
 	/* 
 	 * I/O APIC 
@@ -410,6 +419,7 @@
 
 	acpi_ioapic = 1;
 
+#endif /*!CONFIG_ACPI_HT_ONLY*/
 #endif /*CONFIG_X86_IO_APIC*/
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/kernel/cpu/intel.c	Sun Sep 15 19:19:29 2002
@@ -156,6 +156,7 @@
 	}
 #endif
 
+	get_model_name(c);
 
 	if (c->cpuid_level > 1) {
 		/* supports eax=2  call */
diff -Nru a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
--- a/arch/i386/kernel/cpu/mtrr/cyrix.c	Sun Sep 15 19:19:28 2002
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c	Sun Sep 15 19:19:28 2002
@@ -110,12 +110,54 @@
 	return -ENOSPC;
 }
 
+static u32 cr4 = 0;
+static u32 ccr3;
+
+static void prepare_set(void)
+{
+	u32 cr0;
+
+	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+	if ( cpu_has_pge ) {
+		cr4 = read_cr4();
+		write_cr4(cr4 & (unsigned char) ~(1 << 7));
+	}
+
+	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	    a side-effect  */
+	cr0 = read_cr0() | 0x40000000;
+	wbinvd();
+	write_cr0(cr0);
+	wbinvd();
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	ccr3 = getCx86(CX86_CCR3);
+
+	/* Cyrix ARRs - everything else were excluded at the top */
+	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
+
+}
+
+static void post_set(void)
+{
+	/*  Flush caches and TLBs  */
+	wbinvd();
+
+	/* Cyrix ARRs - everything else was excluded at the top */
+	setCx86(CX86_CCR3, ccr3);
+		
+	/*  Enable caches  */
+	write_cr0(read_cr0() & 0xbfffffff);
+
+	/*  Restore value of CR4  */
+	if ( cpu_has_pge )
+		write_cr4(cr4);
+}
+
 static void cyrix_set_arr(unsigned int reg, unsigned long base,
 			  unsigned long size, mtrr_type type)
 {
 	unsigned char arr, arr_type, arr_size;
-	u32 cr0, ccr3;
-	u32 cr4 = 0;
 
 	arr = CX86_ARR_BASE + (reg << 1) + reg;	/* avoid multiplication by 3 */
 
@@ -158,24 +200,7 @@
 		}
 	}
 
-	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-	if ( cpu_has_pge ) {
-		cr4 = read_cr4();
-		write_cr4(cr4 & (unsigned char) ~(1 << 7));
-	}
-
-	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
-	    a side-effect  */
-	cr0 = read_cr0() | 0x40000000;
-	wbinvd();
-	write_cr0(cr0);
-	wbinvd();
-
-	/* Cyrix ARRs - everything else were excluded at the top */
-	ccr3 = getCx86(CX86_CCR3);
-
-	/* Cyrix ARRs - everything else were excluded at the top */
-	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
+	prepare_set();
 
 	base <<= PAGE_SHIFT;
 	setCx86(arr, ((unsigned char *) &base)[3]);
@@ -183,18 +208,7 @@
 	setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size);
 	setCx86(CX86_RCR_BASE + reg, arr_type);
 
-	/*  Flush caches and TLBs  */
-	wbinvd();
-
-	/* Cyrix ARRs - everything else was excluded at the top */
-	setCx86(CX86_CCR3, ccr3);
-		
-	/*  Enable caches  */
-	write_cr0(read_cr0() & 0xbfffffff);
-
-	/*  Restore value of CR4  */
-	if ( cpu_has_pge )
-		write_cr4(cr4);
+	post_set();
 }
 
 typedef struct {
@@ -210,31 +224,11 @@
 
 unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
 
-static void __init
-cyrix_arr_init_secondary(void)
+static void cyrix_set_all(void)
 {
 	int i;
-	u32 cr0, ccr3, cr4 = 0;
-
-	/* flush cache and enable MAPEN */
-	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-	if ( cpu_has_pge ) {
-		cr4 = read_cr4();
-		write_cr4(cr4 & (unsigned char) ~(1 << 7));
-	}
 
-	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
-	    a side-effect  */
-	cr0 = read_cr0() | 0x40000000;
-	wbinvd();
-	write_cr0(cr0);
-	wbinvd();
-
-	/* Cyrix ARRs - everything else were excluded at the top */
-	ccr3 = getCx86(CX86_CCR3);
-
-	/* Cyrix ARRs - everything else were excluded at the top */
-	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
+	prepare_set();
 
 	/* the CCRs are not contiguous */
 	for (i = 0; i < 4; i++)
@@ -245,18 +239,7 @@
 		cyrix_set_arr(i, arr_state[i].base, 
 			      arr_state[i].size, arr_state[i].type);
 
-	/*  Flush caches and TLBs  */
-	wbinvd();
-
-	/* Cyrix ARRs - everything else was excluded at the top */
-	setCx86(CX86_CCR3, ccr3);
-		
-	/*  Enable caches  */
-	write_cr0(read_cr0() & 0xbfffffff);
-
-	/*  Restore value of CR4  */
-	if ( cpu_has_pge )
-		write_cr4(cr4);
+	post_set();
 }
 
 /*
@@ -361,7 +344,7 @@
 static struct mtrr_ops cyrix_mtrr_ops = {
 	.vendor            = X86_VENDOR_CYRIX,
 	.init              = cyrix_arr_init,
-	.init_secondary    = cyrix_arr_init_secondary,
+	.set_all	   = cyrix_set_all,
 	.set               = cyrix_set_arr,
 	.get               = cyrix_get_arr,
 	.get_free_region   = cyrix_get_free_region,
diff -Nru a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
--- a/arch/i386/kernel/cpu/mtrr/generic.c	Sun Sep 15 19:19:50 2002
+++ b/arch/i386/kernel/cpu/mtrr/generic.c	Sun Sep 15 19:19:50 2002
@@ -1,3 +1,5 @@
+#include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
@@ -6,6 +8,90 @@
 #include <asm/cpufeature.h>
 #include "mtrr.h"
 
+struct mtrr_state {
+	struct mtrr_var_range *var_ranges;
+	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
+	unsigned char enabled;
+	mtrr_type def_type;
+};
+
+static unsigned long smp_changes_mask __initdata = 0;
+struct mtrr_state mtrr_state = {};
+
+
+/*  Get the MSR pair relating to a var range  */
+static void __init
+get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
+{
+	rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+	rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+}
+
+static void __init
+get_fixed_ranges(mtrr_type * frs)
+{
+	unsigned long *p = (unsigned long *) frs;
+	int i;
+
+	rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+
+	for (i = 0; i < 2; i++)
+		rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]);
+	for (i = 0; i < 8; i++)
+		rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
+}
+
+/*  Grab all of the MTRR state for this CPU into *state  */
+void get_mtrr_state(void)
+{
+	unsigned int i;
+	struct mtrr_var_range *vrs;
+	unsigned long lo, dummy;
+
+	if (!mtrr_state.var_ranges) {
+		mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), 
+						GFP_KERNEL);
+		if (!mtrr_state.var_ranges)
+			return;
+	} 
+	vrs = mtrr_state.var_ranges;
+
+	for (i = 0; i < num_var_ranges; i++)
+		get_mtrr_var_range(i, &vrs[i]);
+	get_fixed_ranges(mtrr_state.fixed_ranges);
+
+	rdmsr(MTRRdefType_MSR, lo, dummy);
+	mtrr_state.def_type = (lo & 0xff);
+	mtrr_state.enabled = (lo & 0xc00) >> 10;
+}
+
+/*  Free resources associated with a struct mtrr_state  */
+void __init finalize_mtrr_state(void)
+{
+	if (mtrr_state.var_ranges)
+		kfree(mtrr_state.var_ranges);
+	mtrr_state.var_ranges = NULL;
+}
+
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
+void __init mtrr_state_warn(void)
+{
+	unsigned long mask = smp_changes_mask;
+
+	if (!mask)
+		return;
+	if (mask & MTRR_CHANGE_MASK_FIXED)
+		printk
+		    ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_VARIABLE)
+		printk
+		    ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
+	if (mask & MTRR_CHANGE_MASK_DEFTYPE)
+		printk
+		    ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
+	printk("mtrr: probably your BIOS does not setup all CPUs\n");
+}
+
 
 int generic_get_free_region(unsigned long base, unsigned long size)
 /*  [SUMMARY] Get a free MTRR.
@@ -55,23 +141,106 @@
 	*type = base_lo & 0xff;
 }
 
-void generic_set_mtrr(unsigned int reg, unsigned long base,
-		      unsigned long size, mtrr_type type)
-/*  [SUMMARY] Set variable MTRR register on the local CPU.
-    <reg> The register to set.
-    <base> The base address of the region.
-    <size> The size of the region. If this is 0 the region is disabled.
-    <type> The type of the region.
-    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
-    be done externally.
-    [RETURNS] Nothing.
+static int __init set_fixed_ranges(mtrr_type * frs)
+{
+	unsigned long *p = (unsigned long *) frs;
+	int changed = FALSE;
+	int i;
+	unsigned long lo, hi;
+
+	rdmsr(MTRRfix64K_00000_MSR, lo, hi);
+	if (p[0] != lo || p[1] != hi) {
+		wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
+		changed = TRUE;
+	}
+
+	for (i = 0; i < 2; i++) {
+		rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
+		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
+			wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
+			      p[3 + i * 2]);
+			changed = TRUE;
+		}
+	}
+
+	for (i = 0; i < 8; i++) {
+		rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
+		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
+			wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
+			      p[7 + i * 2]);
+			changed = TRUE;
+		}
+	}
+	return changed;
+}
+
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
+static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
+{
+	unsigned int lo, hi;
+	int changed = FALSE;
+
+	rdmsr(MTRRphysBase_MSR(index), lo, hi);
+	if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
+	    || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
+		wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
+		changed = TRUE;
+	}
+
+	rdmsr(MTRRphysMask_MSR(index), lo, hi);
+
+	if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
+	    || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
+		wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
+		changed = TRUE;
+	}
+	return changed;
+}
+
+static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
+/*  [SUMMARY] Set the MTRR state for this CPU.
+    <state> The MTRR state information to read.
+    <ctxt> Some relevant CPU context.
+    [NOTE] The CPU must already be in a safe state for MTRR changes.
+    [RETURNS] 0 if no changes made, else a mask indication what was changed.
 */
 {
-	u32 cr0, cr4 = 0;
-	u32 deftype_lo, deftype_hi;
-	static spinlock_t set_atomicity_lock = SPIN_LOCK_UNLOCKED;
+	unsigned int i;
+	unsigned long change_mask = 0;
+
+	for (i = 0; i < num_var_ranges; i++)
+		if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
+			change_mask |= MTRR_CHANGE_MASK_VARIABLE;
+
+	if (set_fixed_ranges(mtrr_state.fixed_ranges))
+		change_mask |= MTRR_CHANGE_MASK_FIXED;
+
+	/*  Set_mtrr_restore restores the old value of MTRRdefType,
+	   so to set it we fiddle with the saved value  */
+	if ((deftype_lo & 0xff) != mtrr_state.def_type
+	    || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
+		deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10);
+		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
+	}
+
+	return change_mask;
+}
+
+
+static u32 cr4 = 0;
+static u32 deftype_lo, deftype_hi;
+static spinlock_t set_atomicity_lock = SPIN_LOCK_UNLOCKED;
+
+static void prepare_set(void)
+{
+	u32 cr0;
 
+	/*  Note that this is not ideal, since the cache is only flushed/disabled
+	   for this CPU while the MTRRs are changed, but changing this requires
+	   more invasive changes to the way the kernel boots  */
 	spin_lock(&set_atomicity_lock);
+
 	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
 	if ( cpu_has_pge ) {
 		cr4 = read_cr4();
@@ -90,18 +259,10 @@
 
 	/*  Disable MTRRs, and set the default type to uncached  */
 	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+}
 
-	if (size == 0) {
-		/* The invalid bit is kept in the mask, so we simply clear the
-		   relevant mask register to disable a range. */
-		wrmsr(MTRRphysMask_MSR(reg), 0, 0);
-	} else {
-		wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
-		      (base & size_and_mask) >> (32 - PAGE_SHIFT));
-		wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
-		      (-size & size_and_mask) >> (32 - PAGE_SHIFT));
-	}
-
+static void post_set(void)
+{
 	/*  Flush caches and TLBs  */
 	wbinvd();
 
@@ -117,6 +278,56 @@
 	spin_unlock(&set_atomicity_lock);
 }
 
+static void generic_set_all(void)
+{
+	unsigned long mask, count;
+
+	prepare_set();
+
+	/* Actually set the state */
+	mask = set_mtrr_state(deftype_lo,deftype_hi);
+
+	post_set();
+
+	/*  Use the atomic bitops to update the global mask  */
+	for (count = 0; count < sizeof mask * 8; ++count) {
+		if (mask & 0x01)
+			set_bit(count, &smp_changes_mask);
+		mask >>= 1;
+	}
+	
+}
+
+static void generic_set_mtrr(unsigned int reg, unsigned long base,
+			     unsigned long size, mtrr_type type)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+	prepare_set();
+
+	printk("MTRR: setting reg %x\n",reg);
+
+	if (size == 0) {
+		/* The invalid bit is kept in the mask, so we simply clear the
+		   relevant mask register to disable a range. */
+		wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+	} else {
+		wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
+		      (base & size_and_mask) >> (32 - PAGE_SHIFT));
+		wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
+		      (-size & size_and_mask) >> (32 - PAGE_SHIFT));
+	}
+
+	post_set();
+}
+
 int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
 {
 	unsigned long lbase, last;
@@ -178,7 +389,7 @@
  */
 struct mtrr_ops generic_mtrr_ops = {
 	.use_intel_if      = 1,
-	.init_secondary    = generic_init_secondary,
+	.set_all	   = generic_set_all,
 	.get               = generic_get_mtrr,
 	.get_free_region   = generic_get_free_region,
 	.set               = generic_set_mtrr,
diff -Nru a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
--- a/arch/i386/kernel/cpu/mtrr/main.c	Sun Sep 15 19:19:28 2002
+++ b/arch/i386/kernel/cpu/mtrr/main.c	Sun Sep 15 19:19:28 2002
@@ -163,8 +163,11 @@
 	}
 
 	/*  The master has cleared me to execute  */
-	mtrr_if->set(data->smp_reg, data->smp_base, 
-		     data->smp_size, data->smp_type);
+	if (data->smp_reg != ~0UL) 
+		mtrr_if->set(data->smp_reg, data->smp_base, 
+			     data->smp_size, data->smp_type);
+	else
+		mtrr_if->set_all();
 
 	atomic_dec(&data->count);
 	while(atomic_read(&data->gate)) {
@@ -243,7 +246,15 @@
 	atomic_set(&data.gate,1);
 
 	/* do our MTRR business */
-	mtrr_if->set(reg,base,size,type);
+
+	/* HACK!
+	 * We use this same function to initialize the mtrrs on boot.
+	 * The state of the boot cpu's mtrrs has been saved, and we want
+	 * to replicate across all the APs. 
+	 * If we're doing that @reg is set to something special...
+	 */
+	if (reg != ~0UL) 
+		mtrr_if->set(reg,base,size,type);
 
 	/* wait for the others */
 	while(atomic_read(&data.count)) {
@@ -530,6 +541,20 @@
 	centaur_init_mtrr();
 }
 
+static void init_other_cpus(void)
+{
+	if (use_intel())
+		get_mtrr_state();
+
+	/* bring up the other processors */
+	set_mtrr(~0UL,0,0,0);
+
+	if (use_intel()) {
+		finalize_mtrr_state();
+		mtrr_state_warn();
+	}
+}
+
 /**
  * mtrr_init - initialie mtrrs on the boot CPU
  *
@@ -537,7 +562,7 @@
  * initialized (i.e. before smp_init()).
  * 
  */
-int __init mtrr_init(void)
+static int __init mtrr_init(void)
 {
 	init_ifs();
 
@@ -608,21 +633,15 @@
 			break;
 		}
 	}
+	printk("mtrr: v%s\n",MTRR_VERSION);
+
 	if (mtrr_if) {
 		set_num_var_ranges();
-		if (use_intel()) {
-			/* Only for Intel MTRRs */
-			get_mtrr_state();
-		}
 		init_table();
+		init_other_cpus();
 	}
-#if 0
-	printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
-	       "mtrr: detected mtrr type: %s\n",
-	       MTRR_VERSION, mtrr_if_name[mtrr_if]);
-#endif
 	return mtrr_if ? -ENXIO : 0;
 }
 
-//subsys_initcall(mtrr_init);
+core_initcall(mtrr_init);
 
diff -Nru a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h	Sun Sep 15 19:19:29 2002
@@ -38,9 +38,10 @@
 	u32	vendor;
 	u32	use_intel_if;
 	void	(*init)(void);
-	void	(*init_secondary)(void);
 	void	(*set)(unsigned int reg, unsigned long base,
 		       unsigned long size, mtrr_type type);
+	void	(*set_all)(void);
+
 	void	(*get)(unsigned int reg, unsigned long *base,
 		       unsigned long *size, mtrr_type * type);
 	int	(*get_free_region) (unsigned long base, unsigned long size);
diff -Nru a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
--- a/arch/i386/kernel/cpu/mtrr/state.c	Sun Sep 15 19:19:28 2002
+++ b/arch/i386/kernel/cpu/mtrr/state.c	Sun Sep 15 19:19:28 2002
@@ -1,180 +1,10 @@
 #include <linux/mm.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 #include "mtrr.h"
 
-struct mtrr_state {
-	struct mtrr_var_range *var_ranges;
-	mtrr_type fixed_ranges[NUM_FIXED_RANGES];
-	unsigned char enabled;
-	mtrr_type def_type;
-};
-
-static unsigned long smp_changes_mask __initdata = 0;
-struct mtrr_state mtrr_state = {};
-
-static int __init set_fixed_ranges(mtrr_type * frs)
-{
-	unsigned long *p = (unsigned long *) frs;
-	int changed = FALSE;
-	int i;
-	unsigned long lo, hi;
-
-	rdmsr(MTRRfix64K_00000_MSR, lo, hi);
-	if (p[0] != lo || p[1] != hi) {
-		wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
-		changed = TRUE;
-	}
-
-	for (i = 0; i < 2; i++) {
-		rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
-		if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
-			wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
-			      p[3 + i * 2]);
-			changed = TRUE;
-		}
-	}
-
-	for (i = 0; i < 8; i++) {
-		rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
-		if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
-			wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
-			      p[7 + i * 2]);
-			changed = TRUE;
-		}
-	}
-	return changed;
-}
-
-/*  Set the MSR pair relating to a var range. Returns TRUE if
-    changes are made  */
-static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr)
-{
-	unsigned int lo, hi;
-	int changed = FALSE;
-
-	rdmsr(MTRRphysBase_MSR(index), lo, hi);
-	if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL)
-	    || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) {
-		wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
-		changed = TRUE;
-	}
-
-	rdmsr(MTRRphysMask_MSR(index), lo, hi);
-
-	if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL)
-	    || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) {
-		wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
-		changed = TRUE;
-	}
-	return changed;
-}
-
-static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi)
-/*  [SUMMARY] Set the MTRR state for this CPU.
-    <state> The MTRR state information to read.
-    <ctxt> Some relevant CPU context.
-    [NOTE] The CPU must already be in a safe state for MTRR changes.
-    [RETURNS] 0 if no changes made, else a mask indication what was changed.
-*/
-{
-	unsigned int i;
-	unsigned long change_mask = 0;
-
-	for (i = 0; i < num_var_ranges; i++)
-		if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i]))
-			change_mask |= MTRR_CHANGE_MASK_VARIABLE;
-
-	if (set_fixed_ranges(mtrr_state.fixed_ranges))
-		change_mask |= MTRR_CHANGE_MASK_FIXED;
-
-	/*  Set_mtrr_restore restores the old value of MTRRdefType,
-	   so to set it we fiddle with the saved value  */
-	if ((deftype_lo & 0xff) != mtrr_state.def_type
-	    || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) {
-		deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10);
-		change_mask |= MTRR_CHANGE_MASK_DEFTYPE;
-	}
-
-	return change_mask;
-}
-
-
-/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
-static void __init mtrr_state_warn(void)
-{
-	unsigned long mask = smp_changes_mask;
-	if (!mask)
-		return;
-	if (mask & MTRR_CHANGE_MASK_FIXED)
-		printk
-		    ("mtrr: your CPUs had inconsistent fixed MTRR settings\n");
-	if (mask & MTRR_CHANGE_MASK_VARIABLE)
-		printk
-		    ("mtrr: your CPUs had inconsistent variable MTRR settings\n");
-	if (mask & MTRR_CHANGE_MASK_DEFTYPE)
-		printk
-		    ("mtrr: your CPUs had inconsistent MTRRdefType settings\n");
-	printk("mtrr: probably your BIOS does not setup all CPUs\n");
-}
-
-/*  Free resources associated with a struct mtrr_state  */
-static void __init finalize_mtrr_state(void)
-{
-	if (mtrr_state.var_ranges)
-		kfree(mtrr_state.var_ranges);
-	mtrr_state.var_ranges = NULL;
-}
-
-/*  Get the MSR pair relating to a var range  */
-static void __init
-get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
-{
-	rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi);
-	rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
-}
-
-static void __init
-get_fixed_ranges(mtrr_type * frs)
-{
-	unsigned long *p = (unsigned long *) frs;
-	int i;
-
-	rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
-
-	for (i = 0; i < 2; i++)
-		rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]);
-	for (i = 0; i < 8; i++)
-		rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
-}
-
-/*  Grab all of the MTRR state for this CPU into *state  */
-void get_mtrr_state(void)
-{
-	unsigned int i;
-	struct mtrr_var_range *vrs;
-	unsigned long lo, dummy;
-
-	if (!mtrr_state.var_ranges) {
-		mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), 
-						GFP_KERNEL);
-		if (!mtrr_state.var_ranges)
-			return;
-	} 
-	vrs = mtrr_state.var_ranges;
-
-	for (i = 0; i < num_var_ranges; i++)
-		get_mtrr_var_range(i, &vrs[i]);
-	get_fixed_ranges(mtrr_state.fixed_ranges);
-
-	rdmsr(MTRRdefType_MSR, lo, dummy);
-	mtrr_state.def_type = (lo & 0xff);
-	mtrr_state.enabled = (lo & 0xc00) >> 10;
-}
-
 
 /*  Put the processor into a state where MTRRs can be safely set  */
 void set_mtrr_prepare_save(struct set_mtrr_context *ctxt)
@@ -245,94 +75,4 @@
 	/*  Re-enable interrupts locally (if enabled previously)  */
 	local_irq_restore(ctxt->flags);
 }
-
-void __init generic_init_secondary(void)
-{
-	u32 cr0, cr4 = 0;
-	u32 deftype_lo, deftype_hi;
-	unsigned long mask, count;
-
-	/*  Note that this is not ideal, since the cache is only flushed/disabled
-	   for this CPU while the MTRRs are changed, but changing this requires
-	   more invasive changes to the way the kernel boots  */
-
-	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
-	if ( cpu_has_pge ) {
-		cr4 = read_cr4();
-		write_cr4(cr4 & (unsigned char) ~(1 << 7));
-	}
-
-	/*  Disable and flush caches. Note that wbinvd flushes the TLBs as
-	    a side-effect  */
-	cr0 = read_cr0() | 0x40000000;
-	wbinvd();
-	write_cr0(cr0);
-	wbinvd();
-
-	/*  Save MTRR state */
-	rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
-
-	/*  Disable MTRRs, and set the default type to uncached  */
-	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
-
-	/* Actually set the state */
-	mask = set_mtrr_state(deftype_lo,deftype_hi);
-
-	/*  Flush caches and TLBs  */
-	wbinvd();
-
-	/* Intel (P6) standard MTRRs */
-	wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi);
-		
-	/*  Enable caches  */
-	write_cr0(read_cr0() & 0xbfffffff);
-
-	/*  Restore value of CR4  */
-	if ( cpu_has_pge )
-		write_cr4(cr4);
-
-	/*  Use the atomic bitops to update the global mask  */
-	for (count = 0; count < sizeof mask * 8; ++count) {
-		if (mask & 0x01)
-			set_bit(count, &smp_changes_mask);
-		mask >>= 1;
-	}
-}
-
-/**
- * mtrr_init_secondary - setup AP MTRR state
- * 
- * Yes, this code is exactly the same as the set_mtrr code, except for the 
- * piece in the middle - you set all the ranges at once, instead of one
- * register at a time.
- * Shoot me.
- */
-void __init mtrr_init_secondary_cpu(void)
-{
-	unsigned long flags;
-
-	if (!mtrr_if || !mtrr_if->init_secondary) {
-		/* I see no MTRRs I can support in SMP mode... */
-		printk("mtrr: SMP support incomplete for this vendor\n");
-		return;
-	}
-
-	local_irq_save(flags);
-	mtrr_if->init_secondary();
-	local_irq_restore(flags);
-}
-
-/**
- * mtrr_final_init  - finalize initialization sequence.
- */
-static int __init mtrr_finalize_state(void)
-{
-	if (use_intel()) {
-		finalize_mtrr_state();
-		mtrr_state_warn();
-	}
-	return 0;
-}
-
-arch_initcall(mtrr_finalize_state);
 
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/kernel/entry.S	Sun Sep 15 19:19:29 2002
@@ -759,6 +759,9 @@
 	.long sys_io_getevents
 	.long sys_io_submit
 	.long sys_io_cancel
+	.long sys_ni_syscall	/* 250 */	/* sys_alloc_hugepages */
+	.long sys_ni_syscall			/* sys_free_hugepages */
+	.long sys_exit_group
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Sun Sep 15 19:19:30 2002
+++ b/arch/i386/kernel/io_apic.c	Sun Sep 15 19:19:30 2002
@@ -1490,7 +1490,7 @@
 	end_lapic_irq
 };
 
-static void enable_NMI_through_LVT0 (void * dummy)
+void enable_NMI_through_LVT0 (void * dummy)
 {
 	unsigned int v, ver;
 
diff -Nru a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c
--- a/arch/i386/kernel/numaq.c	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/kernel/numaq.c	Sun Sep 15 19:19:29 2002
@@ -29,8 +29,11 @@
 #include <linux/mmzone.h>
 #include <asm/numaq.h>
 
-u64 nodes_mem_start[MAX_NUMNODES];
-u64 nodes_mem_size[MAX_NUMNODES];
+/* These are needed before the pgdat's are created */
+unsigned long node_start_pfn[MAX_NUMNODES];
+unsigned long node_end_pfn[MAX_NUMNODES];
+
+#define	MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
 
 /*
  * Function: smp_dump_qct()
@@ -46,17 +49,16 @@
 	struct sys_cfg_data *scd =
 		(struct sys_cfg_data *)__va(SYS_CFG_DATA_PRIV_ADDR);
 
-#define	MB_TO_B(addr) ((addr) << 20)
 	numnodes = 0;
 	for(node = 0; node < MAX_NUMNODES; node++) {
 		if(scd->quads_present31_0 & (1 << node)) {
 			numnodes++;
 			eq = &scd->eq[node];
-			/* Convert to bytes */
-			nodes_mem_start[node] = MB_TO_B((u64)eq->hi_shrd_mem_start -
-							(u64)eq->priv_mem_size);
-			nodes_mem_size[node] = MB_TO_B((u64)eq->hi_shrd_mem_size +
-						       (u64)eq->priv_mem_size);
+			/* Convert to pages */
+			node_start_pfn[node] = MB_TO_PAGES(
+				eq->hi_shrd_mem_start - eq->priv_mem_size);
+			node_end_pfn[node] = MB_TO_PAGES(
+				eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
 		}
 	}
 }
@@ -83,7 +85,7 @@
 #define MB_TO_ELEMENT(x) (x >> ELEMENT_REPRESENTS)
 #define PA_TO_MB(pa) (pa >> 20) 	/* assumption: a physical address is in bytes */
 
-int numaqpa_to_nid(u64 pa)
+int pa_to_nid(u64 pa)
 {
 	int nid;
 	
@@ -96,9 +98,9 @@
 	return nid;
 }
 
-int numaqpfn_to_nid(unsigned long pfn)
+int pfn_to_nid(unsigned long pfn)
 {
-	return numaqpa_to_nid(((u64)pfn) << PAGE_SHIFT);
+	return pa_to_nid(((u64)pfn) << PAGE_SHIFT);
 }
 
 /*
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Sun Sep 15 19:19:45 2002
+++ b/arch/i386/kernel/smpboot.c	Sun Sep 15 19:19:45 2002
@@ -45,7 +45,6 @@
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
-#include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/smpboot.h>
@@ -403,12 +402,6 @@
 
 	local_irq_enable();
 
-#ifdef CONFIG_MTRR
-	/*
-	 * Must be done before calibration delay is computed
-	 */
-	mtrr_init_secondary_cpu ();
-#endif
 	/*
 	 * Get our bogomips.
 	 */
@@ -452,6 +445,11 @@
 	while (!test_bit(smp_processor_id(), &smp_commenced_mask))
 		rep_nop();
 	setup_secondary_APIC_clock();
+	if (nmi_watchdog == NMI_IO_APIC) {
+		disable_8259A_irq(0);
+		enable_NMI_through_LVT0(NULL);
+		enable_8259A_irq(0);
+	}
 	enable_APIC_timer();
 	/*
 	 * low-memory mappings have been cleared, flush them from
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Sun Sep 15 19:19:46 2002
+++ b/arch/i386/kernel/time.c	Sun Sep 15 19:19:46 2002
@@ -115,7 +115,7 @@
 	return delay_at_last_interrupt + edx;
 }
 
-#define TICK_SIZE tick
+#define TICK_SIZE (tick_nsec / 1000)
 
 spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 EXPORT_SYMBOL(i8253_lock);
@@ -280,7 +280,7 @@
 			usec += lost * (1000000 / HZ);
 	}
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
+	usec += (xtime.tv_nsec / 1000);
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	while (usec >= 1000000) {
@@ -309,7 +309,8 @@
 		tv->tv_sec--;
 	}
 
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = (tv->tv_usec * 1000);
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
@@ -437,8 +438,8 @@
 	 */
 	if ((time_status & STA_UNSYNC) == 0 &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
+	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
 		if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
@@ -655,7 +656,7 @@
 	extern int x86_udelay_tsc;
 	
 	xtime.tv_sec = get_cmos_time();
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 /*
  * If we have APM enabled or the CPU clock speed is variable
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/kernel/vm86.c	Sun Sep 15 19:19:29 2002
@@ -608,16 +608,17 @@
 
 static inline int task_valid(struct task_struct *tsk)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	int ret = 0;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p)
 		if ((p == tsk) && (p->sig)) {
 			ret = 1;
-			break;
+			goto out;
 		}
-	}
+	while_each_thread(g, p);
+out:
 	read_unlock(&tasklist_lock);
 	return ret;
 }
diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c	Sun Sep 15 19:19:50 2002
+++ b/arch/i386/mm/discontig.c	Sun Sep 15 19:19:50 2002
@@ -34,20 +34,14 @@
 #include <asm/e820.h>
 #include <asm/setup.h>
 
-struct pfns {
-	unsigned long start_pfn;
-	unsigned long max_pfn;
-};
-
-struct plat_pglist_data *plat_node_data[MAX_NUMNODES];
-bootmem_data_t plat_node_bdata;
-struct pfns plat_node_bootpfns[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES];
+bootmem_data_t node0_bdata;
 
 extern unsigned long find_max_low_pfn(void);
 extern void find_max_pfn(void);
 extern void one_highpage_init(struct page *, int, int);
 
-extern u64 nodes_mem_start[], nodes_mem_size[];
+extern unsigned long node_start_pfn[], node_end_pfn[];
 extern struct e820map e820;
 extern char _end;
 extern unsigned long highend_pfn, highstart_pfn;
@@ -60,22 +54,22 @@
  */
 static void __init find_max_pfn_node(int nid)
 {
-	unsigned long node_datasz;
-	unsigned long start, end;
-
-	start = plat_node_bootpfns[nid].start_pfn = PFN_UP(nodes_mem_start[nid]);
-	end = PFN_DOWN(nodes_mem_start[nid]) + PFN_DOWN(nodes_mem_size[nid]);
-
-	if (start >= end) {
+	if (node_start_pfn[nid] >= node_end_pfn[nid])
 		BUG();
-	}
-	if (end > max_pfn) {
-		end = max_pfn;
-	}
-	plat_node_bootpfns[nid].max_pfn = end;
+	if (node_end_pfn[nid] > max_pfn)
+		node_end_pfn[nid] = max_pfn;
+}
 
-	node_datasz = PFN_UP(sizeof(struct plat_pglist_data));
-	PLAT_NODE_DATA(nid) = (struct plat_pglist_data *)(__va(min_low_pfn << PAGE_SHIFT));
+/* 
+ * Allocate memory for the pg_data_t via a crude pre-bootmem method
+ * We ought to relocate these onto their own node later on during boot.
+ */
+static void __init allocate_pgdat(int nid)
+{
+	unsigned long node_datasz;
+
+	node_datasz = PFN_UP(sizeof(struct pglist_data));
+	NODE_DATA(nid) = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
 	min_low_pfn += node_datasz;
 }
 
@@ -147,12 +141,11 @@
 			pages_to_mb(system_max_low_pfn));
 	
 	for (nid = 0; nid < numnodes; nid++)
-	{	
+		allocate_pgdat(nid);
+	for (nid = 0; nid < numnodes; nid++)
 		find_max_pfn_node(nid);
 
-	}
-
-	NODE_DATA(0)->bdata = &plat_node_bdata;
+	NODE_DATA(0)->bdata = &node0_bdata;
 
 	/*
 	 * Initialize the boot-time allocator (with low memory only):
@@ -231,8 +224,8 @@
 		unsigned int max_dma;
 
 		unsigned long low = max_low_pfn;
-		unsigned long high = plat_node_bootpfns[nid].max_pfn;
-		unsigned long start = plat_node_bootpfns[nid].start_pfn;
+		unsigned long start = node_start_pfn[nid];
+		unsigned long high = node_end_pfn[nid];
 		
 		max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
@@ -289,7 +282,7 @@
 	num_physpages = highend_pfn;
 
 	for (nid = 0; nid < numnodes; nid++) {
-		lmax_mapnr = PLAT_NODE_DATA_STARTNR(nid) + PLAT_NODE_DATA_SIZE(nid);
+		lmax_mapnr = node_startnr(nid) + node_size(nid);
 		if (lmax_mapnr > max_mapnr) {
 			max_mapnr = lmax_mapnr;
 		}
diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c
--- a/arch/i386/pci/common.c	Sun Sep 15 19:19:37 2002
+++ b/arch/i386/pci/common.c	Sun Sep 15 19:19:37 2002
@@ -199,11 +199,11 @@
 	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	int err;
 
-	if ((err = pcibios_enable_resources(dev)) < 0)
+	if ((err = pcibios_enable_resources(dev, mask)) < 0)
 		return err;
 
 	return pcibios_enable_irq(dev);
diff -Nru a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
--- a/arch/i386/pci/i386.c	Sun Sep 15 19:19:29 2002
+++ b/arch/i386/pci/i386.c	Sun Sep 15 19:19:29 2002
@@ -243,7 +243,7 @@
 	pcibios_assign_resources();
 }
 
-int pcibios_enable_resources(struct pci_dev *dev)
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -252,6 +252,10 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
diff -Nru a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
--- a/arch/i386/pci/pci.h	Sun Sep 15 19:19:50 2002
+++ b/arch/i386/pci/pci.h	Sun Sep 15 19:19:50 2002
@@ -31,7 +31,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
+int pcibios_enable_resources(struct pci_dev *, int);
 
 /* pci-pc.c */
 
diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
--- a/arch/i386/pci/visws.c	Sun Sep 15 19:20:12 2002
+++ b/arch/i386/pci/visws.c	Sun Sep 15 19:20:12 2002
@@ -131,9 +131,9 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-	return pcibios_enable_resources(dev);
+	return pcibios_enable_resources(dev, mask);
 }
 
 void __init pcibios_penalize_isa_irq(irq)
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Sun Sep 15 19:19:28 2002
+++ b/arch/ia64/Makefile	Sun Sep 15 19:19:28 2002
@@ -96,9 +96,6 @@
 
 vmlinux: arch/$(ARCH)/vmlinux.lds.s
 
-arch/$(ARCH)/vmlinux.lds.s: arch/$(ARCH)/vmlinux.lds.S
-	$(CPP) $(CPPFLAGS) $(CPPFLAGS_$@) -D__ASSEMBLY__ -P -C -U$(ARCH) $< -o $@
-
 compressed: vmlinux
 	$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux-tmp
 	gzip vmlinux-tmp
diff -Nru a/arch/mips64/Makefile b/arch/mips64/Makefile
--- a/arch/mips64/Makefile	Sun Sep 15 19:19:29 2002
+++ b/arch/mips64/Makefile	Sun Sep 15 19:19:29 2002
@@ -149,7 +149,7 @@
 
 vmlinux: arch/mips64/vmlinux.lds.s
 
-CPPFLAGS_arch/mips64/vmlinux.lds.s := -imacros $(srctree)/include/asm-mips64/sn/mapped_kernel.h
+AFLAGS_vmlinux.lds.o := -imacros $(srctree)/include/asm-mips64/sn/mapped_kernel.h
 
 ifdef CONFIG_MAPPED_KERNEL
 vmlinux.64: vmlinux
diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
--- a/arch/ppc/kernel/irq.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc/kernel/irq.c	Sun Sep 15 19:19:29 2002
@@ -29,13 +29,12 @@
  * to reduce code space and undefined function references.
  */
 
-
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Sun Sep 15 19:19:34 2002
+++ b/arch/ppc/kernel/misc.S	Sun Sep 15 19:19:34 2002
@@ -1304,6 +1304,9 @@
 	.long sys_io_getevents
 	.long sys_io_submit	/* 230 */
 	.long sys_io_cancel
+	.long sys_ni_syscall	/* reserved for alloc_hugepages */
+	.long sys_ni_syscall	/* reserved for free_hugepages */
+	.long sys_exit_group
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Sun Sep 15 19:19:39 2002
+++ b/arch/ppc/kernel/pci.c	Sun Sep 15 19:19:39 2002
@@ -638,7 +638,7 @@
 
 
 int
-pcibios_enable_resources(struct pci_dev *dev)
+pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -647,6 +647,10 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+		
 		r = &dev->resource[idx];
 		if (r->flags & IORESOURCE_UNSET) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -1191,7 +1195,7 @@
 	/* XXX FIXME - update OF device tree node interrupt property */
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -1553,6 +1557,7 @@
 			printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
 	}
 	bus.number = busnr;
+	bus.sysdata = hose;
 	bus.ops = hose? hose->ops: &null_pci_ops;
 	return &bus;
 }
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Sun Sep 15 19:19:45 2002
+++ b/arch/ppc/kernel/process.c	Sun Sep 15 19:19:45 2002
@@ -57,7 +57,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /* this is 8kB-aligned so we can get to the thread_info struct
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc/kernel/setup.c	Sun Sep 15 19:20:24 2002
@@ -659,100 +659,3 @@
 	/* this is for modules since _machine can be a define -- Cort */
 	ppc_md.ppc_machine = _machine;
 }
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-#endif
diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
--- a/arch/ppc/kernel/time.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc/kernel/time.c	Sun Sep 15 19:19:29 2002
@@ -193,7 +193,7 @@
 		 */
 		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
 		     xtime.tv_sec - last_rtc_update >= 659 &&
-		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
+		     abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
 		     jiffies - wall_jiffies == 1) {
 		  	if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
 				last_rtc_update = xtime.tv_sec+1;
@@ -228,7 +228,7 @@
 
 	read_lock_irqsave(&xtime_lock, flags);
 	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
+	usec = (xtime.tv_nsec / 1000);
 #ifdef CONFIG_PPC_ISERIES
 	delta = tb_ticks_per_jiffy - ( next_jiffy_update_tb[0] - get_tb64() );
 #else
@@ -285,7 +285,7 @@
 		new_sec--; 
 		new_usec += 1000000;
 	}
-	xtime.tv_usec = new_usec;
+	xtime.tv_nsec = (new_usec * 1000);
 	xtime.tv_sec = new_sec;
 
 	/* In case of a large backwards jump in time with NTP, we want the 
@@ -344,7 +344,7 @@
 		write_lock_irqsave(&xtime_lock, flags);
 		xtime.tv_sec = sec;
 		last_jiffy_stamp(0) = tb_last_stamp = stamp;
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
 		/* No update now, we just read the time from the RTC ! */
 		last_rtc_update = xtime.tv_sec;
 		write_unlock_irqrestore(&xtime_lock, flags);
diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
--- a/arch/ppc/mm/pgtable.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc/mm/pgtable.c	Sun Sep 15 19:19:29 2002
@@ -26,6 +26,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
@@ -202,7 +203,7 @@
 		err = map_page(v+i, p+i, flags);
 	if (err) {
 		if (mem_init_done)
-			vfree((void *)v);
+			vunmap((void *)v);
 		return NULL;
 	}
 
@@ -219,7 +220,7 @@
 	if (v_mapped_by_bats((unsigned long)addr)) return;
 
 	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
-		vfree((void *) (PAGE_MASK & (unsigned long) addr));
+		vunmap((void *) (PAGE_MASK & (unsigned long)addr));
 }
 #endif /* CONFIG_PPC_ISERIES */
 
diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
--- a/arch/ppc/platforms/pmac_time.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc/platforms/pmac_time.c	Sun Sep 15 19:19:29 2002
@@ -228,7 +228,7 @@
 	case PBOOK_WAKE:
 		write_lock_irqsave(&xtime_lock, flags);
 		xtime.tv_sec = pmac_get_rtc_time() + time_diff;
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
 		last_rtc_update = xtime.tv_sec;
 		write_unlock_irqrestore(&xtime_lock, flags);
 		break;
diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc/platforms/prep_pci.c	Sun Sep 15 19:20:24 2002
@@ -27,7 +27,6 @@
 #include <asm/machdep.h>
 #include <asm/open_pic.h>
 
-#define MAX_DEVNR 22
 
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
@@ -616,47 +615,79 @@
 #define ELCRM_INT7_LVL          0x80
 #define ELCRM_INT5_LVL          0x20
 
-#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
-#define DEVNO(dev)  (dev>>3)                                  
+/*
+ * PCI config space access.
+ */
+#define CFGADDR(dev)	((1<<(dev>>3)) | ((dev&7)<<8))
+#define DEVNO(dev)	(dev>>3)
 
-#define cfg_read(val, addr, type, op)	*val = op((type)(addr))
-#define cfg_write(val, addr, type, op)	op((type *)(addr), (val))
+#define MIN_DEVNR	11
+#define MAX_DEVNR	22
 
-#define cfg_read_bad(val, size)		*val = bad_##size;
-#define cfg_write_bad(val, size)
+static int __prep
+prep_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		 int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile unsigned char *cfg_data;
+
+	if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR
+	    || DEVNO(devfn) > MAX_DEVNR)
+		return PCIBIOS_DEVICE_NOT_FOUND;
 
-#define bad_byte	0xff
-#define bad_word	0xffff
-#define bad_dword	0xffffffffU
-
-#define PREP_PCI_OP(rw, size, type, op)					\
-static int __prep							\
-prep_##rw##_config_##size(struct pci_dev *dev, int offset, type val)	\
-{									\
-	if ((dev->bus->number != 0) || (DEVNO(dev->devfn) > MAX_DEVNR))	\
-	{                   						\
-		cfg_##rw##_bad(val, size)				\
-		return PCIBIOS_DEVICE_NOT_FOUND;    			\
-	}								\
-	cfg_##rw(val, CFGPTR(dev->devfn), type, op);			\
-	return PCIBIOS_SUCCESSFUL;					\
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + CFGADDR(devfn) + offset;
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)cfg_data);
+		break;
+	case 2:
+		*val = in_le16((u16 *)cfg_data);
+		break;
+	default:
+		*val = in_le32((u32 *)cfg_data);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
 }
 
-PREP_PCI_OP(read, byte, u8 *, in_8)
-PREP_PCI_OP(read, word, u16 *, in_le16)
-PREP_PCI_OP(read, dword, u32 *, in_le32)
-PREP_PCI_OP(write, byte, u8, out_8)
-PREP_PCI_OP(write, word, u16, out_le16)
-PREP_PCI_OP(write, dword, u32, out_le32)
+static int __prep
+prep_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		  int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile unsigned char *cfg_data;
+
+	if (bus->number != 0 || DEVNO(devfn) < MIN_DEVNR
+	    || DEVNO(devfn) > MAX_DEVNR)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + CFGADDR(devfn) + offset;
+	switch (len) {
+	case 1:
+		out_8((u8 *)cfg_data, val);
+		break;
+	case 2:
+		out_le16((u16 *)cfg_data, val);
+		break;
+	default:
+		out_le32((u32 *)cfg_data, val);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
 
 static struct pci_ops prep_pci_ops =
 {
-	prep_read_config_byte,
-	prep_read_config_word,
-	prep_read_config_dword,
-	prep_write_config_byte,
-	prep_write_config_word,
-	prep_write_config_dword
+	prep_read_config,
+	prep_write_config
 };
 
 #define MOTOROLA_CPUTYPE_REG	0x800
@@ -1239,10 +1270,12 @@
 	hose->last_busno = 0xff;
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
 	hose->io_base_phys = PREP_ISA_IO_BASE;
-	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
-	prep_init_resource(&hose->io_resource, 0, 0x00ffffff, IORESOURCE_IO);
+	hose->io_base_virt = ioremap(PREP_ISA_IO_BASE, 0x800000);
+	prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO);
 	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
 			   IORESOURCE_MEM);
+	/* XXX why can't we use the indirect config space access method? */
+	hose->cfg_data = ioremap(PREP_ISA_IO_BASE + 0x800000, 0x800000);
 	hose->ops = &prep_pci_ops;
 
 	printk("PReP architecture\n");
diff -Nru a/arch/ppc64/config.in b/arch/ppc64/config.in
--- a/arch/ppc64/config.in	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/config.in	Sun Sep 15 19:19:29 2002
@@ -65,12 +65,12 @@
 
 if [ "$CONFIG_HOTPLUG" = "y" ]; then
    source drivers/pcmcia/Config.in
+   source drivers/hotplug/Config.in
 else
    define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_HOTPLUG_PCI n
 fi
 
-source drivers/parport/Config.in
-
 if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
    bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
 
@@ -83,9 +83,9 @@
 endmenu
 
 source drivers/mtd/Config.in
+source drivers/parport/Config.in
 source drivers/pnp/Config.in
 source drivers/block/Config.in
-source drivers/md/Config.in
 
 mainmenu_option next_comment
 comment 'ATA/ATAPI/MFM/RLL support'
@@ -100,13 +100,15 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'SCSI support'
-tristate 'SCSI support' CONFIG_SCSI
+comment 'SCSI device support'
+tristate 'SCSI device support' CONFIG_SCSI
 if [ "$CONFIG_SCSI" != "n" ]; then
    source drivers/scsi/Config.in
 fi
 endmenu
 
+source drivers/md/Config.in
+
 source drivers/message/fusion/Config.in
 
 source drivers/ieee1394/Config.in
@@ -135,67 +137,26 @@
 
 source drivers/isdn/Config.in
 
-mainmenu_option next_comment
-comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-
-bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-   source drivers/cdrom/Config.in
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'Console drivers'
-source drivers/video/Config.in
-endmenu
+source drivers/telephony/Config.in
 
+#
+# input before char - char/joystick depends on it. As does USB.
+#
 source drivers/input/Config.in
 
-if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
-mainmenu_option next_comment
-comment 'iSeries device drivers'
-   dep_tristate 'iSeries Virtual Console Support' CONFIG_VIOCONS $CONFIG_PPC_ISERIES
-   dep_tristate 'iSeries Virtual I/O disk support' CONFIG_VIODASD $CONFIG_PPC_ISERIES
-   if [ "$CONFIG_VIODASD" = "y" -o "$CONFIG_VIODASD" = "m" ]; then
-      bool 'iSeries Virtual disk IDE emulation' CONFIG_VIODASD_IDE
-   fi
-   dep_tristate 'iSeries Virtual I/O CD support' CONFIG_VIOCD $CONFIG_PPC_ISERIES
-   if [ "$CONFIG_VIOCD" = "y" -o "$CONFIG_VIOCD" = "m" ]; then
-      bool 'iSeries Virtual CD Aztech emulation' CONFIG_VIOCD_AZTECH
-   fi
-   dep_tristate 'iSeries Virtual Tape Support' CONFIG_VIOTAPE  $CONFIG_PPC_ISERIES
-   dep_tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH $CONFIG_PPC_ISERIES
-endmenu
-fi
-
-if [ "$CONFIG_VIOCONS" = "n" ]; then
-   if [ "$CONFIG_VIODASD" = "n" ]; then
-      if [ "$CONFIG_VIOTAPE" = "n" ]; then
-         if [ "$CONFIG_VIOCD" = "n" ]; then
-		    define_bool CONFIG_VIOPATH n
-		 else
-		    define_bool CONFIG_VIOPATH y
-         fi
-	  else
-	     define_bool CONFIG_VIOPATH y
-      fi
-   else
-      define_bool CONFIG_VIOPATH y
-   fi
-else
-   define_bool CONFIG_VIOPATH y
-fi
-
-if [ "$CONFIG_VIOCD" = "y" ]; then
-   define_bool CONFIG_CD_NO_IDESCSI y
-fi
-
 source drivers/char/Config.in
 
 source drivers/media/Config.in
 
 source fs/Config.in
 
+if [ "$CONFIG_VT" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Console drivers'
+   source drivers/video/Config.in
+   endmenu
+fi
+
 mainmenu_option next_comment
 comment 'Sound'
 tristate 'Sound card support' CONFIG_SOUND
@@ -208,6 +169,25 @@
 source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
+
+if [ "$CONFIG_PPC_ISERIES" = "y" ]; then
+mainmenu_option next_comment
+comment 'iSeries device drivers'
+   tristate 'iSeries Virtual Console Support' CONFIG_VIOCONS
+   tristate 'iSeries Virtual I/O disk support' CONFIG_VIODASD
+   if [ "$CONFIG_VIODASD" = "y" -o "$CONFIG_VIODASD" = "m" ]; then
+      bool 'iSeries Virtual disk IDE emulation' CONFIG_VIODASD_IDE
+   fi
+   tristate 'iSeries Virtual I/O CD support' CONFIG_VIOCD
+   if [ "$CONFIG_VIOCD" = "y" -o "$CONFIG_VIOCD" = "m" ]; then
+      bool 'iSeries Virtual CD Aztech emulation' CONFIG_VIOCD_AZTECH
+   fi
+   tristate 'iSeries Virtual Tape Support' CONFIG_VIOTAPE
+   tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH
+endmenu
+
+   define_bool CONFIG_VIOPATH y
+fi
 
 mainmenu_option next_comment
 comment 'Kernel hacking'
diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/defconfig	Sun Sep 15 19:19:29 2002
@@ -56,11 +56,7 @@
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
+# CONFIG_HOTPLUG_PCI is not set
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 
@@ -70,6 +66,11 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
@@ -94,74 +95,13 @@
 CONFIG_BLK_DEV_INITRD=y
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-CONFIG_NET_IPIP=y
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-CONFIG_SYN_COOKIES=y
-CONFIG_IPV6=m
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
 
@@ -230,8 +170,18 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_MESH is not set
-# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Fusion MPT device support
@@ -258,6 +208,47 @@
 # CONFIG_I2O_PROC is not set
 
 #
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_IPV6=m
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -303,8 +294,8 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_E100 is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -316,7 +307,7 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -331,7 +322,8 @@
 CONFIG_ACENIC=y
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -352,11 +344,7 @@
 #
 # Token Ring devices
 #
-CONFIG_TR=y
-CONFIG_IBMOL=y
-# CONFIG_IBMLS is not set
-# CONFIG_3C359 is not set
-# CONFIG_TMS380TR is not set
+# CONFIG_TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
@@ -387,77 +375,28 @@
 # CONFIG_ISDN_BOOL is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Console drivers
+# Telephony Support
 #
-
-#
-# Frame-buffer support
-#
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
-# CONFIG_FB_CT65550 is not set
-# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-# CONFIG_FB_RIVA is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_G450 is not set
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-# CONFIG_FB_ATY is not set
-# CONFIG_FB_RADEON is not set
-# CONFIG_FB_ATY128 is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-# CONFIG_FB_3DFX is not set
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-CONFIG_FBCON_ACCEL=y
-CONFIG_FBCON_FONTWIDTH8_ONLY=y
-CONFIG_FBCON_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
 
 #
 # Userland interfaces
 #
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
 # CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
-# CONFIG_INPUT_UINPUT is not set
 
 #
 # Input I/O drivers
@@ -470,8 +409,11 @@
 # CONFIG_GAMEPORT_VORTEX is not set
 # CONFIG_GAMEPORT_FM801 is not set
 # CONFIG_GAMEPORT_CS461x is not set
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_I8042_REG_BASE=60
+CONFIG_I8042_KBD_IRQ=1
+CONFIG_I8042_AUX_IRQ=12
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
 # CONFIG_SERIO_PARKBD is not set
@@ -479,13 +421,52 @@
 #
 # Input Device Drivers
 #
-CONFIG_VIOPATH=y
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+# CONFIG_INPUT_JOYDUMP is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=y
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -519,7 +500,6 @@
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-CONFIG_PSMOUSE=y
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -528,6 +508,7 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -678,6 +659,57 @@
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+CONFIG_FBCON_ACCEL=y
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
 
 #
 # Sound
diff -Nru a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c
--- a/arch/ppc64/kernel/align.c	Sun Sep 15 19:19:42 2002
+++ b/arch/ppc64/kernel/align.c	Sun Sep 15 19:19:42 2002
@@ -16,7 +16,6 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/chrp_setup.c	Sun Sep 15 19:19:29 2002
@@ -23,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
@@ -56,7 +55,6 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
-#include <asm/keyboard.h>
 #include <asm/naca.h>
 #include <asm/time.h>
 
@@ -72,14 +70,6 @@
 void chrp_progress(char *, unsigned short);
 void chrp_request_regions(void);
 
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
 extern void openpic_init_IRQ(void);
 extern void init_ras_IRQ(void);
 
@@ -90,7 +80,7 @@
 extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
 extern int  pSeries_set_rtc_time(struct rtc_time *rtc_time);
 void pSeries_calibrate_decr(void);
-static void fwnmi_init(void);
+void fwnmi_init(void);
 extern void SystemReset_FWNMI(void), MachineCheck_FWNMI(void);	/* from head.S */
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
@@ -194,7 +184,7 @@
  * the firmware supports this feature.
  *
  */
-static void __init fwnmi_init(void)
+void __init fwnmi_init(void)
 {
 	long ret;
 	int ibm_nmi_register = rtas_token("ibm,nmi-register");
@@ -283,19 +273,6 @@
 
 	ppc_md.progress = chrp_progress;
 
-#ifdef CONFIG_VT
-	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
-	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
-	ppc_md.kbd_translate     = pckbd_translate;
-	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
-	SYSRQ_KEY = 0x63;	/* Print Screen */
-#endif
-#endif
-	
 	ppc_md.progress("Linux ppc64\n", 0x0);
 }
 
diff -Nru a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c
--- a/arch/ppc64/kernel/eeh.c	Sun Sep 15 19:19:58 2002
+++ b/arch/ppc64/kernel/eeh.c	Sun Sep 15 19:19:58 2002
@@ -94,16 +94,13 @@
 
 		dev = pci_find_slot(bus, devfn);
 		if (dev) {
-			udbg_printf("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			printk("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
+			printk(KERN_ERR "EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
 			      rets[0], dev->slot_name, dev->name);
 			PPCDBG_ENTER_DEBUGGER();
 			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
 			      rets[0], dev->slot_name, dev->name);
 		} else {
-			udbg_printf("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			printk("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
+			printk(KERN_ERR "EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
 			PPCDBG_ENTER_DEBUGGER();
 			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
 		}
@@ -112,8 +109,46 @@
 	return val;	/* good case */
 }
 
+struct eeh_early_enable_info {
+	unsigned int buid_hi;
+	unsigned int buid_lo;
+	int adapters_enabled;
+};
+
+/* Enable eeh for the given device node. */
+static void *early_enable_eeh(struct device_node *dn, void *data)
+{
+	struct eeh_early_enable_info *info = data;
+	long ret;
+
+	/* Try to enable eeh */
+	ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+			CONFIG_ADDR(dn->busno, dn->devfn),
+			info->buid_hi, info->buid_lo, EEH_ENABLE);
+	if (ret == 0)
+		info->adapters_enabled++;
+	return NULL; 
+}
+
+/*
+ * Initialize eeh by trying to enable it for all of the adapters in the system.
+ * As a side effect we can determine here if eeh is supported at all.
+ * Note that we leave EEH on so failed config cycles won't cause a machine
+ * check.  If a user turns off EEH for a particular adapter they are really
+ * telling Linux to ignore errors.
+ *
+ * We should probably distinguish between "ignore errors" and "turn EEH off"
+ * but for now disabling EEH for adapters is mostly to work around drivers that
+ * directly access mmio space (without using the macros).
+ *
+ * The eeh-force-off/on option does literally what it says, so if Linux must
+ * avoid enabling EEH this must be done.
+ */
 void eeh_init(void)
 {
+	struct device_node *phb;
+	struct eeh_early_enable_info info;
+
 	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
 	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
 	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
@@ -127,7 +162,7 @@
 	if (eeh_force_off > eeh_force_on) {
 		/* User is forcing EEH off.  Be noisy if it is implemented. */
 		if (eeh_implemented)
-			printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
+			printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
 		eeh_implemented = 0;
 		return;
 	}
@@ -135,8 +170,29 @@
 	if (eeh_force_on > eeh_force_off)
 		eeh_implemented = 1;	/* User is forcing it on. */
 
-	if (eeh_implemented)
-		printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
+	/* Enable EEH for all adapters.  Note that eeh requires buid's */
+	info.adapters_enabled = 0;
+	for (phb = find_devices("pci"); phb; phb = phb->next) {
+		int len;
+		int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
+		if (!buid_vals)
+			continue;
+		if (len == sizeof(int)) {
+			info.buid_lo = buid_vals[0];
+			info.buid_hi = 0;
+		} else if (len == sizeof(int)*2) {
+			info.buid_hi = buid_vals[0];
+			info.buid_lo = buid_vals[1];
+		} else {
+			printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
+			continue;
+		}
+		traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
+	}
+	if (info.adapters_enabled) {
+		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
+		eeh_implemented = 1;
+	}
 }
 
 
@@ -167,7 +223,7 @@
 
 	if (!eeh_check_opts_config(dev, default_state)) {
 		if (default_state)
-			printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
+			printk(KERN_INFO "EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
 		return 0;
 	}
 
@@ -175,7 +231,6 @@
 			CONFIG_ADDR(dn->busno, dn->devfn),
 			BUID_HI(phb->buid), BUID_LO(phb->buid));
 	eeh_capable = (ret == 0 && rets[1] == 1);
-	printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
 	return eeh_capable;
 }
 
@@ -318,7 +373,7 @@
 		if (*cur) {
 			int curlen = curend-cur;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
-				printk("EEH: sorry...too many eeh cmd line options\n");
+				printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
 				return 1;
 			}
 			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S	Sun Sep 15 19:19:28 2002
+++ b/arch/ppc64/kernel/entry.S	Sun Sep 15 19:19:28 2002
@@ -113,10 +113,6 @@
 	clrldi	r4,r4,32
 	clrldi	r5,r5,32
 	clrldi	r6,r6,32
-#if 0 /* XXX Why not ??? - Anton */
-	clrldi	r7,r7,32
-	clrldi	r8,r8,32
-#endif
 	b	17f
 15:
 #endif
@@ -187,10 +183,6 @@
 	clrldi	r4,r4,32
 	clrldi	r5,r5,32
 	clrldi	r6,r6,32
-#if 0 /* XXX Why not ??? - Anton */
-	clrldi	r7,r7,32
-	clrldi	r8,r8,32
-#endif
 	b	57f
 55:
 #endif
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Sun Sep 15 19:19:50 2002
+++ b/arch/ppc64/kernel/head.S	Sun Sep 15 19:19:50 2002
@@ -153,8 +153,9 @@
  */
 
 /*
- * We make as much of the exception code common between native Pseries
- * and Iseries LPAR implementations as possible.
+ * We make as much of the exception code common between native
+ * exception handlers (including pSeries LPAR) and iSeries LPAR
+ * implementations as possible.
  */
 
 /*
@@ -1340,17 +1341,10 @@
 					/* executed here.                 */
 
         LOADADDR(r0, 4f)                /* Jump to the copy of this code  */
-	mtctr	r0			/* that we just made              */
+	mtctr	r0			/* that we just made/relocated    */
 	bctr
 
-4:	LOADADDR(r9,rtas)
-	sub	r9,r9,r26
-	ld	r5,RTASBASE(r9)		/* get the value of rtas->base */
-	ld	r9,RTASSIZE(r9)		/* get the value of rtas->size */
-	bl	.copy_and_flush		/* copy upto rtas->base */
-	add     r6,r6,r9		/* then skip over rtas->size bytes */
-
-	LOADADDR(r5,klimit)
+4:	LOADADDR(r5,klimit)
 	sub	r5,r5,r26
 	ld	r5,0(r5)		/* get the value of klimit */
 	sub	r5,r5,r27
@@ -1571,7 +1565,6 @@
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfid
-#endif /* CONFIG_SMP */
 
 /* 
  * Running with relocation on at this point.  All we want to do is
@@ -1581,6 +1574,7 @@
 	li	r3,0
 	std	r3,0(r1)                /* Zero the stack frame pointer     */
 	bl	.start_secondary
+#endif
 
 /*
  * This subroutine clobbers r11, r12 and the LR
@@ -1674,9 +1668,6 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 	sub	r2,r2,r26
-
-	/* Init naca->debug_switch so it can be used in stab & htab init.  */
-	bl	.ppcdbg_initialize
 
 	/* Get the pointer to the segment table which is used by           */
 	/* stab_initialize                                                 */
diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc64/kernel/iSeries_pci.c	Sun Sep 15 19:20:24 2002
@@ -510,7 +510,7 @@
 /* I/0 Memory copy MUST use mmio commands on iSeries                    */
 /* To do; For performance, include the hv call directly                 */
 /************************************************************************/
-void* iSeries_memset(void* dest, char c, size_t Count)
+void* iSeries_memset_io(void* dest, char c, size_t Count)
 {
 	u8    ByteValue     = c;
 	long  NumberOfBytes = Count;
diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Sun Sep 15 19:20:10 2002
+++ b/arch/ppc64/kernel/iSeries_setup.c	Sun Sep 15 19:20:10 2002
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
@@ -334,17 +332,6 @@
 	ppc_md.calibrate_decr	 	= iSeries_calibrate_decr;
 	ppc_md.progress			= iSeries_progress;
 
-	ppc_md.kbd_setkeycode    	= NULL;
-	ppc_md.kbd_getkeycode    	= NULL;
-	ppc_md.kbd_translate     	= NULL;
-	ppc_md.kbd_unexpected_up 	= NULL;
-	ppc_md.kbd_leds          	= NULL;
-	ppc_md.kbd_init_hw       	= NULL;
-
-#if defined(CONFIG_MAGIC_SYSRQ)
-	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
-#endif
-	
 	hpte_init_iSeries();
 	tce_init_iSeries();
 
diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c	Sun Sep 15 19:20:20 2002
+++ b/arch/ppc64/kernel/idle.c	Sun Sep 15 19:20:20 2002
@@ -16,7 +16,6 @@
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
diff -Nru a/arch/ppc64/kernel/init_task.c b/arch/ppc64/kernel/init_task.c
--- a/arch/ppc64/kernel/init_task.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/init_task.c	Sun Sep 15 19:19:29 2002
@@ -7,7 +7,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc64/kernel/ioctl32.c	Sun Sep 15 19:20:24 2002
@@ -4590,9 +4590,12 @@
 			return -ENOMEM;
 		memset(additional_ioctls, 0, PAGE_SIZE);
 	}
-	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++)
+	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++) {
 		if (!additional_ioctls[i].cmd)
 			break;
+		if (additional_ioctls[i].cmd == cmd)
+			printk("duplicate ioctl found: %x\n", cmd);
+	}
 	if (i == PAGE_SIZE/sizeof(struct ioctl_trans))
 		return -ENOMEM;
 	additional_ioctls[i].cmd = cmd;
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Sun Sep 15 19:19:37 2002
+++ b/arch/ppc64/kernel/irq.c	Sun Sep 15 19:19:37 2002
@@ -23,7 +23,6 @@
  * should be easier.
  */
 
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
@@ -410,11 +409,13 @@
 			= { [ 0 ... NR_IRQS-1 ] = { 0, 0 } };
 
 #define IDLE_ENOUGH(cpu,now) \
-		(idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > ((HZ/100)+1)))
+		(idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
 
 #define IRQ_ALLOWED(cpu,allowed_mask) \
 		((1 << cpu) & (allowed_mask))
 
+#define IRQ_BALANCE_INTERVAL (HZ/50)
+
 static unsigned long move(unsigned long curr_cpu, unsigned long allowed_mask,
 			  unsigned long now, int direction)
 {
@@ -447,8 +448,9 @@
 	irq_balance_t *entry = irq_balance + irq;
 	unsigned long now = jiffies;
 
-	if (unlikely(entry->timestamp != now)) {
+	if (unlikely(time_after(now, entry->timestamp + IRQ_BALANCE_INTERVAL))) {
 		unsigned long allowed_mask;
+		unsigned int new_cpu;
 		unsigned long random_number;
 
 		if (!irq_desc[irq].handler->set_affinity)
@@ -459,8 +461,11 @@
 
 		allowed_mask = cpu_online_map & irq_affinity[irq];
 		entry->timestamp = now;
-		entry->cpu = move(entry->cpu, allowed_mask, now, random_number);
-		irq_desc[irq].handler->set_affinity(irq, 1 << entry->cpu);
+		new_cpu = move(entry->cpu, allowed_mask, now, random_number);
+		if (entry->cpu != new_cpu) {
+			entry->cpu = new_cpu;
+			irq_desc[irq].handler->set_affinity(irq, 1 << new_cpu);
+		}
 	}
 }
 #else
diff -Nru a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c
--- a/arch/ppc64/kernel/lmb.c	Sun Sep 15 19:19:50 2002
+++ b/arch/ppc64/kernel/lmb.c	Sun Sep 15 19:19:50 2002
@@ -12,6 +12,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <asm/types.h>
 #include <asm/page.h>
 #include <asm/prom.h>
@@ -27,7 +28,7 @@
 static long lmb_add_region(struct lmb_region *, unsigned long, unsigned long, unsigned long);
 
 struct lmb lmb = {
-	0,
+	0, 0,
 	{0,0,0,0,{{0,0,0}}},
 	{0,0,0,0,{{0,0,0}}}
 };
@@ -150,6 +151,10 @@
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_rgn = &(_lmb->memory);
 
+	/* On pSeries LPAR systems, the first LMB is our RMO region. */
+	if ( base == 0 )
+		_lmb->rmo_size = size;
+
 	return lmb_add_region(_rgn, base, size, LMB_MEMORY_AREA);
 
 }
@@ -257,12 +262,17 @@
 	return (i < rgn->cnt) ? i : -1;
 }
 
-
 unsigned long
 lmb_alloc(unsigned long size, unsigned long align)
 {
+	return lmb_alloc_base(size, align, LMB_ALLOC_ANYWHERE);
+}
+
+unsigned long
+lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr)
+{
 	long i, j;
-	unsigned long base;
+	unsigned long base = 0;
 	unsigned long offset = reloc_offset();
 	struct lmb *_lmb = PTRRELOC(&lmb);
 	struct lmb_region *_mem = &(_lmb->memory);
@@ -276,7 +286,12 @@
 		if ( lmbtype != LMB_MEMORY_AREA )
 			continue;
 
+		if ( max_addr == LMB_ALLOC_ANYWHERE )
 		base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+		else if ( lmbbase < max_addr )
+			base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align);
+		else
+			continue;
 
 		while ( (lmbbase <= base) &&
 			((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) {
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Sun Sep 15 19:19:30 2002
+++ b/arch/ppc64/kernel/misc.S	Sun Sep 15 19:19:30 2002
@@ -504,9 +504,9 @@
 /* Why isn't this a) automatic, b) written in 'C'? */	
 	.balign 8
 _GLOBAL(sys_call_table32)
-	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
-	.llong .sys32_exit
-	.llong .sys32_fork
+	.llong .sys_ni_syscall		/* 0 - old setup syscall */
+	.llong .sys_exit
+	.llong .sys_fork
 	.llong .sys_read
 	.llong .sys_write
 	.llong .sys32_open		/* 5 */
@@ -521,8 +521,8 @@
 	.llong .sys_mknod
 	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
-	.llong .sys_ni_syscall			/* old break syscall holder */
-	.llong .sys32_stat
+	.llong .sys_ni_syscall		/* old break syscall */
+	.llong .sys_ni_syscall		/* old stat syscall */
 	.llong .sys32_lseek
 	.llong .sys_getpid              /* 20 */
 	.llong .sys32_mount
@@ -532,14 +532,14 @@
 	.llong .ppc64_sys32_stime       /* 25 */
 	.llong .sys32_ptrace
 	.llong .sys_alarm
-	.llong .sys32_fstat
+	.llong .sys_ni_syscall		/* old fstat syscall */
 	.llong .sys32_pause
 	.llong .sys32_utime		/* 30 */
-	.llong .sys_ni_syscall			/* old stty syscall holder */
-	.llong .sys_ni_syscall			/* old gtty syscall holder */
+	.llong .sys_ni_syscall		/* old stty syscall */
+	.llong .sys_ni_syscall		/* old gtty syscall */
 	.llong .sys32_access
 	.llong .sys32_nice
-	.llong .sys_ni_syscall	/* 35 */	/* old ftime syscall holder */
+	.llong .sys_ni_syscall		/* 35 - old ftime syscall */
 	.llong .sys_sync
 	.llong .sys32_kill
 	.llong .sys_rename
@@ -548,21 +548,21 @@
 	.llong .sys_dup
 	.llong .sys_pipe
 	.llong .sys32_times
-	.llong .sys_ni_syscall			/* old prof syscall holder */
-	.llong .sys_brk		/* 45 */
+	.llong .sys_ni_syscall		/* old prof syscall */
+	.llong .sys_brk			/* 45 */
 	.llong .sys_setgid
 	.llong .sys_getgid
 	.llong .sys_signal
 	.llong .sys_geteuid
-	.llong .sys_getegid  	/* 50 */
+	.llong .sys_getegid		/* 50 */
 	.llong .sys_acct
-	.llong .sys32_umount			/* recycled never used phys() */
-	.llong .sys_ni_syscall			/* old lock syscall holder */
+	.llong .sys32_umount
+	.llong .sys_ni_syscall		/* old lock syscall */
 	.llong .sys32_ioctl
 	.llong .sys32_fcntl		/* 55 */
-	.llong .sys_ni_syscall			/* old mpx syscall holder */
+	.llong .sys_ni_syscall		/* old mpx syscall */
 	.llong .sys32_setpgid
-	.llong .sys_ni_syscall			/* old ulimit syscall holder */
+	.llong .sys_ni_syscall		/* old ulimit syscall */
 	.llong .sys_olduname
 	.llong .sys32_umask		/* 60 */
 	.llong .sys_chroot
@@ -588,11 +588,11 @@
 	.llong .sys32_setgroups
 	.llong .ppc32_select
 	.llong .sys_symlink
-	.llong .sys32_lstat
+	.llong .sys_ni_syscall		/* old lstat syscall */
 	.llong .sys32_readlink	        /* 85 */
 	.llong .sys_uselib
-	.llong .sys32_swapon
-	.llong .sys32_reboot
+	.llong .sys_swapon
+	.llong .sys_reboot
 	.llong .old32_readdir
 	.llong .sys32_mmap		/* 90 */
 	.llong .sys_munmap
@@ -602,34 +602,34 @@
 	.llong .sys_fchown              /* 95 */
 	.llong .sys32_getpriority
 	.llong .sys32_setpriority
-	.llong .sys_ni_syscall			/* old profil syscall holder */
+	.llong .sys_ni_syscall		/* old profil syscall */
 	.llong .sys32_statfs
-	.llong .sys32_fstatfs	/* 100 */
-	.llong .sys_ni_syscall		/* old ioperm syscall holder */
+	.llong .sys32_fstatfs		/* 100 */
+	.llong .sys_ioperm
 	.llong .sys32_socketcall
 	.llong .sys32_syslog
 	.llong .sys32_setitimer
-	.llong .sys32_getitimer	/* 105 */
+	.llong .sys32_getitimer		/* 105 */
 	.llong .sys32_newstat
 	.llong .sys32_newlstat
 	.llong .sys32_newfstat
 	.llong .sys_uname
-	.llong .sys_ni_syscall		/* 110 old iopl syscall holder */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
-	.llong .sys_ni_syscall		/* old 'idle' syscall */
-	.llong .sys_ni_syscall		/* old vm86 syscall holder */
+	.llong .sys_ni_syscall		/* old idle syscall */
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys32_wait4
-	.llong .sys_swapoff	/* 115 */
+	.llong .sys_swapoff		/* 115 */
 	.llong .sys32_sysinfo
 	.llong .sys32_ipc
 	.llong .sys_fsync
 	.llong .ppc32_sigreturn
-	.llong .sys32_clone		/* 120 */
+	.llong .sys_clone		/* 120 */
 	.llong .sys32_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys_ni_syscall		/* old modify_ldt syscall holder */
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys32_adjtimex
-	.llong .sys_mprotect	/* 125 */
+	.llong .sys_mprotect		/* 125 */
 	.llong .sys32_sigprocmask
 	.llong .sys32_create_module
 	.llong .sys32_init_module
@@ -638,7 +638,7 @@
 	.llong .sys_quotactl
 	.llong .sys32_getpgid
 	.llong .sys_fchdir
-	.llong .sys32_bdflush
+	.llong .sys_bdflush
 	.llong .sys32_sysfs		/* 135 */
 	.llong .sys32_personality
 	.llong .sys_ni_syscall	        /* for afs_syscall */
@@ -689,37 +689,37 @@
 	.llong .sys_getcwd
 	.llong .sys_capget
 	.llong .sys_capset
-	.llong .sys32_sigaltstack	        /* 185 */
+	.llong .sys32_sigaltstack	/* 185 */
 	.llong .sys32_sendfile
-	.llong .sys_ni_syscall		/* streams1 */
-	.llong .sys_ni_syscall		/* streams2 */
-	.llong .sys32_vfork
+	.llong .sys_ni_syscall		/* reserved for streams1 */
+	.llong .sys_ni_syscall		/* reserved for streams2 */
+	.llong .sys_vfork
 	.llong .sys32_getrlimit	        /* 190 */
 	.llong .sys32_readahead
-	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
-	.llong .sys32_truncate64	/* 193 - truncate64 */
-	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
-	.llong .sys_stat64      	/* 195 - stat64 */
-	.llong .sys_lstat64     	/* 196 - lstat64 */
-	.llong .sys_fstat64		/* 197 - fstat64 */
-	.llong .sys32_pciconfig_read  	/* 198 */
-	.llong .sys32_pciconfig_write  	/* 199 */
-	.llong .sys_ni_syscall		/* 200 - reserved - sys_pciconfig_iobase */
-	.llong .sys_ni_syscall		/* 201 - reserved - MacOnLinux - new */
-	.llong .sys_getdents64		/* 202 */
-	.llong .sys_pivot_root		/* 203 */
-	.llong .sys32_fcntl64		/* 204 */
+	.llong .ppc32_mmap2
+	.llong .sys32_truncate64
+	.llong .sys32_ftruncate64
+	.llong .sys_stat64      	/* 195 */
+	.llong .sys_lstat64
+	.llong .sys_fstat64
+	.llong .sys32_pciconfig_read
+	.llong .sys32_pciconfig_write
+	.llong .sys_ni_syscall		/* 200 - reserved for sys_pciconfig_iobase */
+	.llong .sys_ni_syscall		/* reserved for MacOnLinux */
+	.llong .sys_getdents64
+	.llong .sys_pivot_root
+	.llong .sys32_fcntl64
 	.llong .sys_madvise		/* 205 */
-	.llong .sys_mincore		/* 206 */
-	.llong .sys_gettid		/* 207 */
-	.llong .sys_tkill		/* 208 */
+	.llong .sys_mincore
+	.llong .sys_gettid
+	.llong .sys_tkill
 	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
+	.llong .sys_lsetxattr		/* 210 */
 	.llong .sys_fsetxattr
 	.llong .sys_getxattr
 	.llong .sys_lgetxattr
 	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
+	.llong .sys_listxattr		/* 215 */
 	.llong .sys_llistxattr
 	.llong .sys_flistxattr
 	.llong .sys_removexattr
@@ -728,17 +728,23 @@
 	.llong .sys_futex
 	.llong .sys32_sched_setaffinity
 	.llong .sys32_sched_getaffinity
-	.llong .sys_ni_syscall		/* reserved for security */
+	.llong .sys_security
 	.llong .sys_ni_syscall		/* 225 - reserved for tux */
+	.llong .sys32_sendfile64
+	.llong .sys_ni_syscall		/* reserved for sys_io_setup */
+	.llong .sys_ni_syscall		/* reserved for sys_io_destroy */
+	.llong .sys_ni_syscall		/* reserved for sys_io_getevents */
+	.llong .sys_ni_syscall		/* 230 - reserved for sys_io_submit */
+	.llong .sys_ni_syscall		/* reserved for sys_io_cancel */
 
-	.rept NR_syscalls-225
+	.rept NR_syscalls-231
 		.llong .sys_ni_syscall
 	.endr
 #endif
 
 	.balign 8
 _GLOBAL(sys_call_table)
-	.llong .sys_ni_syscall	/* 0  -  old "setup()" system call */
+	.llong .sys_ni_syscall		/* 0 - old setup syscall */
 	.llong .sys_exit
 	.llong .sys_fork
 	.llong .sys_read
@@ -748,17 +754,17 @@
 	.llong .sys_waitpid
 	.llong .sys_creat
 	.llong .sys_link
-	.llong .sys_unlink	/* 10 */
+	.llong .sys_unlink		/* 10 */
 	.llong .sys_execve
 	.llong .sys_chdir
 	.llong .sys64_time
 	.llong .sys_mknod
 	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
-	.llong .sys_ni_syscall			/* old break syscall holder */
-	.llong .sys_stat
+	.llong .sys_ni_syscall		/* old break syscall */
+	.llong .sys_ni_syscall		/* old stat syscall */
 	.llong .sys_lseek
-	.llong .sys_getpid	/* 20 */
+	.llong .sys_getpid		/* 20 */
 	.llong .sys_mount
 	.llong .sys_oldumount
 	.llong .sys_setuid
@@ -766,14 +772,14 @@
 	.llong .ppc64_sys_stime		/* 25 */
 	.llong .sys_ptrace
 	.llong .sys_alarm
-	.llong .sys_fstat
+	.llong .sys_ni_syscall		/* old fstat syscall */
 	.llong .sys_pause
 	.llong .sys_utime		/* 30 */
-	.llong .sys_ni_syscall			/* old stty syscall holder */
-	.llong .sys_ni_syscall			/* old gtty syscall holder */
+	.llong .sys_ni_syscall		/* old stty syscall */
+	.llong .sys_ni_syscall		/* old gtty syscall */
 	.llong .sys_access
 	.llong .sys_nice
-	.llong .sys_ni_syscall	/* 35 */	/* old ftime syscall holder */
+	.llong .sys_ni_syscall		/* 35 - old ftime syscall */
 	.llong .sys_sync
 	.llong .sys_kill
 	.llong .sys_rename
@@ -782,78 +788,78 @@
 	.llong .sys_dup
 	.llong .sys_pipe
 	.llong .sys_times
-	.llong .sys_ni_syscall			/* old prof syscall holder */
-	.llong .sys_brk		/* 45 */
+	.llong .sys_ni_syscall		/* old prof syscall */
+	.llong .sys_brk			/* 45 */
 	.llong .sys_setgid
 	.llong .sys_getgid
 	.llong .sys_signal
 	.llong .sys_geteuid
-	.llong .sys_getegid	/* 50 */
+	.llong .sys_getegid		/* 50 */
 	.llong .sys_acct
-	.llong .sys_umount			/* recycled never used phys() */
-	.llong .sys_ni_syscall			/* old lock syscall holder */
+	.llong .sys_umount
+	.llong .sys_ni_syscall		/* old lock syscall */
 	.llong .sys_ioctl
 	.llong .sys_fcntl		/* 55 */
-	.llong .sys_ni_syscall			/* old mpx syscall holder */
+	.llong .sys_ni_syscall		/* old mpx syscall */
 	.llong .sys_setpgid
-	.llong .sys_ni_syscall			/* old ulimit syscall holder */
+	.llong .sys_ni_syscall		/* old ulimit syscall */
 	.llong .sys_olduname
 	.llong .sys_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
 	.llong .sys_dup2
 	.llong .sys_getppid
-	.llong .sys_getpgrp	/* 65 */
+	.llong .sys_getpgrp		/* 65 */
 	.llong .sys_setsid
 	.llong .sys_sigaction
 	.llong .sys_sgetmask
 	.llong .sys_ssetmask
-	.llong .sys_setreuid	/* 70 */
+	.llong .sys_setreuid		/* 70 */
 	.llong .sys_setregid
 	.llong .sys_sigsuspend
 	.llong .sys_sigpending
 	.llong .sys_sethostname
-	.llong .sys_setrlimit	/* 75 */
+	.llong .sys_setrlimit		/* 75 */
 	.llong .sys_old_getrlimit
 	.llong .sys_getrusage
 	.llong .sys_gettimeofday
 	.llong .sys_settimeofday
-	.llong .sys_getgroups	/* 80 */
+	.llong .sys_getgroups		/* 80 */
 	.llong .sys_setgroups
 	.llong .sys_select
 	.llong .sys_symlink
-	.llong .sys_lstat
-	.llong .sys_readlink	/* 85 */
+	.llong .sys_ni_syscall		/* old lstat syscall */
+	.llong .sys_readlink		/* 85 */
 	.llong .sys_uselib
 	.llong .sys_swapon
 	.llong .sys_reboot
 	.llong .old_readdir
-	.llong .sys_mmap	/* 90 */
+	.llong .sys_mmap		/* 90 */
 	.llong .sys_munmap
 	.llong .sys_truncate
 	.llong .sys_ftruncate
 	.llong .sys_fchmod
-	.llong .sys_fchown	/* 95 */
+	.llong .sys_fchown		/* 95 */
 	.llong .sys_getpriority
 	.llong .sys_setpriority
-	.llong .sys_ni_syscall			/* old profil syscall holder */
+	.llong .sys_ni_syscall		/* old profil syscall holder */
 	.llong .sys_statfs
-	.llong .sys_fstatfs	/* 100 */
-	.llong .sys_ni_syscall		/* old ioperm syscall holder */
+	.llong .sys_fstatfs		/* 100 */
+	.llong .sys_ioperm
 	.llong .sys_socketcall
 	.llong .sys_syslog
 	.llong .sys_setitimer
-	.llong .sys_getitimer	/* 105 */
+	.llong .sys_getitimer		/* 105 */
 	.llong .sys_newstat
 	.llong .sys_newlstat
 	.llong .sys_newfstat
 	.llong .sys_uname
-	.llong .sys_ni_syscall		/* 110 old iopl syscall holder */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
-	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys_ni_syscall		/* old vm86 syscall holder */
+	.llong .sys_ni_syscall		/* old idle syscall */
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys_wait4
-	.llong .sys_swapoff	/* 115 */
+	.llong .sys_swapoff		/* 115 */
 	.llong .sys_sysinfo
 	.llong .sys_ipc
 	.llong .sys_fsync
@@ -863,7 +869,7 @@
 	.llong .ppc64_newuname
 	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
-	.llong .sys_mprotect	/* 125 */
+	.llong .sys_mprotect		/* 125 */
 	.llong .sys_sigprocmask
 	.llong .sys_create_module
 	.llong .sys_init_module
@@ -925,35 +931,35 @@
 	.llong .sys_capset
 	.llong .sys_sigaltstack	        /* 185 */
 	.llong .sys_sendfile
-	.llong .sys_ni_syscall		/* streams1 */
-	.llong .sys_ni_syscall		/* streams2 */
+	.llong .sys_ni_syscall		/* reserved for streams1 */
+	.llong .sys_ni_syscall		/* reserved for streams2 */
 	.llong .sys_vfork
 	.llong .sys_getrlimit	        /* 190 */
 	.llong .sys_readahead
-	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
-	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
-	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
-	.llong .sys_ni_syscall		/* 195 - reserved - stat64 */
-	.llong .sys_ni_syscall		/* 196 - reserved - lstat64 */
-	.llong .sys_ni_syscall		/* 197 - reserved - fstat64 */
-	.llong .sys_pciconfig_read	/* 198 */
-	.llong .sys_pciconfig_write 	/* 199 */
+	.llong .sys_ni_syscall		/* 32bit only mmap2 */
+	.llong .sys_ni_syscall		/* 32bit only truncate64 */
+	.llong .sys_ni_syscall		/* 32bit only ftruncate64 */
+	.llong .sys_ni_syscall		/* 195 - 32bit only stat64 */
+	.llong .sys_ni_syscall		/* 32bit only lstat64 */
+	.llong .sys_ni_syscall		/* 32bit only fstat64 */
+	.llong .sys_pciconfig_read
+	.llong .sys_pciconfig_write
 	.llong .sys_ni_syscall		/* 200 - reserved - sys_pciconfig_iobase */
-	.llong .sys_ni_syscall		/* 201 - reserved - MacOnLinux - new */
-	.llong .sys_getdents64		/* 202 */
-	.llong .sys_pivot_root		/* 203 */
-	.llong .sys_ni_syscall		/* 204 */
+	.llong .sys_ni_syscall		/* reserved for MacOnLinux */
+	.llong .sys_getdents64
+	.llong .sys_pivot_root
+	.llong .sys_ni_syscall		/* 32bit only fcntl64 */
 	.llong .sys_madvise		/* 205 */
-	.llong .sys_mincore		/* 206 */
-	.llong .sys_gettid		/* 207 */
-	.llong .sys_tkill		/* 208 */
+	.llong .sys_mincore
+	.llong .sys_gettid
+	.llong .sys_tkill
 	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
+	.llong .sys_lsetxattr		/* 210 */
 	.llong .sys_fsetxattr
 	.llong .sys_getxattr
 	.llong .sys_lgetxattr
 	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
+	.llong .sys_listxattr		/* 215 */
 	.llong .sys_llistxattr
 	.llong .sys_flistxattr
 	.llong .sys_removexattr
@@ -962,9 +968,15 @@
 	.llong .sys_futex
 	.llong .sys_sched_setaffinity
 	.llong .sys_sched_getaffinity
-	.llong .sys_ni_syscall		/* reserved for security */
-	.llong .sys_ni_syscall		/* reserved for tux */
+	.llong .sys_security
+	.llong .sys_ni_syscall		/* 225 - reserved for tux */
+	.llong .sys_ni_syscall		/* 32bit only sendfile64 */
+	.llong .sys_io_setup
+	.llong .sys_io_destroy
+	.llong .sys_io_getevents
+	.llong .sys_io_submit		/* 230 */
+	.llong .sys_io_cancel
 
-	.rept NR_syscalls-225
-	.llong .sys_ni_syscall
+	.rept NR_syscalls-231
+		.llong .sys_ni_syscall
 	.endr
diff -Nru a/arch/ppc64/kernel/mk_defs.c b/arch/ppc64/kernel/mk_defs.c
--- a/arch/ppc64/kernel/mk_defs.c	Sun Sep 15 19:20:00 2002
+++ b/arch/ppc64/kernel/mk_defs.c	Sun Sep 15 19:20:00 2002
@@ -20,7 +20,6 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <asm/io.h>
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Sun Sep 15 19:20:24 2002
@@ -34,91 +34,7 @@
 #include <asm/naca.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
-
-/* Status return values */
-#define H_Success	0
-#define H_Busy		1	/* Hardware busy -- retry later */
-#define H_Hardware	-1	/* Hardware error */
-#define H_Function	-2	/* Function not supported */
-#define H_Privilege	-3	/* Caller not privileged */
-#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
-#define H_Bad_Mode	-5	/* Illegal msr value */
-#define H_PTEG_Full	-6	/* PTEG is full */
-#define H_Not_Found	-7	/* PTE was not found" */
-#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
-
-/* Flags */
-#define H_LARGE_PAGE		(1UL<<(63-16))
-#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
-#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
-#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
-#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
-#define H_ANDCOND		(1UL<<(63-33))
-#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
-#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
-#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
-#define H_COPY_PAGE		(1UL<<(63-49))
-#define H_N			(1UL<<(63-61))
-#define H_PP1			(1UL<<(63-62))
-#define H_PP2			(1UL<<(63-63))
-
-
-
-/* pSeries hypervisor opcodes */
-#define H_REMOVE		0x04
-#define H_ENTER			0x08
-#define H_READ			0x0c
-#define H_CLEAR_MOD		0x10
-#define H_CLEAR_REF		0x14
-#define H_PROTECT		0x18
-#define H_GET_TCE		0x1c
-#define H_PUT_TCE		0x20
-#define H_SET_SPRG0		0x24
-#define H_SET_DABR		0x28
-#define H_PAGE_INIT		0x2c
-#define H_SET_ASR		0x30
-#define H_ASR_ON		0x34
-#define H_ASR_OFF		0x38
-#define H_LOGICAL_CI_LOAD	0x3c
-#define H_LOGICAL_CI_STORE	0x40
-#define H_LOGICAL_CACHE_LOAD	0x44
-#define H_LOGICAL_CACHE_STORE	0x48
-#define H_LOGICAL_ICBI		0x4c
-#define H_LOGICAL_DCBF		0x50
-#define H_GET_TERM_CHAR		0x54
-#define H_PUT_TERM_CHAR		0x58
-#define H_REAL_TO_LOGICAL	0x5c
-#define H_HYPERVISOR_DATA	0x60
-#define H_EOI			0x64
-#define H_CPPR			0x68
-#define H_IPI			0x6c
-#define H_IPOLL			0x70
-#define H_XIRR			0x74
-
-#define HSC			".long 0x44000022\n"
-#define H_ENTER_r3		"li	3, 0x08\n"
-
-/* plpar_hcall() -- Generic call interface using above opcodes
- *
- * The actual call interface is a hypervisor call instruction with
- * the opcode in R3 and input args in R4-R7.
- * Status is returned in R3 with variable output values in R4-R11.
- * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
- * and return only two out args which MUST ALWAYS BE PROVIDED.
- */
-long plpar_hcall(unsigned long opcode,
-		 unsigned long arg1,
-		 unsigned long arg2,
-		 unsigned long arg3,
-		 unsigned long arg4,
-		 unsigned long *out1,
-		 unsigned long *out2,
-		 unsigned long *out3);
-
-/* Same as plpar_hcall but for those opcodes that return no values
- * other than status.  Slightly more efficient.
- */
-long plpar_hcall_norets(unsigned long opcode, ...);
+#include <asm/hvcall.h>
 
 
 long plpar_pte_enter(unsigned long flags,
@@ -408,7 +324,7 @@
 	 * Leave all the interfaces NULL.
 	 */
 
-	if (naca->serialPortAddr) {
+	if (0 /*naca->serialPortAddr */) {
 		void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE);
 		udbg_init_uart(comport);
 		ppc_md.udbg_putc = udbg_putc;
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc64/kernel/pSeries_pci.c	Sun Sep 15 19:20:24 2002
@@ -1,7 +1,7 @@
 /*
  * pSeries_pci.c
  *
- * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  *
  * pSeries specific routines for PCI.
  * 
@@ -63,89 +63,85 @@
 
 static int s7a_workaround;
 
-/******************************************************************************
- *
- * pSeries I/O Operations to access the PCI configuration space.
- *
- *****************************************************************************/
-#define RTAS_PCI_READ_OP(size, type, nbytes) \
-int \
-rtas_read_config_##size(struct device_node *dn, int offset, type val) {  \
-	unsigned long returnval = ~0L; \
-	unsigned long buid; \
-	unsigned int addr; \
-	int ret; \
-	 \
-	if (dn == NULL) { \
-		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
-	} else { \
-		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
-		buid = dn->phb->buid; \
-		if (buid) { \
-			ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, nbytes); \
-                        if (ret < 0) \
-                               ret = rtas_fake_read(dn, offset, nbytes, &returnval); \
-		} else { \
-			ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, nbytes); \
-		} \
-	} \
-	*val = returnval; \
-	return ret; \
-} \
-int \
-rtas_pci_read_config_##size(struct pci_dev *dev, int offset, type val) {  \
-        struct device_node *dn = pci_device_to_OF_node(dev); \
-	int ret = rtas_read_config_##size(dn, offset, val); \
-        /* udbg_printf("read bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
-        return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
-}
-
-#define RTAS_PCI_WRITE_OP(size, type, nbytes) \
-int \
-rtas_write_config_##size(struct device_node *dn, int offset, type val) { \
-	unsigned long buid; \
-	unsigned int addr; \
-	int ret; \
-	 \
-	if (dn == NULL) { \
-		ret = -2; \
-	} else if (dn->status) { \
-		ret = -1; \
-	} else { \
-		buid = dn->phb->buid; \
-		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
-		if (buid) { \
-			ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, nbytes, (ulong) val); \
-		} else { \
-			ret = rtas_call(write_pci_config, 3, 1, NULL, addr, nbytes, (ulong)val); \
-		} \
-	} \
-	return ret; \
-} \
-int \
-rtas_pci_write_config_##size(struct pci_dev *dev, int offset, type val) { \
-	struct device_node*  dn = pci_device_to_OF_node(dev); \
-	int  ret = rtas_write_config_##size(dn, offset, val); \
-	/* udbg_printf("write bus=%x, devfn=%x, ret=%d phb=%lx, dn=%lx\n", dev->bus->number, dev->devfn, ret, dn ? dn->phb : 0, dn); */ \
-	return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; \
-}
-
-RTAS_PCI_READ_OP(byte, u8 *, 1)
-RTAS_PCI_READ_OP(word, u16 *, 2)
-RTAS_PCI_READ_OP(dword, u32 *, 4)
-RTAS_PCI_WRITE_OP(byte, u8, 1)
-RTAS_PCI_WRITE_OP(word, u16, 2)
-RTAS_PCI_WRITE_OP(dword, u32, 4)
+static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val)
+{
+	unsigned long returnval = ~0L;
+	unsigned long buid, addr;
+	int ret;
+
+	if (!dn)
+		return -2;
+
+	addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+	buid = dn->phb->buid;
+	if (buid) {
+		ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, buid >> 32, buid & 0xffffffff, size);
+		if (ret < 0|| (returnval == 0xffffffff))
+			ret = rtas_fake_read(dn, where, size, &returnval);
+	} else {
+		ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size);
+	}
+	*val = returnval;
+	return ret;
+}
+
+static int rtas_pci_read_config(struct pci_bus *bus,
+				unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	struct device_node *busdn, *dn;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+
+	/* Search only direct children of the bus */
+	for (dn = busdn->child; dn; dn = dn->sibling)
+		if (dn->devfn == devfn)
+			return rtas_read_config(dn, where, size, val);
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int rtas_write_config(struct device_node *dn, int where, int size, u32 val)
+{
+	unsigned long buid, addr;
+	int ret;
+
+	if (!dn)
+		return -2;
+
+	addr = (dn->busno << 16) | (dn->devfn << 8) | where;
+	buid = dn->phb->buid;
+	if (buid) {
+		ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val);
+	} else {
+		ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val);
+	}
+	return ret;
+}
+
+static int rtas_pci_write_config(struct pci_bus *bus,
+				 unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct device_node *busdn, *dn;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+
+	/* Search only direct children of the bus */
+	for (dn = busdn->child; dn; dn = dn->sibling)
+		if (dn->devfn == devfn)
+			return rtas_write_config(dn, where, size, val);
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
 
 struct pci_ops rtas_pci_ops = {
-	rtas_pci_read_config_byte,
-	rtas_pci_read_config_word,
-	rtas_pci_read_config_dword,
-	rtas_pci_write_config_byte,
- 	rtas_pci_write_config_word,
-	rtas_pci_write_config_dword,
+	rtas_pci_read_config,
+	rtas_pci_write_config
 };
 
 /*
@@ -569,8 +565,7 @@
 	
   if (buid_vals == NULL) {
 		phb->buid = 0;
-	} 
-  else {
+	} else {
 		struct pci_bus check;
 		if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 ||
 		    sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) {
@@ -582,11 +577,11 @@
 			      "number, primary, secondary and subordinate are ints.\n");
     }
     
-    if (len < 2 * sizeof(int))
-      phb->buid = (unsigned long)buid_vals[0];  // Support for new OF that only has 1 integer for buid.
-    else
-      phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
-                  (((unsigned long)buid_vals[1]) & 0xffffffff);
+	if (len < 2 * sizeof(int))
+		phb->buid = (unsigned long)buid_vals[0];  // Support for new OF that only has 1 integer for buid.
+	else
+		phb->buid = (((unsigned long)buid_vals[0]) << 32UL) |
+			(((unsigned long)buid_vals[1]) & 0xffffffff);
   	
 		phb->first_busno += (phb->global_number << 8);
 		phb->last_busno += (phb->global_number << 8);
@@ -656,6 +651,11 @@
 		if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) {
 			continue;
 		}
+		if (dev->resource[i].start > dev->resource[i].end) {
+			/* Bogus resource.  Just clear it out. */
+			dev->resource[i].start = dev->resource[i].end = 0;
+			continue;
+		}
 
 		if (dev->resource[i].flags & IORESOURCE_IO) {
 			if (is_eeh_implemented()) {
@@ -781,12 +781,8 @@
 void 
 pSeries_pcibios_init_early(void)
 {
-	ppc_md.pcibios_read_config_byte = rtas_read_config_byte;
-	ppc_md.pcibios_read_config_word = rtas_read_config_word;
-	ppc_md.pcibios_read_config_dword = rtas_read_config_dword;
-	ppc_md.pcibios_write_config_byte = rtas_write_config_byte;
-	ppc_md.pcibios_write_config_word = rtas_write_config_word;
-	ppc_md.pcibios_write_config_dword = rtas_write_config_dword;
+	ppc_md.pcibios_read_config = rtas_read_config;
+	ppc_md.pcibios_write_config = rtas_write_config;
 }
 /************************************************************************/
 /* Get a char* of the device physical location(U0.3-P1-I8)              */
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Sun Sep 15 19:20:23 2002
+++ b/arch/ppc64/kernel/pci.c	Sun Sep 15 19:20:23 2002
@@ -490,7 +490,8 @@
 #endif
 
 	/* Cache the location of the ISA bridge (if we have one) */
-	if (ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL))
+	ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+	if (ppc64_isabridge_dev != NULL)
 		printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name);
 
 	printk("PCI: Probing PCI hardware done\n");
@@ -514,11 +515,11 @@
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
+#ifndef CONFIG_PPC_ISERIES
 	struct pci_controller *phb = PCI_GET_PHB_PTR(bus);
 	struct resource *res;
 	int i;
 
-#ifndef CONFIG_PPC_ISERIES
 	if (bus->parent == NULL) {
 		/* This is a host bridge - fill in its resources */
 		phb->bus = bus;
diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
--- a/arch/ppc64/kernel/pci_dma.c	Sun Sep 15 19:19:56 2002
+++ b/arch/ppc64/kernel/pci_dma.c	Sun Sep 15 19:19:56 2002
@@ -708,10 +708,10 @@
 		 */
 		dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0);
 		if (dma_window) {
-			/* Busno hasn't been copied yet.
+			/* Bussubno hasn't been copied yet.
 			 * Do it now because getTceTableParmsPSeriesLP needs it.
 			 */
-			busdn->busno = bus->number;
+			busdn->bussubno = bus->number;
 			create_pci_bus_tce_table((unsigned long)busdn);
 		} else
 			create_tce_tables_for_busesLP(&bus->children);
@@ -966,12 +966,12 @@
 		panic("PCI_DMA: getTceTableParmsPSeriesLP: device %s has no ibm,dma-window property!\n", dn->full_name);
 	}
 
-	newTceTable->busNumber = dn->busno;
+	newTceTable->busNumber = dn->bussubno;
 	newTceTable->size = (((((unsigned long)dma_window[4] << 32) | (unsigned long)dma_window[5]) >> PAGE_SHIFT) << 3) >> PAGE_SHIFT;
 	newTceTable->startOffset = ((((unsigned long)dma_window[2] << 32) | (unsigned long)dma_window[3]) >> 12);
 	newTceTable->base = 0;
 	newTceTable->index = dma_window[0];
-	PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->busno);
+	PPCDBG(PPCDBG_TCEINIT, "getTceTableParmsPSeriesLP for bus 0x%lx:\n", dn->bussubno);
 	PPCDBG(PPCDBG_TCEINIT, "\tDevice = %s\n", dn->full_name);
 	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->index       = 0x%lx\n", newTceTable->index);
 	PPCDBG(PPCDBG_TCEINIT, "\tnewTceTable->startOffset = 0x%lx\n", newTceTable->startOffset);
@@ -1121,7 +1121,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_unmap_single size to large: 0x%lx \n",size);
+ 		printk("PCI_DMA: pci_unmap_single 0x%lx size to large: 0x%lx \n",dma_handle,size);
  		return;
  	}
 	
@@ -1377,10 +1377,11 @@
 	PPCDBG(PPCDBG_TCE, "pci_unmap_sg:\n");
 	PPCDBG(PPCDBG_TCE, "\thwdev = 0x%16.16lx, sg = 0x%16.16lx, direction = 0x%16.16lx, nelms = 0x%16.16lx\n", hwdev, sg, direction, nelms);	
 
-	if ( direction == PCI_DMA_NONE )
+	if ( direction == PCI_DMA_NONE || nelms == 0 )
 		BUG();
 
 	dma_start_page = sg->dma_address & PAGE_MASK;
+ 	dma_end_page   = 0;
 	for ( i=nelms; i>0; --i ) {
 		unsigned k = i - 1;
 		if ( sg[k].dma_length ) {
@@ -1396,6 +1397,7 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
+ 		printk("PCI_DMA: dma_start_page:0x%lx  dma_end_page:0x%lx\n",dma_start_page,dma_end_page);
 		printk("PCI_DMA: pci_unmap_sg size to large: 0x%x \n",(numTces << PAGE_SHIFT));
  		return;
  	}
diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
--- a/arch/ppc64/kernel/pci_dn.c	Sun Sep 15 19:19:46 2002
+++ b/arch/ppc64/kernel/pci_dn.c	Sun Sep 15 19:19:46 2002
@@ -74,9 +74,6 @@
 static void * __init
 write_OF_bars(struct device_node *dn, void *data)
 {
-	int i;
-	u32 oldbar, newbar, newbartest;
-	u8  config_offset;
 	char *name = get_property(dn, "name", 0);
 	char *device_type = get_property(dn, "device_type", 0);
 	char devname[128];
@@ -95,21 +92,25 @@
 		return NULL;
 	}
 
-#ifndef CONFIG_PPC_ISERIES 
+#ifndef CONFIG_PPC_ISERIES
+	int i;
+	u32 oldbar, newbar, newbartest;
+	u8 config_offset;
+
 	for (i = 0; i < dn->n_addrs; i++) {
 		newbar = dn->addrs[i].address;
 		config_offset = dn->addrs[i].space & 0xff;
-		if (ppc_md.pcibios_read_config_dword(dn, config_offset, &oldbar) != PCIBIOS_SUCCESSFUL) {
+		if (ppc_md.pcibios_read_config(dn, config_offset, 4, &oldbar) != PCIBIOS_SUCCESSFUL) {
 			printk(KERN_WARNING "write_OF_bars %s: read BAR%d failed\n", devname, i);
 			continue;
 		}
 		/* Need to update this BAR. */
-		if (ppc_md.pcibios_write_config_dword(dn, config_offset, newbar) != PCIBIOS_SUCCESSFUL) {
+		if (ppc_md.pcibios_write_config(dn, config_offset, 4, newbar) != PCIBIOS_SUCCESSFUL) {
 			printk(KERN_WARNING "write_OF_bars %s: write BAR%d with 0x%08x failed (old was 0x%08x)\n", devname, i, newbar, oldbar);
 			continue;
 		}
 		/* sanity check */
-		if (ppc_md.pcibios_read_config_dword(dn, config_offset, &newbartest) != PCIBIOS_SUCCESSFUL) {
+		if (ppc_md.pcibios_read_config(dn, config_offset, 4, &newbartest) != PCIBIOS_SUCCESSFUL) {
 			printk(KERN_WARNING "write_OF_bars %s: sanity test read BAR%d failed?\n", devname, i);
 			continue;
 		}
@@ -214,7 +215,6 @@
 	return NULL;
 }
 
-
 /* Traversal func that looks for a <busno,devfcn> value.
  * If found, the device_node is returned (thus terminating the traversal).
  */
@@ -223,6 +223,7 @@
 {
 	int busno = ((unsigned long)data >> 8) & 0xff;
 	int devfn = ((unsigned long)data) & 0xff;
+
 	return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
 }
 
diff -Nru a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
--- a/arch/ppc64/kernel/ppc_ksyms.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/ppc_ksyms.c	Sun Sep 15 19:19:29 2002
@@ -19,16 +19,13 @@
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 
 #include <asm/page.h>
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#if 0
-#include <linux/ide.h>
-#include <asm/ide.h>
-#endif
 #include <asm/atomic.h>
 #include <asm/bitops.h>
 #include <asm/checksum.h>
@@ -41,7 +38,6 @@
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
 #include <asm/abs_addr.h>
-#include <asm/smplock.h>
 #include <asm/cacheflush.h>
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iSeries/iSeries_pci.h>
@@ -54,6 +50,7 @@
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
+extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 extern int sys_sigreturn(struct pt_regs *regs);
 extern int do_signal(sigset_t *, struct pt_regs *);
 extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
@@ -68,6 +65,7 @@
 extern struct pci_dev * iSeries_vio_dev;
 
 EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys_sigreturn);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -158,15 +156,17 @@
 EXPORT_SYMBOL(pci_map_sg);
 EXPORT_SYMBOL(pci_unmap_sg);
 #ifdef CONFIG_PPC_ISERIES
-EXPORT_SYMBOL(iSeries_Write_Long);
 EXPORT_SYMBOL(iSeries_GetLocationData);
-EXPORT_SYMBOL(iSeries_Read_Long);
 EXPORT_SYMBOL(iSeries_Device_ToggleReset);
-EXPORT_SYMBOL(iSeries_Write_Word);
+EXPORT_SYMBOL(iSeries_memset_io);
+EXPORT_SYMBOL(iSeries_memcpy_toio);
 EXPORT_SYMBOL(iSeries_memcpy_fromio);
-EXPORT_SYMBOL(iSeries_Read_Word);
 EXPORT_SYMBOL(iSeries_Read_Byte);
+EXPORT_SYMBOL(iSeries_Read_Word);
+EXPORT_SYMBOL(iSeries_Read_Long);
 EXPORT_SYMBOL(iSeries_Write_Byte);
+EXPORT_SYMBOL(iSeries_Write_Word);
+EXPORT_SYMBOL(iSeries_Write_Long);
 #endif /* CONFIG_PPC_ISERIES */
 #ifndef CONFIG_PPC_ISERIES
 EXPORT_SYMBOL(eeh_check_failure);
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Sun Sep 15 19:19:53 2002
+++ b/arch/ppc64/kernel/process.c	Sun Sep 15 19:19:53 2002
@@ -25,12 +25,12 @@
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -235,9 +235,6 @@
 	current->thread.fpscr = 0;
 }
 
-/* XXX temporary */
-#define PR_FP_EXC_PRECISE	3	/* precise exception mode */
-
 int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
 {
 	struct pt_regs *regs = tsk->thread.regs;
@@ -259,19 +256,21 @@
 	return put_user(val, (unsigned int *) adr);
 }
 
-int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
-	      struct pt_regs *regs)
+int sys_clone(unsigned long clone_flags, u32 p2, u32 p3, u32 p4, u32 p5,
+	      u32 p6, struct pt_regs *regs)
 {
 	struct task_struct *p;
+	int *user_tid = (int *)p3;
 
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(p1 & ~CLONE_IDLETASK, regs->gpr[1], regs, 0);
+	p = do_fork(clone_flags & ~CLONE_IDLETASK, regs->gpr[1], regs, 0,
+		    user_tid);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
-int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+int sys_fork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
 	     struct pt_regs *regs)
 {
 	struct task_struct *p;
@@ -279,19 +278,20 @@
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(SIGCHLD, regs->gpr[1], regs, 0);
+	p = do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
-int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
-			 struct pt_regs *regs)
+int sys_vfork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
+	      struct pt_regs *regs)
 {
 	struct task_struct *p;
 
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0);
+	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0,
+	            NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Sun Sep 15 19:20:08 2002
+++ b/arch/ppc64/kernel/prom.c	Sun Sep 15 19:20:08 2002
@@ -180,6 +180,8 @@
 char *bootpath = 0;
 char *bootdevice = 0;
 
+int boot_cpuid = 0;
+
 struct device_node *allnodes = 0;
 
 #define UNDEFINED_IRQ 0xffff
@@ -619,8 +621,8 @@
 }
 
 
-static unsigned long __init
-prom_instantiate_rtas(unsigned long mem)
+static void __init
+prom_instantiate_rtas(void)
 {
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
@@ -653,16 +655,18 @@
 	        _rtas->size = getprop_rval;
 		prom_print(RELOC("instantiating rtas"));
 		if (_rtas->size != 0) {
-			/*
-			 * Ask OF for some space for RTAS.
-			 * Actually OF has bugs so we just arbitrarily
-			 * use memory at the 6MB point.
+			unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
+
+			/* Grab some space within the first RTAS_INSTANTIATE_MAX bytes
+			 * of physical memory (or within the RMO region) because RTAS
+			 * runs in 32-bit mode and relocate off.
 			 */
-			// The new code...
-			mem = PAGE_ALIGN(mem);
-			_rtas->base = mem + offset - KERNELBASE;
+			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+				struct lmb *_lmb  = PTRRELOC(&lmb);
+				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
+			}
+			_rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region);
 
-			mem += _rtas->size;
 			prom_print(RELOC(" at 0x"));
 			prom_print_hex(_rtas->base);
 
@@ -699,8 +703,6 @@
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_instantiate_rtas: end...\n"));
 #endif
-
-	return mem;
 }
 
 unsigned long prom_strtoul(const char *cp)
@@ -940,7 +942,7 @@
 		align = (minalign < minsize) ? minsize : minalign;
 
 		/* Carve out storage for the TCE table. */
-		base = lmb_alloc(minsize, align);
+		base = lmb_alloc(8UL << 20, 8UL << 20);
 
 		if ( !base ) {
 			prom_print(RELOC("ERROR, cannot find space for TCE table.\n"));
@@ -1350,7 +1352,9 @@
 		&getprop_rval, sizeof(getprop_rval));
 	_prom->cpu = (int)(unsigned long)getprop_rval;
 	_xPaca[_prom->cpu].active = 1;
+#ifdef CONFIG_SMP
 	RELOC(cpu_online_map) = 1 << _prom->cpu;
+#endif
 	RELOC(boot_cpuid) = _prom->cpu;
 
 #ifdef DEBUG_PROM
@@ -1378,7 +1382,7 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
-	mem = prom_instantiate_rtas(mem);
+	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
         mem = prom_initialize_naca(mem);
diff -Nru a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c
--- a/arch/ppc64/kernel/ptrace.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/ptrace.c	Sun Sep 15 19:19:29 2002
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -57,6 +58,9 @@
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ops->ptrace(current->parent, current);
+		if (ret)
 			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->ptrace |= PT_PTRACED;
diff -Nru a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c
--- a/arch/ppc64/kernel/ptrace32.c	Sun Sep 15 19:19:51 2002
+++ b/arch/ppc64/kernel/ptrace32.c	Sun Sep 15 19:19:51 2002
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -46,6 +47,9 @@
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ops->ptrace(current->parent, current);
+		if (ret)
 			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->ptrace |= PT_PTRACED;
diff -Nru a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c
--- a/arch/ppc64/kernel/ras.c	Sun Sep 15 19:19:30 2002
+++ b/arch/ppc64/kernel/ras.c	Sun Sep 15 19:19:30 2002
@@ -23,7 +23,6 @@
  * End Change Activity 
  */
 
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/kernel_stat.h>
diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/rtas.c	Sun Sep 15 19:19:29 2002
@@ -106,17 +106,12 @@
 	enter_rtas((void *)__pa((unsigned long)rtas));	
 }
 
-#if 0
-#define DEBUG_RTAS
-#endif
 int
 rtas_token(const char *service)
 {
 	int *tokp;
 	if (rtas.dev == NULL) {
-#ifdef DEBUG_RTAS
-		udbg_printf("\tNo rtas device in device-tree...\n");
-#endif /* DEBUG_RTAS */
+		PPCDBG(PPCDBG_RTAS,"\tNo rtas device in device-tree...\n");
 		return RTAS_UNKNOWN_SERVICE;
 	}
 	tokp = (int *) get_property(rtas.dev, service, NULL);
@@ -132,13 +127,11 @@
 	unsigned long s;
 	struct rtas_args *rtas_args = &(get_paca()->xRtas);
 
-#ifdef DEBUG_RTAS
-	udbg_printf("Entering rtas_call\n");
-	udbg_printf("\ttoken    = 0x%x\n", token);
-	udbg_printf("\tnargs    = %d\n", nargs);
-	udbg_printf("\tnret     = %d\n", nret);
-	udbg_printf("\t&outputs = 0x%lx\n", outputs);
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n");
+	PPCDBG(PPCDBG_RTAS, "\ttoken    = 0x%x\n", token);
+	PPCDBG(PPCDBG_RTAS, "\tnargs    = %d\n", nargs);
+	PPCDBG(PPCDBG_RTAS, "\tnret     = %d\n", nret);
+	PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs);
 	if (token == RTAS_UNKNOWN_SERVICE)
 		return -1;
 
@@ -149,9 +142,7 @@
 	va_start(list, outputs);
 	for (i = 0; i < nargs; ++i) {
 	  rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
-#ifdef DEBUG_RTAS
-	  udbg_printf("\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
-#endif /* DEBUG_RTAS */
+		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
 	}
 	va_end(list);
 
@@ -163,22 +154,19 @@
 #else
 	spin_lock_irqsave(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
-	udbg_printf("\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args));
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
+		(void *)__pa((unsigned long)rtas_args));
 	enter_rtas((void *)__pa((unsigned long)rtas_args));
-#ifdef DEBUG_RTAS
-	udbg_printf("\treturned from rtas ...\n");
-#endif /* DEBUG_RTAS */
+	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
 #if 0   /* Gotta do something different here, use global lock for now... */
 	spin_unlock_irqrestore(&rtas_args->lock, s);
 #else
 	spin_unlock_irqrestore(&rtas.lock, s);
 #endif
-#ifdef DEBUG_RTAS
+	ifppcdebug(PPCDBG_RTAS) {
 	for(i=0; i < nret ;i++)
 	  udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
-#endif /* DEBUG_RTAS */
+	}
 
 	if (nret > 1 && outputs != NULL)
 		for (i = 0; i < nret-1; ++i)
diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Sun Sep 15 19:19:40 2002
+++ b/arch/ppc64/kernel/setup.c	Sun Sep 15 19:19:40 2002
@@ -262,7 +262,6 @@
 	unsigned short maj;
 	unsigned short min;
 
-#ifdef CONFIG_SMP
 	if (cpu_id == NR_CPUS) {
 
 		if (ppc_md.get_cpuinfo != NULL)
@@ -273,16 +272,17 @@
 
 	if (!(cpu_online_map & (1<<cpu_id)))
 		return 0;
-#endif
 
+#ifdef CONFIG_SMP
 	pvr = paca[cpu_id].pvr;
+#else
+	pvr = _get_PVR();
+#endif
 	maj = (pvr >> 8) & 0xFF;
 	min = pvr & 0xFF;
 
 	seq_printf(m, "processor\t: %lu\n", cpu_id);
 	seq_printf(m, "cpu\t\t: ");
-
-	pvr = paca[cpu_id].pvr;
 
 	switch (PVR_VER(pvr)) {
 	case PV_NORTHSTAR:
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Sun Sep 15 19:19:28 2002
+++ b/arch/ppc64/kernel/signal.c	Sun Sep 15 19:19:28 2002
@@ -22,7 +22,6 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/wait.h>
-#include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
 #include <linux/elf.h>
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Sun Sep 15 19:20:12 2002
+++ b/arch/ppc64/kernel/smp.c	Sun Sep 15 19:20:12 2002
@@ -55,7 +55,6 @@
 
 /* initialised so it doesnt end up in bss */
 unsigned long cpu_online_map = 0;
-int boot_cpuid = 0;
 
 static struct smp_ops_t *smp_ops;
 
@@ -616,7 +615,7 @@
 	/* create a process for the processor */
 	/* only regs.msr is actually used, and 0 is OK for it */
 	memset(&regs, 0, sizeof(struct pt_regs));
-	p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
+	p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
 
diff -Nru a/arch/ppc64/kernel/sys32.S b/arch/ppc64/kernel/sys32.S
--- a/arch/ppc64/kernel/sys32.S	Sun Sep 15 19:20:20 2002
+++ b/arch/ppc64/kernel/sys32.S	Sun Sep 15 19:20:20 2002
@@ -44,14 +44,10 @@
 	clrldi		r7, r7, 32	/* int *optlen parm */
 	b		.sys_getsockopt
 
-_GLOBAL(sys32_bdflush)
-	extsw		r4,r4		/* sign extend long data parm */
-	b		.sys_bdflush
-
-_GLOBAL(sys32_mmap2)
+_GLOBAL(ppc32_mmap2)
 	clrldi		r7, r7, 32	/* unsigned long fd parm */
-	extsw		r8, r8		/* off_t offset */
-	b		.sys_mmap
+	clrldi		r8, r8, 32	/* unsigned long pgoff */
+	b		.sys32_mmap2
 
 _GLOBAL(sys32_socketcall)	/* r3=call, r4=args */
 	cmpwi		r3, 1
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Sun Sep 15 19:20:05 2002
+++ b/arch/ppc64/kernel/sys_ppc32.c	Sun Sep 15 19:20:05 2002
@@ -67,21 +67,6 @@
 #include <asm/ppc32.h>
 #include <asm/mmu_context.h>
 
-extern unsigned long wall_jiffies;
-#define USEC_PER_SEC (1000000)
-
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
-
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
 struct utimbuf32 {
@@ -461,7 +446,6 @@
 	u32		d_ino;
 	u32		d_offset;
 	unsigned short	d_namlen;
-  /* unsigned char	d_type; */
 	char		d_name[1];
 };
 
@@ -512,22 +496,12 @@
 	return error;
 }
 
-#if 0
 struct linux_dirent32 {
 	u32		d_ino;
 	u32		d_off;
 	unsigned short	d_reclen;
 	char		d_name[1];
 };
-#else
-struct linux_dirent32 {
-	u32		d_ino;
-	u32		d_off;
-	unsigned short	d_reclen;
-  /* unsigned char	d_type; */
-	char		d_name[256];
-};
-#endif
 
 struct getdents_callback32 {
 	struct linux_dirent32 * current_dir;
@@ -554,7 +528,6 @@
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(reclen, &dirent->d_reclen);
-	/* put_user(d_type, &dirent->d_type); */
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
 	((char *) dirent) += reclen;
@@ -1432,15 +1405,10 @@
 	return -ENOSYS;
 }
 
-/* Note: it is necessary to treat which as an unsigned int, 
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_query_module(const char *name_user, u32 which, char *buf, size_t bufsize, size_t *ret)
+asmlinkage long sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret)
 {
 	/* Let the program know about the new interface.  Not that it'll do them much good. */
-	if ((int)which == 0)
+	if (which == 0)
 		return 0;
 
 	return -ENOSYS;
@@ -2779,69 +2747,6 @@
 	return err;
 }
 
-/* stat syscall methods. */
-extern asmlinkage int sys_stat(char* filename, struct __old_kernel_stat* statbuf);
-
-static int cp_old_stat32(struct kstat *stat, struct __old_kernel_stat32* statbuf)
-{
-	static int warncount = 5;
-	struct __old_kernel_stat32 tmp;
-
-	if (warncount) {
-		warncount--;
-		printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n",
-			current->comm);
-	}
-
-	tmp.st_dev = stat->dev;
-	tmp.st_ino = stat->ino;
-	tmp.st_mode = stat->mode;
-	tmp.st_nlink = stat->nlink;
-	SET_OLDSTAT_UID(tmp, stat->uid);
-	SET_OLDSTAT_GID(tmp, stat->gid);
-	tmp.st_rdev = stat->rdev;
-	if (stat->size > MAX_NON_LFS)
-		return -EOVERFLOW;
-	tmp.st_size = stat->size;
-	tmp.st_atime = stat->atime;
-	tmp.st_mtime = stat->mtime;
-	tmp.st_ctime = stat->ctime;
-	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
-}
-
-asmlinkage long sys32_stat(char* filename, struct __old_kernel_stat32* statbuf)
-{
-	struct kstat stat;
-	int error = vfs_stat(filename, &stat);
-	
-	if (!error)
-		error = cp_old_stat32(&stat, statbuf);
-
-	return error;
-}
-
-asmlinkage long sys32_fstat(unsigned int fd, struct __old_kernel_stat32* statbuf)
-{
-	struct kstat stat;
-	int error = vfs_fstat(fd, &stat);
-	
-	if (!error)
-		error = cp_old_stat32(&stat, statbuf);
-
-	return error;
-}
-
-asmlinkage long sys32_lstat(char* filename, struct __old_kernel_stat32* statbuf)
-{
-	struct kstat stat;
-	int error = vfs_lstat(filename, &stat);
-	
-	if (!error)
-		error = cp_old_stat32(&stat, statbuf);
-
-	return error;
-}
-
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t* offset, size_t count);
 
 /* Note: it is necessary to treat out_fd and in_fd as unsigned ints, 
@@ -2868,6 +2773,27 @@
 	return ret;
 }
 
+extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count);
+
+asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	loff_t lof;
+	
+	if (offset && get_user(lof, offset))
+		return -EFAULT;
+		
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
+	set_fs(old_fs);
+	
+	if (offset && put_user(lof, offset))
+		return -EFAULT;
+		
+	return ret;
+}
+
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
 
 asmlinkage long sys32_setsockopt(int fd, int level, int optname, char* optval, int optlen)
@@ -3560,7 +3486,7 @@
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-
+	bprm.security = NULL;
 	bprm.mm = mm_alloc();
 	retval = -ENOMEM;
 	if (!bprm.mm)
@@ -3578,6 +3504,10 @@
 	if ((retval = bprm.envc) < 0)
 		goto out_mm;
 
+	retval = security_ops->bprm_alloc_security(&bprm);
+	if (retval) 
+		goto out;
+
 	retval = prepare_binprm(&bprm);
 	if (retval < 0) 
 		goto out; 
@@ -3596,9 +3526,11 @@
 		goto out; 
 
 	retval = search_binary_handler(&bprm,regs);
-	if (retval >= 0)
+	if (retval >= 0) {
 		/* execve success */
+		security_ops->bprm_free_security(&bprm);
 		return retval;
+	}
 
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
@@ -3608,6 +3540,9 @@
 			__free_page(page);
 	}
 
+	if (bprm.security)
+		security_ops->bprm_free_security(&bprm);
+
 out_mm:
 	mmdrop(bprm.mm);
 
@@ -3766,19 +3701,6 @@
 }
 
 
-extern asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
-
-/* Note: it is necessary to treat p1, p2, p3, p4, p5, p7, and regs as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_clone(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
-{
-	return sys_clone((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
-}
-
-
 extern asmlinkage long sys_creat(const char * pathname, int mode);
 
 /* Note: it is necessary to treat mode as an unsigned int,
@@ -3792,19 +3714,6 @@
 }
 
 
-extern asmlinkage long sys_exit(int error_code);
-
-/* Note: it is necessary to treat error_code as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_exit(u32 error_code)
-{
-	return sys_exit((int)error_code);
-}
-
-
 extern asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, struct rusage * ru);
 
 /* Note: it is necessary to treat pid and options as unsigned ints,
@@ -3847,19 +3756,6 @@
 }
 
 
-extern asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
-
-/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_fork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
-{
-	return sys_fork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
-}
-
-
 extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
 
 /* Note: it is necessary to treat gidsetsize as an unsigned int,
@@ -3978,19 +3874,36 @@
 	return sys_nice((int)increment);
 }
 
-
-extern asmlinkage long sys_open(const char * filename, int flags, int mode);
-
-/* Note: it is necessary to treat flags and mode as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * This is just a version for 32-bit applications which does
+ * not force O_LARGEFILE on.
  */
-asmlinkage long sys32_open(const char * filename, int flags, int mode)
+long sys32_open(const char * filename, int flags, int mode)
 {
-	return sys_open(filename, (int)flags, (int)mode);
-}
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file * f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
 
@@ -4004,20 +3917,6 @@
 	return sys_readlink(path, buf, (int)bufsiz);
 }
 
-
-extern asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg);
-
-/* Note: it is necessary to treat magic1 and magic2 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_reboot(u32 magic1, u32 magic2, unsigned int cmd, void * arg)
-{
-	return sys_reboot((int)magic1, (int)magic2, cmd, arg);
-}
-
-
 extern asmlinkage long sys_sched_get_priority_max(int policy);
 
 /* Note: it is necessary to treat option as an unsigned int,
@@ -4174,19 +4073,6 @@
 }
 
 
-extern asmlinkage long sys_swapon(const char * specialfile, int swap_flags);
-
-/* Note: it is necessary to treat swap_flags as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_swapon(const char * specialfile, u32 swap_flags)
-{
-	return sys_swapon(specialfile, (int)swap_flags);
-}
-
-
 extern asmlinkage long sys_syslog(int type, char * buf, int len);
 
 /* Note: it is necessary to treat type and len as an unsigned int,
@@ -4226,19 +4112,6 @@
 }
 
 
-extern asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs);
-
-/* Note: it is necessary to treat p1, p2, p3, p4, p5, and p6 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_vfork(u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, struct pt_regs *regs)
-{
-	return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
-}
-
-
 extern ssize_t sys_pread64(unsigned int fd, char *buf, size_t count,
 			   loff_t pos);
 
@@ -4254,16 +4127,16 @@
 }
 
 ssize_t32 sys32_pwrite64(unsigned int fd, char *ubuf, __kernel_size_t32 count,
-			 u32 reg6 ,u32 poshi, u32 poslo)
+			 u32 reg6, u32 poshi, u32 poslo)
 {
 	return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
 extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
 
-ssize_t32 sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+ssize_t32 sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
 {
-        return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+        return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, AA(count));
 }
 
 extern asmlinkage long sys_truncate(const char * path, unsigned long length);
@@ -4410,4 +4283,16 @@
 	}
 
 	return ret;
+}
+
+extern unsigned long sys_mmap(unsigned long addr, size_t len,
+			      unsigned long prot, unsigned long flags,
+			      unsigned long fd, off_t offset);
+
+unsigned long sys32_mmap2(unsigned long addr, size_t len,
+			  unsigned long prot, unsigned long flags,
+			  unsigned long fd, unsigned long pgoff)
+{
+	/* This should remain 12 even if PAGE_SIZE changes */
+	return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
 }
diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/kernel/syscalls.c	Sun Sep 15 19:19:29 2002
@@ -254,7 +254,7 @@
 	tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
 
 	secs  = xtime.tv_sec;  
-	usecs = xtime.tv_usec + tb_delta / tb_ticks_per_usec;
+	usecs = (xtime.tv_nsec/1000) + tb_delta / tb_ticks_per_usec;
 	while (usecs >= USEC_PER_SEC) {
 		++secs;
 		usecs -= USEC_PER_SEC;
diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
--- a/arch/ppc64/kernel/time.c	Sun Sep 15 19:20:24 2002
+++ b/arch/ppc64/kernel/time.c	Sun Sep 15 19:20:24 2002
@@ -150,7 +150,7 @@
          */
         if ( (time_status & STA_UNSYNC) == 0 &&
              xtime.tv_sec - last_rtc_update >= 659 &&
-             abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
+             abs((xtime.tv_nsec/1000) - (1000000-1000000/HZ)) < 500000/HZ &&
              jiffies - wall_jiffies == 1) {
 	    struct rtc_time tm;
 	    to_tm(xtime.tv_sec+1, &tm);
@@ -175,7 +175,7 @@
 		do_gettimeofday( &my_tv );
 		if ( xtime.tv_sec <= my_tv.tv_sec ) {
 			xtime.tv_sec = my_tv.tv_sec;
-			xtime.tv_usec = my_tv.tv_usec;
+			xtime.tv_nsec = my_tv.tv_usec * 1000;
 		}
 	}
 }
@@ -356,7 +356,7 @@
 		new_sec--; 
 		new_usec += USEC_PER_SEC;
 	}
-	xtime.tv_usec = new_usec;
+	xtime.tv_nsec = new_usec * 1000;
 	xtime.tv_sec = new_sec;
 
 	/* In case of a large backwards jump in time with NTP, we want the 
@@ -465,7 +465,7 @@
 
 	time_freq = 0;
 
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 	last_rtc_update = xtime.tv_sec;
 	write_unlock_irqrestore(&xtime_lock, flags);
 
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Sun Sep 15 19:19:48 2002
+++ b/arch/ppc64/kernel/traps.c	Sun Sep 15 19:19:48 2002
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
-#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
diff -Nru a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c
--- a/arch/ppc64/mm/fault.c	Sun Sep 15 19:19:29 2002
+++ b/arch/ppc64/mm/fault.c	Sun Sep 15 19:19:29 2002
@@ -24,7 +24,6 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Sun Sep 15 19:19:52 2002
+++ b/arch/ppc64/mm/init.c	Sun Sep 15 19:19:52 2002
@@ -27,7 +27,6 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
@@ -58,6 +57,7 @@
 #include <asm/naca.h>
 #include <asm/eeh.h>
 #include <asm/processor.h>
+#include <asm/mmzone.h>
 
 #include <asm/ppcdebug.h>
 
@@ -99,21 +99,23 @@
 
 void show_mem(void)
 {
-	int i,total = 0,reserved = 0;
+	int pfn, total = 0, reserved = 0;
 	int shared = 0, cached = 0;
+	struct page *page;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	i = max_mapnr;
-	while (i-- > 0) {
+	pfn = max_mapnr;
+	while (pfn-- > 0) {
+		page = pfn_to_page(pfn);
 		total++;
-		if (PageReserved(mem_map+i))
+		if (PageReserved(page))
 			reserved++;
-		else if (PageSwapCache(mem_map+i))
+		else if (PageSwapCache(page))
 			cached++;
-		else if (page_count(mem_map+i))
-			shared += page_count(mem_map+i) - 1;
+		else if (page_count(page))
+			shared += page_count(page) - 1;
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d reserved pages\n",reserved);
@@ -434,6 +436,7 @@
  * Initialize the bootmem system and give it all the memory we
  * have available.
  */
+#ifndef CONFIG_DISCONTIGMEM
 void __init do_init_bootmem(void)
 {
 	unsigned long i;
@@ -493,6 +496,7 @@
 		zones_size[i] = 0;
 	free_area_init(zones_size);
 }
+#endif
 
 extern unsigned long prof_shift;
 extern unsigned long prof_len;
@@ -505,19 +509,39 @@
 
 void __init mem_init(void)
 {
+#ifndef CONFIG_DISCONTIGMEM
 	extern char *sysmap; 
 	extern unsigned long sysmap_size;
 	unsigned long addr;
+#endif
 	int codepages = 0;
 	int datapages = 0;
 	int initpages = 0;
-	unsigned long va_rtas_base = (unsigned long)__va(rtas.base);
 
 	max_mapnr = max_low_pfn;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
 	max_pfn = max_low_pfn;
 
+#ifdef CONFIG_DISCONTIGMEM
+{
+	int nid;
+
+        for (nid = 0; nid < MAX_NUMNODES; nid++) {
+		if (numa_node_exists[nid]) {
+			printk("freeing bootmem node %x\n", nid);
+			totalram_pages +=
+				free_all_bootmem_node(NODE_DATA(nid));
+		}
+	}
+
+	printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	       (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
+	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
+	       initpages<< (PAGE_SHIFT-10),
+	       PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM()));
+}
+#else
 	totalram_pages += free_all_bootmem();
 
 	if ( sysmap_size )
@@ -545,6 +569,7 @@
 	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
 	       initpages<< (PAGE_SHIFT-10),
 	       PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM()));
+#endif
 	mem_init_done = 1;
 
 	/* set the last page of each hardware interrupt stack to be protected */
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Sun Sep 15 19:20:22 2002
+++ b/arch/ppc64/xmon/xmon.c	Sun Sep 15 19:20:22 2002
@@ -33,7 +33,7 @@
 #define skipbl	xmon_skipbl
 
 #ifdef CONFIG_SMP
-static unsigned long cpus_in_xmon = 0;
+unsigned long cpus_in_xmon = 0;
 static unsigned long got_xmon = 0;
 static volatile int take_xmon = -1;
 #endif /* CONFIG_SMP */
diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile
--- a/arch/sh/Makefile	Sun Sep 15 19:19:57 2002
+++ b/arch/sh/Makefile	Sun Sep 15 19:19:57 2002
@@ -72,9 +72,7 @@
 
 vmlinux: arch/sh/vmlinux.lds.s
 
-CPPFLAGS_arch/sh/vmlinux.lds.s := -traditional
-
-FORCE: ;
+AFLAGS_vmlinux.lds.o := -traditional
 
 zImage: vmlinux
 	@$(MAKEBOOT) zImage
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc/config.in	Sun Sep 15 19:19:28 2002
@@ -59,6 +59,9 @@
 mainmenu_option next_comment
 comment 'Console drivers'
 bool 'PROM console' CONFIG_PROM_CONSOLE
+if [ "$CONFIG_PROM_CONSOLE" != "y" ]; then
+   define_bool CONFIG_DUMMY_CONSOLE y
+fi
 source drivers/video/Config.in
 endmenu
 
@@ -213,6 +216,8 @@
    int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
 fi
 endmenu
+
+source drivers/input/Config.in
 
 source fs/Config.in
 
diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig
--- a/arch/sparc/defconfig	Sun Sep 15 19:20:14 2002
+++ b/arch/sparc/defconfig	Sun Sep 15 19:20:14 2002
@@ -3,6 +3,12 @@
 #
 CONFIG_UID16=y
 CONFIG_HIGHMEM=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
 
 #
 # General setup
@@ -13,11 +19,6 @@
 CONFIG_SYSCTL=y
 
 #
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
 # Loadable module support
 #
 CONFIG_MODULES=y
@@ -29,6 +30,7 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SMP is not set
 CONFIG_SPARC32=y
 # CONFIG_ISA is not set
@@ -37,20 +39,15 @@
 # CONFIG_PCMCIA is not set
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
-CONFIG_BUSMOUSE=y
-CONFIG_SUN_MOUSE=y
-CONFIG_SERIAL=y
-CONFIG_SUN_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
-CONFIG_SUN_KEYBOARD=y
-CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_SUN_PM=y
 # CONFIG_SUN4 is not set
-# CONFIG_PCI is not set
+CONFIG_PCI=y
+# CONFIG_PCI_NAMES is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_AOUT=y
@@ -67,29 +64,13 @@
 #
 # Console drivers
 #
-CONFIG_PROM_CONSOLE=y
+# CONFIG_PROM_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 
 #
 # Frame-buffer support
 #
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_SBUS=y
-CONFIG_FB_CGSIX=y
-CONFIG_FB_BWTWO=y
-CONFIG_FB_CGTHREE=y
-CONFIG_FB_TCX=y
-CONFIG_FB_CGFOURTEEN=y
-# CONFIG_FB_P9100 is not set
-CONFIG_FB_LEO=y
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_MFB=y
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_FONTWIDTH8_ONLY=y
-CONFIG_FONT_SUN8x16=y
-# CONFIG_FBCON_FONTS is not set
+# CONFIG_FB is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -97,15 +78,41 @@
 # CONFIG_MTD is not set
 
 #
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_CS is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SUNCORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SERIAL_SUNSU=y
+# CONFIG_SERIAL_SUNSAB is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+
+#
 # Misc Linux/SPARC drivers
 #
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
-CONFIG_SUN_AURORA=m
+# CONFIG_SUN_AURORA is not set
 # CONFIG_TADPOLE_TS102_UCTRL is not set
 # CONFIG_SUN_JSFLASH is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_RTC is not set
 
 #
 # Linux/SPARC audio subsystem (EXPERIMENTAL)
@@ -119,9 +126,9 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_DEV_FD is not set
 CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_NBD is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -139,6 +146,31 @@
 CONFIG_BLK_DEV_INITRD=y
 
 #
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fibre Channel support
+#
+# CONFIG_FC4 is not set
+# CONFIG_FC4_SOC is not set
+# CONFIG_FC4_SOCAL is not set
+# CONFIG_SCSI_PLUTO is not set
+# CONFIG_SCSI_FCAL is not set
+
+#
 # Networking options
 #
 CONFIG_PACKET=y
@@ -150,30 +182,35 @@
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
 
 #
-#  
+#    SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPX=m
-# CONFIG_IPX_INTERN is not set
-CONFIG_ATALK=m
-CONFIG_DECNET=m
-CONFIG_DECNET_SIOCGIFCONF=y
-# CONFIG_DECNET_ROUTER is not set
+CONFIG_IPV6_SCTP__=m
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_ADLER32 is not set
+# CONFIG_SCTP_DBG_MSG is not set
+CONFIG_SCTP_DBG_OBJCNT=y
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -184,83 +221,22 @@
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
-# CONFIG_IDE is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CDrom)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
-CONFIG_CHR_DEV_SG=m
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-CONFIG_SCSI_SUNESP=y
-CONFIG_SCSI_QLOGICPTI=m
-
-#
-# Fibre Channel support
-#
-CONFIG_FC4=m
-
-#
-# FC4 drivers
-#
-CONFIG_FC4_SOC=m
-CONFIG_FC4_SOCAL=m
-
-#
-# FC4 targets
-#
-CONFIG_SCSI_PLUTO=m
-CONFIG_SCSI_FCAL=m
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
-CONFIG_BONDING=m
-# CONFIG_TUN is not set
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
-CONFIG_SUNLANCE=y
-CONFIG_HAPPYMEAL=m
-CONFIG_SUNBMAC=m
+# CONFIG_BONDING is not set
+CONFIG_TUN=m
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+CONFIG_SUNLANCE=m
+CONFIG_HAPPYMEAL=y
+# CONFIG_SUNBMAC is not set
 CONFIG_SUNQE=m
-CONFIG_MYRI_SBUS=m
+# CONFIG_MYRI_SBUS is not set
+CONFIG_VORTEX=m
 
 #
 # Unix98 PTY support
@@ -272,6 +248,8 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
 # CONFIG_REISERFS_FS is not set
@@ -279,17 +257,17 @@
 # CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
-CONFIG_AFFS_FS=m
+# CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
 # CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
-CONFIG_EFS_FS=m
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
@@ -298,12 +276,15 @@
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-CONFIG_MINIX_FS=m
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_DEBUG is not set
 # CONFIG_NTFS_RW is not set
-CONFIG_HPFS_FS=m
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
@@ -313,26 +294,27 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_SYSV_FS=m
+# CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
-CONFIG_UFS_FS=m
+# CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
-CONFIG_CODA_FS=m
-CONFIG_INTERMEZZO_FS=m
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=m
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_EXPORTFS is not set
+# CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
 # CONFIG_NCPFS_IOCTL_LOCKING is not set
@@ -343,7 +325,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -351,49 +332,8 @@
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
 CONFIG_SUN_PARTITION=y
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
 
 #
 # Bluetooth support
@@ -408,9 +348,18 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_SLAB=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+
+#
+# Security options
+#
+CONFIG_SECURITY_CAPABILITIES=y
 
 #
 # Library routines
 #
 CONFIG_CRC32=y
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Nru a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
--- a/arch/sparc/kernel/Makefile	Sun Sep 15 19:19:30 2002
+++ b/arch/sparc/kernel/Makefile	Sun Sep 15 19:19:30 2002
@@ -13,7 +13,7 @@
 IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
 obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
 	    process.o signal.o ioport.o setup.o idprom.o \
-	    sys_sparc.o sunos_asm.o sparc-stub.o systbls.o \
+	    sys_sparc.o sunos_asm.o systbls.o \
 	    time.o windows.o cpu.o devices.o sclow.o \
 	    tadpole.o tick14.o ptrace.o sys_solaris.o \
 	    unaligned.o muldiv.o pcic.o semaphore.o sparc_ksyms.o
diff -Nru a/arch/sparc/kernel/check_asm.sh b/arch/sparc/kernel/check_asm.sh
--- a/arch/sparc/kernel/check_asm.sh	Sun Sep 15 19:20:18 2002
+++ b/arch/sparc/kernel/check_asm.sh	Sun Sep 15 19:20:18 2002
@@ -11,8 +11,7 @@
     echo "	sizeof(struct $2_struct)," >> $4
   ;;
   -ints)
-    sed -n -e '/check_asm_data:/,/\.size/p' <$2 | sed -e 's/check_asm_data://' -e 's/\.size.*//' -e 's/\.ident.*//' -e 's/\.long[ 	]\([0-9]*\)/\1,/' >>$3
-  ;;
+    sed -n -e '/check_asm_data:/,/\.size/p' <$2 | sed -e 's/check_asm_data://' -e 's/\.size.*//' -e 's/\.ident.*//' -e 's/\.global.*//' -e 's/\.long[ 	]\([0-9]*\)/\1,/' >>$3  ;;
   *)
     exit 1
   ;;
diff -Nru a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
--- a/arch/sparc/kernel/ebus.c	Sun Sep 15 19:20:24 2002
+++ b/arch/sparc/kernel/ebus.c	Sun Sep 15 19:20:24 2002
@@ -24,8 +24,6 @@
 
 struct linux_ebus *ebus_chain = 0;
 
-extern void rs_init(void);
-
 /* We are together with pcic.c under CONFIG_PCI. */
 extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
 
@@ -361,6 +359,4 @@
 		ebus->next = 0;
 		++num_ebus;
 	}
-
-	rs_init();
 }
diff -Nru a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
--- a/arch/sparc/kernel/entry.S	Sun Sep 15 19:19:39 2002
+++ b/arch/sparc/kernel/entry.S	Sun Sep 15 19:19:39 2002
@@ -53,6 +53,7 @@
 	.text
 	.align	4
 
+#if 0 /* kgdb is dropped from 2.5.33 */
 ! This function is called when any SPARC trap (except window overflow or
 ! underflow) occurs.  It makes sure that the invalid register window is still
 ! available before jumping into C code.  It will also restore the world if you
@@ -119,7 +120,7 @@
 	STORE_PT_PRIV(sp, l0, l1, l2)
 
 	RESTORE_ALL
-
+#endif
 
 #ifdef CONFIG_BLK_DEV_FD
 	.text
diff -Nru a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
--- a/arch/sparc/kernel/init_task.c	Sun Sep 15 19:19:52 2002
+++ b/arch/sparc/kernel/init_task.c	Sun Sep 15 19:19:52 2002
@@ -7,7 +7,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 struct task_struct init_task = INIT_TASK(init_task);
 
diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
--- a/arch/sparc/kernel/pcic.c	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc/kernel/pcic.c	Sun Sep 15 19:19:28 2002
@@ -1,5 +1,5 @@
-/* $Id: pcic.c,v 1.23 2002/01/23 14:33:55 davem Exp $
- * pcic.c: Sparc/PCI controller support
+/*
+ * pcic.c: MicroSPARC-IIep PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
  *
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 
 #include <asm/ebus.h>
 #include <asm/sbus.h> /* for sanity check... */
@@ -193,48 +194,26 @@
 
 #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
 
-static int pcic_read_config(struct pci_bus *bus, unsigned int devfn,
-			    int where, int size, u32 *value)
+static int pcic_read_config_dword(unsigned int busno, unsigned int devfn,
+    int where, u32 *value)
 {
-	unsigned int v;
-	unsigned char busnum = bus->number;
 	struct linux_pcic *pcic;
 	unsigned long flags;
-	/* unsigned char where; */
 
-	switch (size) {
-	case 1:
-		pcic_read_config(bus, devfn, where&~3, 4, &v);
-		*value = 0xff & (v >> (8*(where & 3)));
-		return PCIBIOS_SUCCESSFUL;
-		break;
-
-	case 2:
-		if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
-
-		pcic_read_config(bus, devfn, where&~3, 4, &v);
-		*value = 0xffff & (v >> (8*(where & 3)));
-		return PCIBIOS_SUCCESSFUL;
-		break;
-	}
-
-	/* size == 4, i.e. dword */
-	if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (busnum != 0) return PCIBIOS_DEVICE_NOT_FOUND;
 	pcic = &pcic0;
 
-	save_and_cli(flags);
+	local_irq_save(flags);
 #if 0 /* does not fail here */
 	pcic_speculative = 1;
 	pcic_trapped = 0;
 #endif
-	writel(CONFIG_CMD(busnum,devfn,where), pcic->pcic_config_space_addr);
+	writel(CONFIG_CMD(busno, devfn, where), pcic->pcic_config_space_addr);
 #if 0 /* does not fail here */
 	nop();
 	if (pcic_trapped) {
-		restore_flags(flags);
+		local_irq_restore(flags);
 		*value = ~0;
-		return PCIBIOS_SUCCESSFUL;
+		return 0;
 	}
 #endif
 	pcic_speculative = 2;
@@ -243,50 +222,77 @@
 	nop();
 	if (pcic_trapped) {
 		pcic_speculative = 0;
-		restore_flags(flags);
+		local_irq_restore(flags);
 		*value = ~0;
-		return PCIBIOS_SUCCESSFUL;
+		return 0;
 	}
 	pcic_speculative = 0;
-	restore_flags(flags);
-	return PCIBIOS_SUCCESSFUL;
+	local_irq_restore(flags);
+	return 0;
 }
 
-static int pcic_write_config(struct pci_bus *bus, unsigned int devfn,
-			     int where, int size, u32 value)
+static int pcic_read_config(struct pci_bus *bus, unsigned int devfn,
+   int where, int size, u32 *val)
 {
 	unsigned int v;
-	unsigned char busnum = bus->number;
-	struct linux_pcic *pcic;
-	unsigned long flags;
 
+	if (bus->number != 0) return -EINVAL;
 	switch (size) {
 	case 1:
-		pcic_read_config(bus, devfn, where&~3, 4, &v);
-	        v = (v & ~(0xff << (8*(where&3)))) |
-	            ((0xff&(unsigned)value) << (8*(where&3)));
-		return pcic_write_config(bus, devfn, where&~3, 4, v);
-		break;
-
+		pcic_read_config_dword(bus->number, devfn, where&~3, &v);
+		*val = 0xff & (v >> (8*(where & 3)));
+		return 0;
 	case 2:
-		if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
-		pcic_read_config(bus, devfn, where&~3, 4, &v);
-		v = (v & ~(0xffff << (8*(where&3)))) |
-		    ((0xffff&(unsigned)value) << (8*(where&3)));
-		return pcic_write_config(bus, devfn, where&~3, 4, v);
-		break;
+		if (where&1) return -EINVAL;
+		pcic_read_config_dword(bus->number, devfn, where&~3, &v);
+		*val = 0xffff & (v >> (8*(where & 3)));
+		return 0;
+	case 4:
+		if (where&3) return -EINVAL;
+		pcic_read_config_dword(bus->number, devfn, where&~3, val);
+		return 0;
 	}
+	return -EINVAL;
+}
+
+static int pcic_write_config_dword(unsigned int busno, unsigned int devfn,
+    int where, u32 value)
+{
+	struct linux_pcic *pcic;
+	unsigned long flags;
 
-	/* size == 4, i.e. dword */
-	if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
-	if (busnum != 0) return PCIBIOS_DEVICE_NOT_FOUND;
 	pcic = &pcic0;
 
-	save_and_cli(flags);
-	writel(CONFIG_CMD(busnum,devfn,where), pcic->pcic_config_space_addr);
+	local_irq_save(flags);
+	writel(CONFIG_CMD(busno, devfn, where), pcic->pcic_config_space_addr);
 	writel(value, pcic->pcic_config_space_data + (where&4));
-	restore_flags(flags);
-	return PCIBIOS_SUCCESSFUL;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int pcic_write_config(struct pci_bus *bus, unsigned int devfn,
+   int where, int size, u32 val)
+{
+	unsigned int v;
+
+	if (bus->number != 0) return -EINVAL;
+	switch (size) {
+	case 1:
+		pcic_read_config_dword(bus->number, devfn, where&~3, &v);
+		v = (v & ~(0xff << (8*(where&3)))) |
+		    ((0xff&val) << (8*(where&3)));
+		return pcic_write_config_dword(bus->number, devfn, where&~3, v);
+	case 2:
+		if (where&1) return -EINVAL;
+		pcic_read_config_dword(bus->number, devfn, where&~3, &v);
+		v = (v & ~(0xffff << (8*(where&3)))) |
+		    ((0xffff&val) << (8*(where&3)));
+		return pcic_write_config_dword(bus->number, devfn, where&~3, v);
+	case 4:
+		if (where&3) return -EINVAL;
+		return pcic_write_config_dword(bus->number, devfn, where, val);
+	}
+	return -EINVAL;
 }
 
 static struct pci_ops pcic_ops = {
@@ -420,7 +426,7 @@
 /*
  * Main entry point from the PCI subsystem.
  */
-static int __init pcibios_init(void)
+static int __init pcic_init(void)
 {
 	struct linux_pcic *pcic;
 
@@ -623,7 +629,7 @@
 {
 	struct list_head *walk;
 	int i, has_io, has_mem;
-	unsigned short cmd;
+	unsigned int cmd;
 	struct linux_pcic *pcic;
 	/* struct linux_pbm_info* pbm = &pcic->pbm; */
 	int node;
@@ -663,19 +669,21 @@
 			} else if (f & IORESOURCE_MEM)
 				has_mem = 1;
 		}
-		pcic_read_config_word(dev, PCI_COMMAND, &cmd);
+		pcic_read_config(dev->bus, dev->devfn, PCI_COMMAND, 2, &cmd);
 		if (has_io && !(cmd & PCI_COMMAND_IO)) {
 			printk("PCIC: Enabling I/O for device %02x:%02x\n",
 				dev->bus->number, dev->devfn);
 			cmd |= PCI_COMMAND_IO;
-			pcic_write_config_word(dev, PCI_COMMAND, cmd);
+			pcic_write_config(dev->bus, dev->devfn,
+			    PCI_COMMAND, 2, cmd);
 		}
 		if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
 			printk("PCIC: Enabling memory for device %02x:%02x\n",
 				dev->bus->number, dev->devfn);
 			cmd |= PCI_COMMAND_MEMORY;
-			pcic_write_config_word(dev, PCI_COMMAND, cmd);
-		}    
+			pcic_write_config(dev->bus, dev->devfn,
+			    PCI_COMMAND, 2, cmd);
+		}
 
 		node = pdev_to_pnode(&pcic->pbm, dev);
 		if(node == 0)
@@ -785,46 +793,54 @@
 	return offset + count;
 }
 
-extern volatile unsigned long wall_jiffies;
+extern unsigned long wall_jiffies;
+extern rwlock_t xtime_lock;
 
 static void pci_do_gettimeofday(struct timeval *tv)
 {
- 	unsigned long flags;
-
-	save_and_cli(flags);
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
+	unsigned long flags;
+	unsigned long usec, sec;
 
-	/*
-	 * xtime is atomically updated in timer_bh. The difference
-	 * between jiffies and wall_jiffies is nonzero if the timer
-	 * bottom half hasnt executed yet.
-	 */
-	if ((jiffies - wall_jiffies) != 0)
-		tv->tv_usec += USECS_PER_JIFFY;
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += (xtime.tv_nsec / 1000);
+	read_unlock_irqrestore(&xtime_lock, flags);
 
-	restore_flags(flags);
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
 
-	if (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}       
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 static void pci_do_settimeofday(struct timeval *tv)
 {
-	cli();
+	/*
+	 * This is revolting. We need to set "xtime" correctly. However, the
+	 * value in this location is the value at the most recent update of
+	 * wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
 	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
+	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = (tv->tv_usec * 1000);
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
 }
 
 #if 0
@@ -853,7 +869,7 @@
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
@@ -898,9 +914,9 @@
 	unsigned long mask, flags;
 
 	mask = get_irqmask(irq_nr);
-	save_and_cli(flags);
+	local_irq_save(flags);
 	writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 static void pcic_enable_irq(unsigned int irq_nr)
@@ -908,9 +924,9 @@
 	unsigned long mask, flags;
 
 	mask = get_irqmask(irq_nr);
-	save_and_cli(flags);
+	local_irq_save(flags);
 	writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 static void pcic_clear_profile_irq(int cpu)
@@ -1021,4 +1037,4 @@
 
 #endif
 
-subsys_initcall(pcibios_init);
+subsys_initcall(pcic_init);
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Sun Sep 15 19:19:29 2002
+++ b/arch/sparc/kernel/process.c	Sun Sep 15 19:19:29 2002
@@ -94,7 +94,7 @@
 			extern unsigned long sun4c_kernel_faults;
 			extern void sun4c_grow_kernel_ring(void);
 
-			save_and_cli(flags);
+			local_irq_save(flags);
 			now = jiffies;
 			count -= (now - last_jiffies);
 			last_jiffies = now;
@@ -110,7 +110,7 @@
 					sun4c_grow_kernel_ring();
 				}
 			}
-			restore_flags(flags);
+			local_irq_restore(flags);
 		}
 
 		while((!need_resched()) && pm_idle) {
@@ -143,8 +143,6 @@
 #endif
 
 extern char reboot_command [];
-
-extern int serial_console;
 
 extern void (*prom_palette)(int);
 
diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc/kernel/setup.c	Sun Sep 15 19:19:28 2002
@@ -34,7 +34,6 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/kgdb.h>
 #include <asm/processor.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
@@ -67,8 +66,6 @@
  */
 
 extern unsigned long trapbase;
-extern int serial_console;
-extern void breakpoint(void);
 void (*prom_palette)(int);
 asmlinkage void sys_sync(void);	/* it's really int */
 
@@ -105,28 +102,15 @@
 	return;
 }
 
-extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
-
 unsigned int boot_flags __initdata = 0;
 #define BOOTME_DEBUG  0x1
 #define BOOTME_SINGLE 0x2
-#define BOOTME_KGDBA  0x4
-#define BOOTME_KGDBB  0x8
-#define BOOTME_KGDB   0xc
 
 static int console_fb __initdata = 0;
 
 /* Exported for mm/init.c:paging_init. */
 unsigned long cmdline_memory_size __initdata = 0;
 
-void kernel_enter_debugger(void)
-{
-	if (boot_flags & BOOTME_KGDB) {
-		printk("KGDB: Entered\n");
-		breakpoint();
-	}
-}
-
 static void
 prom_console_write(struct console *con, const char *s, unsigned n)
 {
@@ -142,11 +126,6 @@
 
 int obp_system_intr(void)
 {
-	if (boot_flags & BOOTME_KGDB) {
-		printk("KGDB: system interrupted\n");
-		breakpoint();
-		return 1;
-	}
 	if (boot_flags & BOOTME_DEBUG) {
 		printk("OBP: system interrupted\n");
 		prom_halt();
@@ -196,24 +175,6 @@
 			commands++;
 			while (*commands && *commands != ' ')
 				process_switch(*commands++);
-		} else if (strlen(commands) >= 9
-			   && !strncmp(commands, "kgdb=tty", 8)) {
-			switch (commands[8]) {
-#ifdef CONFIG_SUN_SERIAL
-			case 'a':
-				boot_flags |= BOOTME_KGDBA;
-				prom_printf("KGDB: Using serial line /dev/ttya.\n");
-				break;
-			case 'b':
-				boot_flags |= BOOTME_KGDBB;
-				prom_printf("KGDB: Using serial line /dev/ttyb.\n");
-				break;
-#endif
-			default:
-				printk("KGDB: Unknown tty line.\n");
-				break;
-			}
-			commands += 9;
 		} else {
 			if (!strncmp(commands, "console=", 8)) {
 				commands += 8;
@@ -378,65 +339,48 @@
 
 	prom_setsync(prom_sync_me);
 
-	{
-#if !CONFIG_SUN_SERIAL
-		serial_console = 0;
+#ifndef CONFIG_SERIAL_CONSOLE	/* Not CONFIG_SERIAL_SUNCORE: to be gone. */
+	serial_console = 0;
 #else
-		switch (console_fb) {
-		case 0: /* Let get our io devices from prom */
-			{
-				int idev = prom_query_input_device();
-				int odev = prom_query_output_device();
-				if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-					serial_console = 0;
-				} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-					serial_console = 1;
-				} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-					serial_console = 2;
-				} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-					prom_printf("MrCoffee ttya\n");
-					serial_console = 1;
-				} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-					serial_console = 0;
-					prom_printf("MrCoffee keyboard\n");
-				} else {
-					prom_printf("Inconsistent or unknown console\n");
-					prom_printf("You cannot mix serial and non serial input/output devices\n");
-					prom_halt();
-				}
+	switch (console_fb) {
+	case 0: /* Let get our io devices from prom */
+		{
+			int idev = prom_query_input_device();
+			int odev = prom_query_output_device();
+			if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+				serial_console = 0;
+			} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+				serial_console = 1;
+			} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+				serial_console = 2;
+			} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
+				prom_printf("MrCoffee ttya\n");
+				serial_console = 1;
+			} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
+				serial_console = 0;
+				prom_printf("MrCoffee keyboard\n");
+			} else {
+				prom_printf("Inconsistent or unknown console\n");
+				prom_printf("You cannot mix serial and non serial input/output devices\n");
+				prom_halt();
 			}
-			break;
-		case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
-		case 2: serial_console = 1; break; /* Force ttya as console */
-		case 3: serial_console = 2; break; /* Force ttyb as console */
 		}
-#endif
-	}
-
-	if ((boot_flags & BOOTME_KGDBA)) {
-		rs_kgdb_hook(0);
-	}
-	if ((boot_flags & BOOTME_KGDBB)) {
-		rs_kgdb_hook(1);
+		break;
+	case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
+	case 2: serial_console = 1; break; /* Force ttya as console */
+	case 3: serial_console = 2; break; /* Force ttyb as console */
 	}
+#endif
 
 	if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
 	   ((*(short *)linux_dbvec) != -1)) {
 		printk("Booted under KADB. Syncing trap table.\n");
 		(*(linux_dbvec->teach_debugger))();
 	}
-	if((boot_flags & BOOTME_KGDB)) {
-		set_debug_traps();
-		prom_printf ("Breakpoint!\n");
-		breakpoint();
-	}
 
 	init_mm.context = (unsigned long) NO_CONTEXT;
 	init_task.thread.kregs = &fake_swapper_regs;
 
-	if (serial_console)
-		conswitchp = NULL;
-
 	paging_init();
 }
 
@@ -514,3 +458,19 @@
 	.stop =	c_stop,
 	.show =	show_cpuinfo,
 };
+
+extern int stop_a_enabled;
+
+void sun_do_break(void)
+{
+	if (!stop_a_enabled)
+		return;
+
+	printk("\n");
+	flush_user_windows();
+
+	prom_cmdline();
+}
+
+int serial_console;
+int stop_a_enabled = 1;
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Sun Sep 15 19:20:05 2002
+++ b/arch/sparc/kernel/signal.c	Sun Sep 15 19:20:05 2002
@@ -38,11 +38,6 @@
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
 			 unsigned long orig_o0, int restart_syscall);
 
-/* This turned off for production... */
-/* #define DEBUG_SIGNALS 1 */
-/* #define DEBUG_SIGNALS_TRACE 1 */
-/* #define DEBUG_SIGNALS_MAPS 1 */
-
 /* Signal frames: the original one (compatible with SunOS):
  *
  * Set up a signal frame... Make the stack look the way SunOS
@@ -470,12 +465,6 @@
 	synchronize_user_stack();
 	sframep = (struct signal_sframe *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
 	if (invalid_frame_pointer (sframep, sizeof(*sframep))){
-#ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
-		printk("%s [%d]: User has trashed signal stack\n",
-		       current->comm, current->pid);
-		printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
-		       sframep, pc, signr);
-#endif
 		/* Don't change signal code and address, so that
 		 * post mortem debuggers can have a look.
 		 */
@@ -635,13 +624,8 @@
 	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill_and_return;
 
-	if (current->thread.w_saved != 0) {
-#ifdef DEBUG_SIGNALS 
-		printk ("%s [%d]: Invalid user stack frame for "
-			"signal delivery.\n", current->comm, current->pid);
-#endif
+	if (current->thread.w_saved != 0)
 		goto sigill_and_return;
-	}
 
 	/* 2. Save the current process state */
 	err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
@@ -795,12 +779,8 @@
 	synchronize_user_stack();
 	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, SVR4_SF_ALIGNED + REGWIN_SZ);
 
-	if (invalid_frame_pointer (sfp, sizeof (*sfp))){
-#ifdef DEBUG_SIGNALS
-		printk ("Invalid stack frame\n");
-#endif
+	if (invalid_frame_pointer (sfp, sizeof (*sfp)))
 		goto sigill_and_return;
-	}
 
 	/* Start with a clean frame pointer and fill it */
 	err = __clear_user(sfp, sizeof (*sfp));
@@ -883,9 +863,6 @@
 	regs->pc = (unsigned long) sa->sa_handler;
 	regs->npc = (regs->pc + 4);
 
-#ifdef DEBUG_SIGNALS
-	printk ("Solaris-frame: %x %x\n", (int) regs->pc, (int) regs->npc);
-#endif
 	/* Arguments passed to signal handler */
 	if (regs->u_regs [14]){
 		struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
@@ -1090,61 +1067,6 @@
 	}
 }
 
-#ifdef DEBUG_SIGNALS_MAPS
-
-#define MAPS_LINE_FORMAT	  "%08lx-%08lx %s %08lx %02x:%02x %lu "
-
-static inline void read_maps (void)
-{
-	struct vm_area_struct * map, * next;
-	char * buffer;
-	ssize_t i;
-
-	buffer = (char*)__get_free_page(GFP_KERNEL);
-	if (!buffer)
-		return;
-
-	for (map = current->mm->mmap ; map ; map = next ) {
-		/* produce the next line */
-		char *line;
-		char str[5], *cp = str;
-		int flags;
-		dev_t dev;
-		unsigned long ino;
-
-		/*
-		 * Get the next vma now (but it won't be used if we sleep).
-		 */
-		next = map->vm_next;
-		flags = map->vm_flags;
-
-		*cp++ = flags & VM_READ ? 'r' : '-';
-		*cp++ = flags & VM_WRITE ? 'w' : '-';
-		*cp++ = flags & VM_EXEC ? 'x' : '-';
-		*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
-		*cp++ = 0;
-
-		dev = 0;
-		ino = 0;
-		if (map->vm_file != NULL) {
-			dev = map->vm_file->f_dentry->d_inode->i_dev;
-			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry,
-				      map->vm_file->f_vfsmnt,
-				      buffer, PAGE_SIZE);
-		}
-		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      MAJOR(dev), MINOR(dev), ino);
-		if (map->vm_file != NULL)
-			printk("%s\n", line);
-		else
-			printk("\n");
-	}
-	free_page((unsigned long)buffer);
-	return;
-}
-#endif
-
 /* Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
@@ -1152,7 +1074,6 @@
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
 			 unsigned long orig_i0, int restart_syscall)
 {
-	unsigned long signr;
 	struct k_sigaction *ka;
 	siginfo_t info;
 
@@ -1171,9 +1092,21 @@
 		oldset = &current->blocked;
 
 	for (;;) {
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
+		sigset_t *mask = &current->blocked;
+		unsigned long signr = 0;
+
+		local_irq_disable();
+		if (current->sig->shared_pending.head) {
+			spin_lock(&current->sig->siglock);
+			signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
+			spin_unlock(&current->sig->siglock);
+		}
+		if (!signr) {
+			spin_lock(&current->sigmask_lock);
+			signr = dequeue_signal(&current->pending, mask, &info);
+			spin_unlock(&current->sigmask_lock);
+		}
+		local_irq_enable();
 
 		if (!signr)
 			break;
@@ -1193,7 +1126,7 @@
 				restart_syscall = 0;
 			}
 			current->exit_code = signr;
-			current->state = TASK_STOPPED;
+			set_current_state(TASK_STOPPED);
 
 			/* This happens to be SMP safe so no need to
 			 * grab master kernel lock even in this case.
@@ -1254,52 +1187,27 @@
 				if (is_orphaned_pgrp(current->pgrp))
 					continue;
 
-			case SIGSTOP:
-				if (current->ptrace & PT_PTRACED)
-					continue;
-				current->state = TASK_STOPPED;
+			case SIGSTOP: {
+				struct signal_struct *sig;
+				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
-
-				/* notify_parent() is SMP safe */
-				if(!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags &
-				     SA_NOCLDSTOP))
+				sig = current->parent->sig;
+				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
+				      SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
+			}
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
 			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
 				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-#ifdef DEBUG_SIGNALS
-				/* Very useful to debug dynamic linker problems */
-				printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
-				show_regs (regs);
-#ifdef DEBUG_SIGNALS_TRACE
-				{
-					struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
-					unsigned int ins[8];
-
-					while (rw &&
-					       !(((unsigned long) rw) & 0x3)) {
-						copy_from_user(ins, &rw->ins[0], sizeof(ins));
-						printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
-						rw = (struct reg_window *)(unsigned long)ins[6];
-					}
-				}
-#endif
-#ifdef DEBUG_SIGNALS_MAPS
-				printk("Maps:\n");
-				read_maps();
-#endif
-#endif
-				/* fall through */
+				/* FALLTHRU */
+
 			default:
-				sigaddset(&current->pending.signal, signr);
-				recalc_sigpending();
-				current->flags |= PF_SIGNALED;
-				do_exit(exit_code);
+				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
 			}
 		}
diff -Nru a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c
--- a/arch/sparc/kernel/sparc-stub.c	Sun Sep 15 19:19:34 2002
+++ b/arch/sparc/kernel/sparc-stub.c	Sun Sep 15 19:19:34 2002
@@ -188,22 +188,16 @@
 /* Initialize the kgdb_savettable so that debugging can commence */
 static void eh_init(void)
 {
-	int i, flags;
+	int i;
 
-	save_and_cli(flags);
 	for(i=0; i < 256; i++)
 		copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]);
-	restore_flags(flags);
 }
 
 /* Install an exception handler for kgdb */
 static void exceptionHandler(int tnum, trapfunc_t trap_entry)
 {
 	unsigned long te_addr = (unsigned long) trap_entry;
-	int flags;
-
-	/* We are dorking with a live trap table, all irqs off */
-	save_and_cli(flags);
 
 	/* Make new vector */
 	sparc_ttable[tnum].inst_one =
@@ -212,8 +206,6 @@
 	sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0;
 	sparc_ttable[tnum].inst_three = SPARC_NOP;
 	sparc_ttable[tnum].inst_four = SPARC_NOP;
-
-	restore_flags(flags);
 }
 
 /* Convert ch from a hex digit to an int */
@@ -406,7 +398,7 @@
 	struct hard_trap_info *ht;
 	unsigned long flags;
 
-	save_and_cli(flags);
+	local_irq_save(flags);
 #if 0	
 /* Have to sort this out. This cannot be done after initialization. */
 	BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
@@ -438,7 +430,7 @@
 #endif
 
 	initialized = 1; /* connect! */
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 /* Convert the SPARC hardware trap type code to a unix signal number. */
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Sun Sep 15 19:19:46 2002
+++ b/arch/sparc/kernel/systbls.S	Sun Sep 15 19:19:46 2002
@@ -55,7 +55,7 @@
 /*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
 /*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
-/*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sys_newuname
+/*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
diff -Nru a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
--- a/arch/sparc/kernel/tadpole.c	Sun Sep 15 19:19:29 2002
+++ b/arch/sparc/kernel/tadpole.c	Sun Sep 15 19:19:29 2002
@@ -56,6 +56,9 @@
 			     "g2", "g3", "g4", "g5");
 }
 
+/*
+ * Tadpole is guaranteed to be UP, using local_irq_save.
+ */
 static void tsu_clockstop(void)
 {
 	unsigned int mcsr;
@@ -64,28 +67,28 @@
 	if (!clk_ctrl)
 		return;
 	if (!(clk_state & CLOCK_INIT_DONE)) {
-		save_and_cli(flags);
+		local_irq_save(flags);
 		clk_init();
 		clk_state |= CLOCK_INIT_DONE;       /* all done */
-		restore_flags(flags);
+		local_irq_restore(flags);
 		return;
 	}
 	if (!(clk_ctrl[2] & 1))
 		return;               /* no speed up yet */
 
-	save_and_cli(flags);
+	local_irq_save(flags);
 
 	/* if SCSI DMA in progress, don't slow clock */
 	mcsr = ldphys(MACIO_SCSI_CSR_ADDR);
 	if ((mcsr&MACIO_EN_DMA) != 0) {
-		restore_flags(flags);
+		local_irq_restore(flags);
 		return;
 	}
 	/* TODO... the minimum clock setting ought to increase the
 	 * memory refresh interval..
 	 */
 	clk_slow();
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
 
 static void swift_clockstop(void)
diff -Nru a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
--- a/arch/sparc/kernel/tick14.c	Sun Sep 15 19:19:37 2002
+++ b/arch/sparc/kernel/tick14.c	Sun Sep 15 19:19:37 2002
@@ -29,32 +29,30 @@
 static unsigned long *linux_lvl14 = NULL;
 static unsigned long obp_lvl14[4];
  
+/*
+ * Call with timer IRQ closed.
+ * First time we do it with disable_irq, later prom code uses spin_lock_irq().
+ */
 void install_linux_ticker(void)
 {
-	unsigned long flags;
 
 	if (!linux_lvl14)
 		return;
-	save_and_cli(flags);
 	linux_lvl14[0] =  lvl14_save[0];
 	linux_lvl14[1] =  lvl14_save[1];
 	linux_lvl14[2] =  lvl14_save[2];
 	linux_lvl14[3] =  lvl14_save[3];
-	restore_flags(flags);
 }
 
 void install_obp_ticker(void)
 {
-	unsigned long flags;
-    
+
 	if (!linux_lvl14)
 		return;
-	save_and_cli(flags);
 	linux_lvl14[0] =  obp_lvl14[0];
 	linux_lvl14[1] =  obp_lvl14[1];
 	linux_lvl14[2] =  obp_lvl14[2];
 	linux_lvl14[3] =  obp_lvl14[3]; 
-	restore_flags(flags);
 }
 
 void claim_ticker14(void (*handler)(int, void *, struct pt_regs *),
diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
--- a/arch/sparc/kernel/time.c	Sun Sep 15 19:19:50 2002
+++ b/arch/sparc/kernel/time.c	Sun Sep 15 19:19:50 2002
@@ -43,6 +43,8 @@
 
 extern rwlock_t xtime_lock;
 
+extern unsigned long wall_jiffies;
+
 u64 jiffies_64;
 
 enum sparc_clock_type sp_clock_typ;
@@ -114,6 +116,9 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
+
+#define TICK_SIZE (tick_nsec / 1000)
+
 void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
@@ -142,8 +147,8 @@
 	/* Determine when to update the Mostek clock. */
 	if ((time_status & STA_UNSYNC) == 0 &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
+	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
 	  if (set_rtc_mmss(xtime.tv_sec) == 0)
 	    last_rtc_update = xtime.tv_sec;
 	  else
@@ -400,7 +405,7 @@
 	mon = MSTK_REG_MONTH(mregs);
 	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 	mregs->creg &= ~MSTK_CREG_READ;
 	spin_unlock_irq(&mostek_lock);
 #ifdef CONFIG_SUN4
@@ -431,7 +436,7 @@
 		intersil_start(iregs);
 
 		xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
 		printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
 	}
 #endif
@@ -467,48 +472,33 @@
 	return offset + count;
 }
 
-/* This need not obtain the xtime_lock as it is coded in
- * an implicitly SMP safe way already.
+/* Ok, my cute asm atomicity trick doesn't work anymore.
+ * There are just too many variables that need to be protected
+ * now (both members of xtime, wall_jiffies, et al.)
  */
 void do_gettimeofday(struct timeval *tv)
 {
-	/* Load doubles must be used on xtime so that what we get
-	 * is guarenteed to be atomic, this is why we can run this
-	 * with interrupts on full blast.  Don't touch this... -DaveM
-	 */
-	__asm__ __volatile__(
-	"sethi	%hi(master_l10_counter), %o1\n\t"
-	"ld	[%o1 + %lo(master_l10_counter)], %g3\n\t"
-	"sethi	%hi(xtime), %g2\n"
-	"1:\n\t"
-	"ldd	[%g2 + %lo(xtime)], %o4\n\t"
-	"ld	[%g3], %o1\n\t"
-	"ldd	[%g2 + %lo(xtime)], %o2\n\t"
-	"xor	%o4, %o2, %o2\n\t"
-	"xor	%o5, %o3, %o3\n\t"
-	"orcc	%o2, %o3, %g0\n\t"
-	"bne	1b\n\t"
-	" cmp	%o1, 0\n\t"
-	"bge	1f\n\t"
-	" srl	%o1, 0xa, %o1\n\t"
-	"sethi	%hi(tick), %o3\n\t"
-	"ld	[%o3 + %lo(tick)], %o3\n\t"
-	"sethi	%hi(0x1fffff), %o2\n\t"
-	"or	%o2, %lo(0x1fffff), %o2\n\t"
-	"add	%o5, %o3, %o5\n\t"
-	"and	%o1, %o2, %o1\n"
-	"1:\n\t"
-	"add	%o5, %o1, %o5\n\t"
-	"sethi	%hi(1000000), %o2\n\t"
-	"or	%o2, %lo(1000000), %o2\n\t"
-	"cmp	%o5, %o2\n\t"
-	"bl,a	1f\n\t"
-	" st	%o4, [%o0 + 0x0]\n\t"
-	"add	%o4, 0x1, %o4\n\t"
-	"sub	%o5, %o2, %o5\n\t"
-	"st	%o4, [%o0 + 0x0]\n"
-	"1:\n\t"
-	"st	%o5, [%o0 + 0x4]\n");
+	unsigned long flags;
+	unsigned long usec, sec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += (xtime.tv_nsec / 1000);
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
@@ -520,12 +510,20 @@
 
 static void sbus_do_settimeofday(struct timeval *tv)
 {
+	/*
+	 * This is revolting. We need to set "xtime" correctly. However, the
+	 * value in this location is the value at the most recent update of
+	 * wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
 	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
+	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = (tv->tv_usec * 1000);
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
diff -Nru a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
--- a/arch/sparc/kernel/unaligned.c	Sun Sep 15 19:19:29 2002
+++ b/arch/sparc/kernel/unaligned.c	Sun Sep 15 19:19:29 2002
@@ -506,9 +506,18 @@
 			break;
 
 		case both:
+#if 0 /* unsupported */
 			do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
 				  (unsigned long *) addr,
 				  user_unaligned_trap_fault);
+#else
+			/*
+			 * This was supported in 2.4. However, we question
+			 * the value of SWAP instruction across word boundaries.
+			 */
+			printk("Unaligned SWAP unsupported.\n");
+			goto kill_user;
+#endif
 			break;
 
 		default:
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Sun Sep 15 19:19:50 2002
+++ b/arch/sparc/mm/srmmu.c	Sun Sep 15 19:19:50 2002
@@ -1212,7 +1212,6 @@
 void (*poke_srmmu)(void) __initdata = NULL;
 
 extern unsigned long bootmem_init(unsigned long *pages_avail);
-extern void sun_serial_setup(void);
 
 void __init srmmu_paging_init(void)
 {
@@ -1280,13 +1279,6 @@
 
 	flush_cache_all();
 	flush_tlb_all();
-
-	/*
-	 * This does not logically belong here, but we need to
-	 * call it at the moment we are able to use the bootmem
-	 * allocator.
-	 */
-	sun_serial_setup();
 
 	sparc_context_init(num_contexts);
 
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Sun Sep 15 19:19:29 2002
+++ b/arch/sparc/mm/sun4c.c	Sun Sep 15 19:19:29 2002
@@ -2001,7 +2001,6 @@
 extern unsigned long end;
 extern unsigned long bootmem_init(unsigned long *pages_avail);
 extern unsigned long last_valid_pfn;
-extern void sun_serial_setup(void);
 
 void __init sun4c_paging_init(void)
 {
@@ -2017,12 +2016,6 @@
 	pages_avail = 0;
 	last_valid_pfn = bootmem_init(&pages_avail);
 	end_pfn = last_valid_pfn;
-
-	/* This does not logically belong here, but we need to
-	 * call it at the moment we are able to use the bootmem
-	 * allocator.
-	 */
-	sun_serial_setup();
 
 	sun4c_probe_mmu();
 	invalid_segment = (num_segmaps - 1);
diff -Nru a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
--- a/arch/sparc/prom/misc.c	Sun Sep 15 19:20:18 2002
+++ b/arch/sparc/prom/misc.c	Sun Sep 15 19:20:18 2002
@@ -12,6 +12,7 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
+#include <asm/system.h>
 
 extern void restore_current(void);
 
@@ -47,7 +48,6 @@
 
 /* We want to do this more nicely some day. */
 extern void (*prom_palette)(int);
-extern int serial_console;
 
 /* Drop into the prom, with the chance to continue with the 'go'
  * prom command.
@@ -55,20 +55,18 @@
 void
 prom_cmdline(void)
 {
-	extern void kernel_enter_debugger(void);
 	extern void install_obp_ticker(void);
 	extern void install_linux_ticker(void);
 	unsigned long flags;
-    
-	kernel_enter_debugger();
+
 	if(!serial_console && prom_palette)
 		prom_palette (1);
-	install_obp_ticker();
 	spin_lock_irqsave(&prom_lock, flags);
+	install_obp_ticker();
 	(*(romvec->pv_abort))();
 	restore_current();
-	spin_unlock_irqrestore(&prom_lock, flags);
 	install_linux_ticker();
+	spin_unlock_irqrestore(&prom_lock, flags);
 #ifdef CONFIG_SUN_AUXIO
 	TURN_ON_LED;
 #endif
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Sun Sep 15 19:19:30 2002
+++ b/arch/sparc64/defconfig	Sun Sep 15 19:19:30 2002
@@ -204,6 +204,8 @@
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
@@ -218,7 +220,7 @@
 # CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDECD_BAILOUT is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
@@ -229,8 +231,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -239,29 +241,29 @@
 CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_ADMA100 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -954,7 +956,7 @@
 CONFIG_USB_RIO500=m
 # CONFIG_USB_BRLVGER is not set
 CONFIG_USB_LCD=m
-CONFIG_USB_SPEEDTOUCH=m
+# CONFIG_USB_SPEEDTOUCH is not set
 
 #
 # Bluetooth support
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc64/kernel/entry.S	Sun Sep 15 19:19:28 2002
@@ -1795,69 +1795,3 @@
 	 restore	%g0, %g0, %g0
 2:	retl
 	 nop
-
-/* This need not obtain the xtime_lock as it is coded in
- * an implicitly SMP safe way already.
- */
-	.align		64
-	.globl		do_gettimeofday
-do_gettimeofday:	/* %o0 = timevalp */
-	/* Load doubles must be used on xtime so that what we get
-	 * is guarenteed to be atomic, this is why we can run this
-	 * with interrupts on full blast.  Don't touch this... -DaveM
-	 *
-	 * Note with time_t changes to the timeval type, I must now use
-	 * nucleus atomic quad 128-bit loads.
-	 *
-	 * If xtime was stored recently, I've seen crap from the
-	 * quad load on Cheetah.  Putting a membar SYNC before
-	 * the quad load seems to make the problem go away. -DaveM
-	 * (we should nop out workarounds like this on spitfire)
-	 */
-	sethi	%hi(timer_tick_offset), %g3
-	sethi	%hi(xtime), %g2
-	sethi	%hi(timer_tick_compare), %g1
-	ldx	[%g3 + %lo(timer_tick_offset)], %g3
-	or	%g2, %lo(xtime), %g2
-	or	%g1, %lo(timer_tick_compare), %g1
-1:	membar	#Sync
-	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o4
-	BRANCH_IF_ANY_CHEETAH(o2,o1,2f)
-	ba,pt	%xcc, 3f
-	 rd	%tick, %o1
-2:	ba,pt	%xcc, 3f
-	 rd	%asr24, %o1
-3:	ldx	[%g1], %g7
-	membar	#Sync
-	ldda	[%g2] ASI_NUCLEUS_QUAD_LDD, %o2
-	xor	%o4, %o2, %o2
-	xor	%o5, %o3, %o3
-	orcc	%o2, %o3, %g0
-	bne,pn	%xcc, 1b
-	 sethi	%hi(wall_jiffies), %o2
-	sethi	%hi(jiffies), %o3
-	ldx	[%o2 + %lo(wall_jiffies)], %o2
-	ldx	[%o3 + %lo(jiffies)], %o3
-	sub	%o3, %o2, %o2
-	sethi	%hi(timer_ticks_per_usec_quotient), %o3
-	add	%g3, %o1, %o1
-	ldx	[%o3 + %lo(timer_ticks_per_usec_quotient)], %o3
-	sub	%o1, %g7, %o1
-	mulx	%o3, %o1, %o1
-	brz,pt	%o2, 1f
-	 srlx	%o1, 32, %o1
-	sethi	%hi(10000), %g2
-	or	%g2, %lo(10000), %g2
-	add	%o1, %g2, %o1
-1:	sethi	%hi(1000000), %o2
-	srlx	%o5, 32, %o5
-	or	%o2, %lo(1000000), %o2
-	add	%o5, %o1, %o5
-	cmp	%o5, %o2
-	bl,a,pn	%xcc, 1f
-	 stx	%o4, [%o0 + 0x0]
-	add	%o4, 0x1, %o4
-	sub	%o5, %o2, %o5
-	stx	%o4, [%o0 + 0x0]
-1:	retl
-	 st	%o5, [%o0 + 0x8]
diff -Nru a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
--- a/arch/sparc64/kernel/init_task.c	Sun Sep 15 19:20:24 2002
+++ b/arch/sparc64/kernel/init_task.c	Sun Sep 15 19:20:24 2002
@@ -8,7 +8,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /* .text section in head.S is aligned at 2 page boundry and this gets linked
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc64/kernel/pci.c	Sun Sep 15 19:19:28 2002
@@ -365,7 +365,7 @@
 {
 }
 
-int pcibios_enable_device(struct pci_dev *pdev)
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
 {
 	return 0;
 }
diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
--- a/arch/sparc64/kernel/power.c	Sun Sep 15 19:20:23 2002
+++ b/arch/sparc64/kernel/power.c	Sun Sep 15 19:20:23 2002
@@ -11,6 +11,7 @@
 #include <linux/signal.h>
 #include <linux/delay.h>
 
+#include <asm/system.h>
 #include <asm/ebus.h>
 
 #define __KERNEL_SYSCALLS__
@@ -36,8 +37,6 @@
 extern void machine_halt(void);
 extern void machine_alt_power_off(void);
 static void (*poweroff_method)(void) = machine_alt_power_off;
-
-extern int serial_console;
 
 void machine_power_off(void)
 {
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Sun Sep 15 19:19:37 2002
+++ b/arch/sparc64/kernel/process.c	Sun Sep 15 19:19:37 2002
@@ -110,7 +110,6 @@
 extern char reboot_command [];
 
 extern void (*prom_palette)(int);
-extern int serial_console;
 extern void (*prom_keyboard)(void);
 
 void machine_halt(void)
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Sun Sep 15 19:19:30 2002
+++ b/arch/sparc64/kernel/setup.c	Sun Sep 15 19:19:30 2002
@@ -314,12 +314,9 @@
 	return 0;
 }
 
-extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
-
 unsigned int boot_flags = 0;
 #define BOOTME_DEBUG  0x1
 #define BOOTME_SINGLE 0x2
-#define BOOTME_KGDB   0x4
 
 static int console_fb __initdata = 0;
 
@@ -389,26 +386,6 @@
 			commands++;
 			while (*commands && *commands != ' ')
 				process_switch(*commands++);
-		} else if (strlen(commands) >= 9
-			   && !strncmp(commands, "kgdb=tty", 8)) {
-			boot_flags |= BOOTME_KGDB;
-			switch (commands[8]) {
-#ifdef CONFIG_SUN_SERIAL
-			case 'a':
-				rs_kgdb_hook(0);
-				prom_printf("KGDB: Using serial line /dev/ttya.\n");
-				break;
-			case 'b':
-				rs_kgdb_hook(1);
-				prom_printf("KGDB: Using serial line /dev/ttyb.\n");
-				break;
-#endif
-			default:
-				printk("KGDB: Unknown tty line.\n");
-				boot_flags &= ~BOOTME_KGDB;
-				break;
-			}
-			commands += 9;
 		} else {
 			if (!strncmp(commands, "console=", 8)) {
 				commands += 8;
@@ -484,7 +461,6 @@
 
 void __init setup_arch(char **cmdline_p)
 {
-	extern int serial_console;  /* in console.c, of course */
 	unsigned long highest_paddr;
 	int i;
 
@@ -568,7 +544,6 @@
 	}
 #endif
 
-#ifdef CONFIG_SUN_SERIAL
 	switch (console_fb) {
 	case 0: /* Let's get our io devices from prom */
 		{
@@ -597,10 +572,7 @@
 	case 3: /* Force ttyb as console */
 		serial_console = 2;
 		break;
-	}
-#else
-	serial_console = 0;
-#endif
+	};
 	if (serial_console)
 		conswitchp = NULL;
 
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Sun Sep 15 19:19:50 2002
+++ b/arch/sparc64/kernel/signal.c	Sun Sep 15 19:19:50 2002
@@ -36,11 +36,6 @@
 static int do_signal(sigset_t *oldset, struct pt_regs * regs,
 		     unsigned long orig_o0, int ret_from_syscall);
 
-/* This turned off for production... */
-/* #define DEBUG_SIGNALS 1 */
-/* #define DEBUG_SIGNALS_TRACE 1 */
-/* #define DEBUG_SIGNALS_MAPS 1 */
-
 int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
@@ -535,13 +530,8 @@
 	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill;
 
-	if (get_thread_wsaved() != 0) {
-#ifdef DEBUG_SIGNALS
-		printk ("%s[%d]: Invalid user stack frame for "
-			"signal delivery.\n", current->comm, current->pid);
-#endif
+	if (get_thread_wsaved() != 0)
 		goto sigill;
-	}
 
 	/* 2. Save the current process state */
 	err = copy_to_user(&sf->regs, regs, sizeof (*regs));
@@ -631,62 +621,6 @@
 	}
 }
 
-#ifdef DEBUG_SIGNALS_MAPS
-
-#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %02x:%02x %lu "
-
-static inline void read_maps (void)
-{
-	struct vm_area_struct * map, * next;
-	char * buffer;
-	ssize_t i;
-
-	buffer = (char*)__get_free_page(GFP_KERNEL);
-	if (!buffer)
-		return;
-
-	for (map = current->mm->mmap ; map ; map = next ) {
-		/* produce the next line */
-		char *line;
-		char str[5], *cp = str;
-		int flags;
-		dev_t dev;
-		unsigned long ino;
-
-		/*
-		 * Get the next vma now (but it won't be used if we sleep).
-		 */
-		next = map->vm_next;
-		flags = map->vm_flags;
-
-		*cp++ = flags & VM_READ ? 'r' : '-';
-		*cp++ = flags & VM_WRITE ? 'w' : '-';
-		*cp++ = flags & VM_EXEC ? 'x' : '-';
-		*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
-		*cp++ = 0;
-
-		dev = 0;
-		ino = 0;
-		if (map->vm_file != NULL) {
-			dev = map->vm_file->f_dentry->d_inode->i_dev;
-			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry,
-				      map->vm_file->f_vfsmnt,
-				      buffer, PAGE_SIZE);
-		}
-		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      MAJOR(dev), MINOR(dev), ino);
-		if (map->vm_file != NULL)
-			printk("%s\n", line);
-		else
-			printk("\n");
-	}
-	free_page((unsigned long)buffer);
-	return;
-}
-
-#endif
-
 /* Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
@@ -694,7 +628,6 @@
 static int do_signal(sigset_t *oldset, struct pt_regs * regs,
 		     unsigned long orig_i0, int restart_syscall)
 {
-	unsigned long signr;
 	siginfo_t info;
 	struct k_sigaction *ka;
 	
@@ -709,9 +642,21 @@
 	}
 #endif	
 	for (;;) {
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
+		sigset_t *mask = &current->blocked;
+		unsigned long signr = 0;
+
+		local_irq_disable();
+		if (current->sig->shared_pending.head) {
+			spin_lock(&current->sig->siglock);
+			signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
+			spin_unlock(&current->sig->siglock);
+		}
+		if (!signr) {
+			spin_lock(&current->sigmask_lock);
+			signr = dequeue_signal(&current->pending, mask, &info);
+			spin_unlock(&current->sigmask_lock);
+		}
+		local_irq_enable();
 		
 		if (!signr)
 			break;
@@ -732,7 +677,7 @@
 			}
 
 			current->exit_code = signr;
-			current->state = TASK_STOPPED;
+			set_current_state(TASK_STOPPED);
 			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
@@ -787,8 +732,7 @@
 
 			case SIGSTOP: {
 				struct signal_struct *sig;
-
-				current->state = TASK_STOPPED;
+				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
 				sig = current->parent->sig;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
@@ -803,29 +747,8 @@
 			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
 				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-#ifdef DEBUG_SIGNALS
-				/* Very useful to debug the dynamic linker */
-				printk ("Sig %d going...\n", (int)signr);
-				show_regs (regs);
-#ifdef DEBUG_SIGNALS_TRACE
-				{
-					struct reg_window *rw = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
-					unsigned long ins[8];
-                                                
-					while (rw &&
-					       !(((unsigned long) rw) & 0x3)) {
-					        copy_from_user(ins, &rw->ins[0], sizeof(ins));
-						printk("Caller[%016lx](%016lx,%016lx,%016lx,%016lx,%016lx,%016lx)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
-						rw = (struct reg_window *)(unsigned long)(ins[6] + STACK_BIAS);
-					}
-				}
-#endif			
-#ifdef DEBUG_SIGNALS_MAPS	
-				printk("Maps:\n");
-				read_maps();
-#endif
-#endif
-				/* fall through */
+				/* FALLTHRU */
+
 			default:
 				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Sun Sep 15 19:19:28 2002
+++ b/arch/sparc64/kernel/signal32.c	Sun Sep 15 19:19:28 2002
@@ -34,12 +34,6 @@
 int do_signal32(sigset_t *oldset, struct pt_regs *regs,
 		unsigned long orig_o0, int ret_from_syscall);
 
-/* This turned off for production... */
-/* #define DEBUG_SIGNALS 1 */
-/* #define DEBUG_SIGNALS_TRACE 1 */
-/* #define DEBUG_SIGNALS_MAPS 1 */
-/* #define DEBUG_SIGNALS_TLB 1 */
-
 /* Signal frames: the original one (compatible with SunOS):
  *
  * Set up a signal frame... Make the stack look the way SunOS
@@ -525,12 +519,6 @@
 
 	sframep = (struct signal_sframe32 *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
 	if (invalid_frame_pointer (sframep, sizeof(*sframep))){
-#ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
-		printk("%s [%d]: User has trashed signal stack\n",
-		       current->comm, current->pid);
-		printk("Sigstack ptr %p handler at pc<%016lx> for sig<%d>\n",
-		       sframep, pc, signr);
-#endif
 		/* Don't change signal code and address, so that
 		 * post mortem debuggers can have a look.
 		 */
@@ -696,21 +684,11 @@
 
 	sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
 	
-	if (invalid_frame_pointer (sf, sigframe_size)) {
-#ifdef DEBUG_SIGNALS
-		printk("new_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n",
-		       current->comm, current->pid, sf, sigframe_size);
-#endif
+	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill;
-	}
 
-	if (get_thread_wsaved() != 0) {
-#ifdef DEBUG_SIGNALS
-		printk ("%s[%d]: Invalid user stack frame for "
-			"signal delivery.\n", current->comm, current->pid);
-#endif
+	if (get_thread_wsaved() != 0)
 		goto sigill;
-	}
 
 	/* 2. Save the current process state */
 	if (test_thread_flag(TIF_32BIT)) {
@@ -835,12 +813,8 @@
 	regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
 	sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, REGWIN_SZ + SVR4_SF_ALIGNED);
 
-	if (invalid_frame_pointer (sfp, sizeof (*sfp))){
-#ifdef DEBUG_SIGNALS
-		printk ("Invalid stack frame\n");
-#endif
+	if (invalid_frame_pointer (sfp, sizeof (*sfp)))
 		do_exit(SIGILL);
-	}
 
 	/* Start with a clean frame pointer and fill it */
 	err = clear_user(sfp, sizeof (*sfp));
@@ -939,9 +913,6 @@
 		regs->tnpc &= 0xffffffff;
 	}
 
-#ifdef DEBUG_SIGNALS
-	printk ("Solaris-frame: %x %x\n", (int) regs->tpc, (int) regs->tnpc);
-#endif
 	/* Arguments passed to signal handler */
 	if (regs->u_regs [14]){
 		struct reg_window32 *rw = (struct reg_window32 *)
@@ -975,12 +946,9 @@
 	synchronize_user_stack();
 	save_and_clear_fpu();
 	
-	if (get_thread_wsaved()) {
-#ifdef DEBUG_SIGNALS
-		printk ("Uh oh, w_saved is not zero (%d)\n", (int) get_thread_wsaved());
-#endif
+	if (get_thread_wsaved())
 		do_exit (SIGSEGV);
-	}
+
 	err = clear_user(uc, sizeof (*uc));
 
 	/* Setup convenience variables */
@@ -1047,12 +1015,9 @@
 	 */
 	flush_user_windows();
 	
-	if (get_thread_wsaved()) {
-#ifdef DEBUG_SIGNALS	
-		printk ("Uh oh, w_saved is: 0x%x\n", get_thread_wsaved());
-#endif
+	if (get_thread_wsaved())
 		goto sigsegv;
-	}
+
 	if (((unsigned long) c) & 3){
 		printk ("Unaligned structure passed\n");
 		goto sigsegv;
@@ -1067,12 +1032,8 @@
 	gr = &c->mcontext.greg;
 	err = __get_user(pc, &((*gr)[SVR4_PC]));
 	err |= __get_user(npc, &((*gr)[SVR4_NPC]));
-	if ((pc | npc) & 3) {
-#ifdef DEBUG_SIGNALS	
-	        printk ("setcontext, PC or nPC were bogus\n");
-#endif
+	if ((pc | npc) & 3)
 		goto sigsegv;
-	}
 	
 	/* Retrieve information from passed ucontext */
 	/* note that nPC is ored a 1, this is used to inform entry.S */
@@ -1148,21 +1109,11 @@
 
 	sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size);
 	
-	if (invalid_frame_pointer (sf, sigframe_size)) {
-#ifdef DEBUG_SIGNALS
-		printk("rt_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n",
-		       current->comm, current->pid, sf, sigframe_size);
-#endif
+	if (invalid_frame_pointer (sf, sigframe_size))
 		goto sigill;
-	}
 
-	if (get_thread_wsaved() != 0) {
-#ifdef DEBUG_SIGNALS
-		printk ("%s[%d]: Invalid user stack frame for "
-			"signal delivery.\n", current->comm, current->pid);
-#endif
+	if (get_thread_wsaved() != 0)
 		goto sigill;
-	}
 
 	/* 2. Save the current process state */
 	if (test_thread_flag(TIF_32BIT)) {
@@ -1317,62 +1268,6 @@
 	}
 }
 
-#ifdef DEBUG_SIGNALS_MAPS
-
-#define MAPS_LINE_FORMAT	  "%016lx-%016lx %s %016lx %02x:%02x %lu "
-
-static inline void read_maps (void)
-{
-	struct vm_area_struct * map, * next;
-	char * buffer;
-	ssize_t i;
-
-	buffer = (char*)__get_free_page(GFP_KERNEL);
-	if (!buffer)
-		return;
-
-	for (map = current->mm->mmap ; map ; map = next ) {
-		/* produce the next line */
-		char *line;
-		char str[5], *cp = str;
-		int flags;
-		dev_t dev;
-		unsigned long ino;
-
-		/*
-		 * Get the next vma now (but it won't be used if we sleep).
-		 */
-		next = map->vm_next;
-		flags = map->vm_flags;
-
-		*cp++ = flags & VM_READ ? 'r' : '-';
-		*cp++ = flags & VM_WRITE ? 'w' : '-';
-		*cp++ = flags & VM_EXEC ? 'x' : '-';
-		*cp++ = flags & VM_MAYSHARE ? 's' : 'p';
-		*cp++ = 0;
-
-		dev = 0;
-		ino = 0;
-		if (map->vm_file != NULL) {
-			dev = map->vm_file->f_dentry->d_inode->i_dev;
-			ino = map->vm_file->f_dentry->d_inode->i_ino;
-			line = d_path(map->vm_file->f_dentry,
-				      map->vm_file->f_vfsmnt,
-				      buffer, PAGE_SIZE);
-		}
-		printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-			      MAJOR(dev), MINOR(dev), ino);
-		if (map->vm_file != NULL)
-			printk("%s\n", line);
-		else
-			printk("\n");
-	}
-	free_page((unsigned long)buffer);
-	return;
-}
-
-#endif
-
 /* Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
@@ -1380,16 +1275,27 @@
 int do_signal32(sigset_t *oldset, struct pt_regs * regs,
 		unsigned long orig_i0, int restart_syscall)
 {
-	unsigned long signr;
 	struct k_sigaction *ka;
 	siginfo_t info;
 	
 	int svr4_signal = current->personality == PER_SVR4;
 	
 	for (;;) {
-		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq(&current->sigmask_lock);
+		sigset_t *mask = &current->blocked;
+		unsigned long signr = 0;
+
+		local_irq_disable();
+		if (current->sig->shared_pending.head) {
+			spin_lock(&current->sig->siglock);
+			signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
+			spin_unlock(&current->sig->siglock);
+		}
+		if (!signr) {
+			spin_lock(&current->sigmask_lock);
+			signr = dequeue_signal(&current->pending, mask, &info);
+			spin_unlock(&current->sigmask_lock);
+		}
+		local_irq_enable();
 		
 		if (!signr)
 			break;
@@ -1410,7 +1316,7 @@
 			}
 
 			current->exit_code = signr;
-			current->state = TASK_STOPPED;
+			set_current_state(TASK_STOPPED);
 			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
@@ -1465,8 +1371,7 @@
 
 			case SIGSTOP: {
 				struct signal_struct *sig;
-
-				current->state = TASK_STOPPED;
+				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
 				sig = current->parent->sig;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
@@ -1480,40 +1385,8 @@
 			case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
 				if (do_coredump(signr, regs))
 					exit_code |= 0x80;
-#ifdef DEBUG_SIGNALS
-				/* Very useful to debug dynamic linker problems */
-				printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
-				/* On SMP we are only interested in the current
-				 * CPU's registers.
-				 */
-				__show_regs (regs);
-#ifdef DEBUG_SIGNALS_TLB
-				do {
-					extern void sparc_ultra_dump_itlb(void);
-					extern void sparc_ultra_dump_dtlb(void);
-					sparc_ultra_dump_dtlb();
-					sparc_ultra_dump_itlb();
-				} while (0);
-#endif
-#ifdef DEBUG_SIGNALS_TRACE
-				{
-					struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
-					unsigned int ins[8];
-
-					while (rw &&
-					       !(((unsigned long) rw) & 0x3)) {
-						copy_from_user(ins, &rw->ins[0], sizeof(ins));
-						printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
-						rw = (struct reg_window32 *)(unsigned long)ins[6];
-					}
-				}
-#endif			
-#ifdef DEBUG_SIGNALS_MAPS	
-				printk("Maps:\n");
-				read_maps();
-#endif
-#endif
-				/* fall through */
+				/* FALLTHRU */
+
 			default:
 				sig_exit(signr, exit_code, &info);
 				/* NOT REACHED */
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Sun Sep 15 19:19:56 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Sun Sep 15 19:19:56 2002
@@ -1921,30 +1921,42 @@
 			return -EINVAL;
 	}
 
-	spin_lock_irq(&current->sigmask_lock);
-	sig = dequeue_signal(&these, &info);
+	spin_lock_irq(&current->sig->siglock);
+	spin_lock(&current->sigmask_lock);
+	sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
+	if (!sig)
+		sig = dequeue_signal(&current->pending, &these, &info);
 	if (!sig) {
-		/* None ready -- temporarily unblock those we're interested
-		   in so that we'll be awakened when they arrive.  */
-		sigset_t oldblocked = current->blocked;
-		sigandsets(&current->blocked, &current->blocked, &these);
-		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
-
 		timeout = MAX_SCHEDULE_TIMEOUT;
 		if (uts)
 			timeout = (timespec_to_jiffies(&ts)
 				   + (ts.tv_sec || ts.tv_nsec));
 
-		current->state = TASK_INTERRUPTIBLE;
-		timeout = schedule_timeout(timeout);
+		if (timeout) {
+			/* None ready -- temporarily unblock those we're
+			 * interested while we are sleeping in so that we'll
+			 * be awakened when they arrive.  */
+			current->real_blocked = current->blocked;
+			sigandsets(&current->blocked, &current->blocked, &these);
+			recalc_sigpending();
+			spin_unlock(&current->sigmask_lock);
+			spin_unlock_irq(&current->sig->siglock);
+
+			current->state = TASK_INTERRUPTIBLE;
+			timeout = schedule_timeout(timeout);
 
-		spin_lock_irq(&current->sigmask_lock);
-		sig = dequeue_signal(&these, &info);
-		current->blocked = oldblocked;
-		recalc_sigpending();
+			spin_lock_irq(&current->sig->siglock);
+			spin_lock(&current->sigmask_lock);
+			sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
+			if (!sig)
+				sig = dequeue_signal(&current->pending, &these, &info);
+			current->blocked = current->real_blocked;
+			siginitset(&current->real_blocked, 0);
+			recalc_sigpending();
+		}
 	}
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (sig) {
 		ret = sig;
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Sun Sep 15 19:19:37 2002
+++ b/arch/sparc64/kernel/systbls.S	Sun Sep 15 19:19:37 2002
@@ -56,7 +56,7 @@
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
@@ -115,7 +115,7 @@
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Sun Sep 15 19:19:46 2002
+++ b/arch/sparc64/kernel/time.c	Sun Sep 15 19:19:46 2002
@@ -44,6 +44,8 @@
 unsigned long ds1287_regs = 0UL;
 #endif
 
+extern unsigned long wall_jiffies;
+
 u64 jiffies_64;
 
 static unsigned long mstk48t08_regs = 0UL;
@@ -61,6 +63,8 @@
 unsigned long timer_tick_compare;
 unsigned long timer_ticks_per_usec_quotient;
 
+#define TICK_SIZE (tick_nsec / 1000)
+
 static __inline__ void timer_check_rtc(void)
 {
 	/* last time the cmos clock got updated */
@@ -69,8 +73,8 @@
 	/* Determine when to update the Mostek clock. */
 	if ((time_status & STA_UNSYNC) == 0 &&
 	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
+	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
 		if (set_rtc_mmss(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
@@ -390,7 +394,7 @@
 	}
 
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 
 	if (mregs) {
 		tmp = mostek_read(mregs + MOSTEK_CREG);
@@ -428,7 +432,7 @@
 			(unsigned int) (long) &unix_tod);
 		prom_feval(obp_gettod);
 		xtime.tv_sec = unix_tod;
-		xtime.tv_usec = 0;
+		xtime.tv_nsec = 0;
 		return;
 	}
 
@@ -658,20 +662,56 @@
 		return;
 
 	write_lock_irq(&xtime_lock);
-
+	/*
+	 * This is revolting. We need to set "xtime" correctly. However, the
+	 * value in this location is the value at the most recent update of
+	 * wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
 	tv->tv_usec -= do_gettimeoffset();
-	if(tv->tv_usec < 0) {
+	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
 
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = (tv->tv_usec * 1000);
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-
 	write_unlock_irq(&xtime_lock);
+}
+
+/* Ok, my cute asm atomicity trick doesn't work anymore.
+ * There are just too many variables that need to be protected
+ * now (both members of xtime, wall_jiffies, et al.)
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long usec, sec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += (xtime.tv_nsec / 1000);
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 static int set_rtc_mmss(unsigned long nowtime)
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Sun Sep 15 19:19:34 2002
+++ b/arch/sparc64/mm/init.c	Sun Sep 15 19:19:34 2002
@@ -1515,14 +1515,6 @@
 	pages_avail = 0;
 	last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
 
-#ifdef CONFIG_SUN_SERIAL
-	/* This does not logically belong here, but we need to
-	 * call it at the moment we are able to use the bootmem
-	 * allocator.
-	 */
-	sun_serial_setup();
-#endif
-
 	/* Inherit non-locked OBP mappings. */
 	inherit_prom_mappings();
 	
diff -Nru a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
--- a/arch/sparc64/prom/misc.c	Sun Sep 15 19:20:18 2002
+++ b/arch/sparc64/prom/misc.c	Sun Sep 15 19:20:18 2002
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/system.h>
 
 /* Reset and reboot the machine with the command 'bcommand'. */
 void prom_reboot(char *bcommand)
@@ -33,7 +34,6 @@
 
 /* We want to do this more nicely some day. */
 extern void (*prom_palette)(int);
-extern int serial_console;
 
 #ifdef CONFIG_SMP
 extern void smp_capture(void);
diff -Nru a/arch/um/Makefile b/arch/um/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/Makefile	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,136 @@
+ARCH_DIR = arch/um
+OS := $(shell uname -s)
+
+include $(ARCH_DIR)/Makefile-$(SUBARCH)
+include $(ARCH_DIR)/Makefile-os-$(OS)
+
+EXTRAVERSION := $(EXTRAVERSION)-1um
+include/linux/version.h: arch/$(ARCH)/Makefile
+
+# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE)
+# The way the toplevel Makefile is written EXTRAVERSION is not supposed
+# to be changed outside the toplevel Makefile, but recalculating MODLIB is
+# a sufficient workaround until we no longer need architecture dependent
+# EXTRAVERSION...
+MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
+
+MAKEBOOT = $(MAKE) -C $(ARCH_DIR)/boot
+
+ifeq ($(CONFIG_DEBUGSYM),y)
+DEBUG = -g
+CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
+endif
+
+ifeq ($(CONFIG_GCOV),y)
+CFLAGS += -fprofile-arcs -ftest-coverage
+endif
+
+ifeq ($(CONFIG_GPROF), y)
+PROFILE += -pg -DPROFILING
+LINK_PROFILE = $(PROFILE) -Wl,--wrap,__monstartup
+endif
+
+ARCH_SUBDIRS = $(ARCH_DIR)/drivers $(ARCH_DIR)/kernel \
+	$(ARCH_DIR)/sys-$(SUBARCH) $(ARCH_DIR)/os-$(OS)
+
+SUBDIRS += $(ARCH_SUBDIRS)
+
+LIBS += $(ARCH_DIR)/kernel/um.o \
+	$(ARCH_DIR)/drivers/drivers.o \
+	$(ARCH_DIR)/sys-$(SUBARCH)/sys.o $(ARCH_DIR)/os/os.o
+
+ifeq ($(CONFIG_PT_PROXY), y)
+SUBDIRS += $(ARCH_DIR)/ptproxy
+LIBS += $(ARCH_DIR)/ptproxy/ptproxy.a
+endif
+
+ARCH_INCLUDE = $(TOPDIR)/$(ARCH_DIR)/include
+
+# -Derrno=kernel_errno - This turns all kernel references to errno into
+# kernel_errno to separate them from the libc errno.  This allows -fno-common
+# in CFLAGS.  Otherwise, it would cause ld to complain about the two different
+# errnos.
+
+CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \
+	-DSUBARCH=\"$(SUBARCH)\" -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) \
+	-Derrno=kernel_errno
+
+LDFLAGS += -r
+
+LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
+
+SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
+
+$(ARCH_DIR)/link.ld: $(ARCH_DIR)/link.ld.in
+	m4 -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
+		-DELF_FORMAT=$(ELF_FORMAT) $< > $@
+
+SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
+	include/asm-um/sigcontext.h include/asm-um/processor.h \
+	include/asm-um/ptrace.h include/asm-um/arch-signal.h
+
+ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \
+	$(SYMLINK_HEADERS)
+
+GEN_HEADERS = $(ARCH_DIR)/include/task.h
+
+linux: scripts $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) $(ARCH_DIR)/main.o \
+	vmlinux $(ARCH_DIR)/link.ld
+	mv vmlinux vmlinux.o
+	$(CC) -Wl,-T,$(ARCH_DIR)/link.ld $(LINK_PROFILE) $(LINK_WRAPS) \
+		-o linux -static $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib -lutil
+
+USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
+USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
+
+# To get a definition of F_SETSIG
+USER_CFLAGS += -D_GNU_SOURCE
+
+$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+archmrproper:
+	for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
+	do \
+		$(MAKE) -C $$d archmrproper; \
+	done
+	rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \
+		$(ARCH_DIR)/link.ld \
+		$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS))
+
+archclean: sysclean
+	for d in $(ARCH_SUBDIRS) $(ARCH_DIR)/util; \
+	do \
+		$(MAKE) -C $$d clean; \
+	done
+	find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \
+		-o -name '*.gcov' \) -type f -print | xargs rm -f
+	rm -f linux x.i gmon.out $(ARCH_DIR)/link.ld $(GEN_HEADERS)
+	@$(MAKEBOOT) clean
+
+archdep: 
+	for d in $(ARCH_SUBDIRS); do $(MAKE) -C $$d fastdep; done
+	@$(MAKEBOOT) dep
+
+$(SYMLINK_HEADERS):
+	cd $(TOPDIR)/$(dir $@) ; \
+	ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@)
+
+include/asm-um/arch:
+	cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch
+
+arch/um/include/sysdep:
+	cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep
+
+arch/um/os:
+	cd $(ARCH_DIR) && ln -sf os-$(OS) os
+
+$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
+	$< > $@
+
+$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
+	$(ARCH_DIR)/util/mk_task_kern.c 
+	$(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util all
+
+export SUBARCH USER_CFLAGS OS
diff -Nru a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/Makefile-i386	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,34 @@
+ifeq ($(CONFIG_HOST_2G_2G), y)
+TOP_ADDR = 0x80000000
+else
+TOP_ADDR = 0xc0000000
+endif
+
+ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH)
+ELF_ARCH = $(SUBARCH)
+ELF_FORMAT = elf32-$(SUBARCH)
+
+
+SYS_HEADERS = $(ARCH_DIR)/include/sysdep-i386/sc.h \
+	$(ARCH_DIR)/include/sysdep-i386/thread.h
+
+$(ARCH_DIR)/include/sysdep-i386/sc.h : $(ARCH_DIR)/sys-i386/util/mk_sc \
+	include/asm
+	$(ARCH_DIR)/sys-i386/util/mk_sc > $@
+
+$(ARCH_DIR)/include/sysdep-i386/thread.h : $(ARCH_DIR)/sys-i386/util/mk_thread\
+	include/asm
+	$(ARCH_DIR)/sys-i386/util/mk_thread > $@
+
+$(ARCH_DIR)/sys-i386/util/mk_sc : $(ARCH_DIR)/sys-i386/util/mk_sc.c \
+	include/asm
+	$(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_sc
+
+$(ARCH_DIR)/sys-i386/util/mk_thread : \
+	$(ARCH_DIR)/sys-i386/util/mk_thread_user.c \
+	$(ARCH_DIR)/sys-i386/util/mk_thread_kern.c
+	$(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_thread
+
+sysclean :
+	rm -f $(SYS_HEADERS)
+	make -C $(ARCH_DIR)/sys-i386/util clean
diff -Nru a/arch/um/Makefile-ia64 b/arch/um/Makefile-ia64
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/Makefile-ia64	Sun Sep 15 19:20:24 2002
@@ -0,0 +1 @@
+START_ADDR = 0x1000000000000000
diff -Nru a/arch/um/Makefile-os-Linux b/arch/um/Makefile-os-Linux
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/Makefile-os-Linux	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,7 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers
+LIBS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o
diff -Nru a/arch/um/Makefile-ppc b/arch/um/Makefile-ppc
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/Makefile-ppc	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,9 @@
+ifeq ($(CONFIG_HOST_2G_2G), y)
+START_ADDR = 0x80000000
+else
+START_ADDR = 0xc0000000
+endif
+ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__
+
+# The arch is ppc, but the elf32 name is powerpc
+ELF_SUBARCH = powerpc
diff -Nru a/arch/um/boot/Makefile b/arch/um/boot/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/boot/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,3 @@
+dep:
+
+clean:
diff -Nru a/arch/um/config.in b/arch/um/config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config.in	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,87 @@
+define_bool CONFIG_USERMODE y
+
+mainmenu_name "Linux/Usermode Kernel Configuration"
+
+define_bool CONFIG_ISA n
+define_bool CONFIG_SBUS n
+define_bool CONFIG_PCI n
+
+define_bool CONFIG_UID16 y
+
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'General Setup'
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+tristate 'Host filesystem' CONFIG_HOSTFS
+bool 'Management console' CONFIG_MCONSOLE
+dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
+bool '2G/2G host address space split' CONFIG_HOST_2G_2G
+bool 'Symmetric multi-processing support' CONFIG_UML_SMP
+define_bool CONFIG_SMP $CONFIG_UML_SMP
+int 'Nesting level' CONFIG_NEST_LEVEL 0
+int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+# MODVERSIONS does not yet work in this architecture
+#   bool '  Set version information on all module symbols' CONFIG_MODVERSIONS
+    bool '  Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+source arch/um/config_char.in
+
+source arch/um/config_block.in
+
+define_bool CONFIG_NETDEVICES $CONFIG_NET
+
+if [ "$CONFIG_NET" = "y" ]; then
+   source arch/um/config_net.in
+   source net/Config.in
+fi
+
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   # This gives us free_dma, which scsi.c wants.
+   define_bool CONFIG_GENERIC_ISA_DMA y
+   source arch/um/config_scsi.in
+fi
+endmenu
+
+source drivers/md/Config.in
+
+source drivers/mtd/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+bool 'Debug memory allocations' CONFIG_DEBUG_SLAB
+bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM
+if [ "$CONFIG_XTERM_CHAN" = "y" ]; then
+   dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM
+else 
+   define_bool CONFIG_PT_PROXY n
+fi
+dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM
+dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM
+endmenu
diff -Nru a/arch/um/config.release b/arch/um/config.release
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config.release	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,335 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_USERMODE=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General Setup
+#
+CONFIG_STDIO_CONSOLE=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_SSL=y
+CONFIG_HOSTFS=y
+CONFIG_MCONSOLE=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_HOST_2G_2G is not set
+# CONFIG_UML_SMP is not set
+# CONFIG_SMP is not set
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CON_CHAN="xterm"
+CONFIG_SSL_CHAN="pty"
+CONFIG_NEST_LEVEL=0
+CONFIG_KERNEL_HALF_GIGS=1
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_KMOD=y
+
+#
+# Devices
+#
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_MMAPPER is not set
+CONFIG_UML_SOUND=y
+CONFIG_SOUND=y
+CONFIG_HOSTAUDIO=y
+# CONFIG_UML_WATCHDOG is not set
+# CONFIG_TTY_LOG is not set
+CONFIG_FD_CHAN=y
+# CONFIG_NULL_CHAN is not set
+CONFIG_PORT_CHAN=y
+CONFIG_PTY_CHAN=y
+CONFIG_TTY_CHAN=y
+CONFIG_XTERM_CHAN=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_UML_NET=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_TUNTAP=y
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_MCAST=y
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=y
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_UMSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_EFS_FS=m
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=m
+CONFIG_TMPFS=y
+CONFIG_RAMFS=m
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_MINIX_FS=m
+CONFIG_VXFS_FS=m
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+CONFIG_HPFS_FS=m
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+CONFIG_SYSV_FS=m
+CONFIG_UDF_FS=m
+# CONFIG_UDF_RW is not set
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUGSYM is not set
+# CONFIG_PT_PROXY is not set
+# CONFIG_GPROF is not set
+# CONFIG_GCOV is not set
diff -Nru a/arch/um/config_block.in b/arch/um/config_block.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config_block.in	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,16 @@
+mainmenu_option next_comment
+comment 'Block Devices'
+
+bool 'Virtual block device' CONFIG_BLK_DEV_UBD
+dep_bool '  Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+	int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+fi
+dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
+
+tristate 'Example IO memory driver' CONFIG_MMAPPER
+
+endmenu
diff -Nru a/arch/um/config_char.in b/arch/um/config_char.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config_char.in	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,37 @@
+mainmenu_option next_comment
+comment 'Character Devices'
+
+define_bool CONFIG_STDIO_CONSOLE y
+
+bool 'Virtual serial line' CONFIG_SSL
+
+bool 'file descriptor channel support' CONFIG_FD_CHAN
+bool 'null channel support' CONFIG_NULL_CHAN
+bool 'port channel support' CONFIG_PORT_CHAN
+bool 'pty channel support' CONFIG_PTY_CHAN
+bool 'tty channel support' CONFIG_TTY_CHAN
+bool 'xterm channel support' CONFIG_XTERM_CHAN
+string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \
+            "fd:0,fd:1"
+string 'Default console channel initialization' CONFIG_CON_CHAN "xterm"
+string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty"
+
+
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+fi
+
+bool 'Watchdog Timer Support' CONFIG_WATCHDOG
+dep_bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \
+	$CONFIG_WATCHDOG
+dep_tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG
+dep_tristate '  UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG
+
+tristate 'Sound support' CONFIG_UML_SOUND
+define_tristate CONFIG_SOUND $CONFIG_UML_SOUND
+define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND
+
+bool 'Enable tty logging' CONFIG_TTY_LOG
+
+endmenu
diff -Nru a/arch/um/config_net.in b/arch/um/config_net.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config_net.in	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,45 @@
+mainmenu_option next_comment
+comment 'Network Devices'
+
+# UML virtual driver
+bool 'Virtual network device' CONFIG_UML_NET
+
+dep_bool '  Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET
+dep_bool '  TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET
+dep_bool '  SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET
+dep_bool '  Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET
+dep_bool '  Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET
+
+# Below are hardware-independent drivers mirrored from
+# drivers/net/Config.in. It would be nice if Linux
+# had HW independent drivers separated from the other
+# but it does not. Until then each non-ISA/PCI arch
+# needs to provide it's own menu of network drivers
+
+tristate 'Dummy net driver support' CONFIG_DUMMY
+tristate 'Bonding driver support' CONFIG_BONDING
+tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   if [ "$CONFIG_NETLINK" = "y" ]; then
+      tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
+   fi
+fi
+
+tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
+if [ ! "$CONFIG_PPP" = "n" ]; then
+   dep_bool '  PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL
+   dep_bool '  PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER
+   dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+   dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+   dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+   dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
+   dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL
+fi
+
+tristate 'SLIP (serial line) support' CONFIG_SLIP
+dep_bool '  CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP
+dep_bool '  Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP
+dep_bool '  Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP
+
+endmenu
diff -Nru a/arch/um/config_scsi.in b/arch/um/config_scsi.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/config_scsi.in	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,30 @@
+comment 'SCSI support type (disk, tape, CD-ROM)'
+
+dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
+
+if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
+   int  'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
+fi
+
+dep_tristate '  SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+
+dep_tristate '  SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+
+if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
+   bool '    Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+   int  'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2
+fi
+dep_tristate '  SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
+
+comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
+
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   bool '  Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES
+#fi
+
+bool '  Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
+  
+bool '  Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+bool '  SCSI logging facility' CONFIG_SCSI_LOGGING
+
+dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI
diff -Nru a/arch/um/defconfig b/arch/um/defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/defconfig	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,389 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_USERMODE=y
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General Setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_HOSTFS=y
+CONFIG_MCONSOLE=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_HOST_2G_2G is not set
+# CONFIG_UML_SMP is not set
+# CONFIG_SMP is not set
+CONFIG_NEST_LEVEL=0
+CONFIG_KERNEL_HALF_GIGS=1
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_KMOD is not set
+
+#
+# Character Devices
+#
+CONFIG_STDIO_CONSOLE=y
+CONFIG_SSL=y
+CONFIG_FD_CHAN=y
+CONFIG_NULL_CHAN=y
+CONFIG_PORT_CHAN=y
+CONFIG_PTY_CHAN=y
+CONFIG_TTY_CHAN=y
+CONFIG_XTERM_CHAN=y
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CON_CHAN="xterm"
+CONFIG_SSL_CHAN="pty"
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_WATCHDOG is not set
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_UML_WATCHDOG is not set
+CONFIG_UML_SOUND=y
+CONFIG_SOUND=y
+CONFIG_HOSTAUDIO=y
+# CONFIG_TTY_LOG is not set
+
+#
+# Block Devices
+#
+CONFIG_BLK_DEV_UBD=y
+# CONFIG_BLK_DEV_UBD_SYNC is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_MMAPPER is not set
+CONFIG_NETDEVICES=y
+
+#
+# Network Devices
+#
+CONFIG_UML_NET=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_TUNTAP=y
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_MCAST=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_EXPORTFS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_DEBUG=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_GEN_PROBE is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUGSYM=y
+CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
+# CONFIG_GCOV is not set
diff -Nru a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,84 @@
+# 
+# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+O_TARGET := drivers.o 
+
+CHAN_OBJS := chan_kern.o chan_user.o line.o 
+
+list-multi := slip.o daemon.o mcast.o mconsole.o net.o ubd.o hostaudio.o \
+	port.o harddog.o
+
+slip-objs := slip_kern.o slip_user.o
+daemon-objs := daemon_kern.o daemon_user.o
+mcast-objs := mcast_kern.o mcast_user.o
+net-objs := net_kern.o net_user.o
+mconsole-objs := mconsole_kern.o mconsole_user.o
+hostaudio-objs := hostaudio_kern.o hostaudio_user.o
+ubd-objs := ubd_kern.o ubd_user.o
+port-objs := port_kern.o port_user.o
+harddog-objs := harddog_kern.o harddog_user.o
+
+export-objs := mconsole_kern.o
+
+obj-y = 
+obj-$(CONFIG_SSL) += ssl.o 
+obj-$(CONFIG_UML_NET_SLIP) += slip.o
+obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
+obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
+obj-$(CONFIG_UML_NET) += net.o 
+obj-$(CONFIG_MCONSOLE) += mconsole.o
+obj-$(CONFIG_MMAPPER) += mmapper_kern.o 
+obj-$(CONFIG_BLK_DEV_UBD) += ubd.o 
+obj-$(CONFIG_HOSTAUDIO) += hostaudio.o
+obj-$(CONFIG_FD_CHAN) += fd.o 
+obj-$(CONFIG_NULL_CHAN) += null.o 
+obj-$(CONFIG_PORT_CHAN) += port.o
+obj-$(CONFIG_PTY_CHAN) += pty.o
+obj-$(CONFIG_TTY_CHAN) += tty.o 
+obj-$(CONFIG_XTERM_CHAN) += xterm.o
+obj-$(CONFIG_UML_WATCHDOG) += harddog.o
+
+obj-y += stdio_console.o $(CHAN_OBJS)
+
+USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
+
+USER_OBJS = $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
+	null.o pty.o tty.o xterm.o
+
+include $(TOPDIR)/Rules.make
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+clean:
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper:
+
+daemon.o : $(daemon-objs)
+
+slip.o : $(slip-objs)
+
+mcast.o : $(mcast-objs)
+
+mconsole.o : $(mconsole-objs)
+
+net.o : $(net-objs)
+
+hostaudio.o : $(hostaudio-objs)
+
+ubd.o : $(ubd-objs)
+
+port.o : $(port-objs)
+
+harddog.o : $(harddog-objs)
+
+$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
+	$(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs)
diff -Nru a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/chan_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,447 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/irq.h>
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "sigio.h"
+#include "line.h"
+
+static void *not_configged_init(char *str, int device, struct chan_opts *opts)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(NULL);
+}
+
+static int not_configged_open(int input, int output, int primary, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-ENODEV);
+}
+
+static void not_configged_close(int fd, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+}
+
+static int not_configged_read(int fd, char *c_out, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_write(int fd, const char *buf, int len, void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_console_write(int fd, const char *buf, int len,
+				       void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-EIO);
+}
+
+static int not_configged_window_size(int fd, void *data, unsigned short *rows,
+				     unsigned short *cols)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+	return(-ENODEV);
+}
+
+static void not_configged_free(void *data)
+{
+	printk(KERN_ERR "Using a channel type which is configured out of "
+	       "UML\n");
+}
+
+static struct chan_ops not_configged_ops = {
+	init:		not_configged_init,
+	open:		not_configged_open,
+	close:		not_configged_close,
+	read:		not_configged_read,
+	write:		not_configged_write,
+	console_write:	not_configged_console_write,
+	window_size:	not_configged_window_size,
+	free:		not_configged_free,
+	winch:		0,
+};
+
+static void tty_receive_char(struct tty_struct *tty, char ch)
+{
+	if(tty == NULL) return;
+
+	if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
+		if(ch == STOP_CHAR(tty)){
+			stop_tty(tty);
+			return;
+		}
+		else if(ch == START_CHAR(tty)){
+			start_tty(tty);
+			return;
+		}
+	}
+
+	if((tty->flip.flag_buf_ptr == NULL) || 
+	   (tty->flip.char_buf_ptr == NULL))
+		return;
+	tty_insert_flip_char(tty, ch, TTY_NORMAL);
+}
+
+static int open_one_chan(struct chan *chan, int input, int output, int primary)
+{
+	int fd;
+
+	if(chan->opened) return(0);
+	if(chan->ops->open == NULL) fd = 0;
+	else fd = (*chan->ops->open)(input, output, primary, chan->data);
+	if(fd < 0) return(fd);
+	chan->fd = fd;
+
+	chan->opened = 1;
+	return(0);
+}
+
+int open_chan(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int ret, err = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		ret = open_one_chan(chan, chan->input, chan->output,
+				    chan->primary);
+		if(chan->primary) err = ret;
+	}
+	return(err);
+}
+
+void chan_enable_winch(struct list_head *chans, void *line)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary && chan->output && chan->ops->winch){
+			register_winch(chan->fd, line);
+			return;
+		}
+	}
+}
+
+void enable_chan(struct list_head *chans, void *data)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->opened) continue;
+
+		line_setup_irq(chan->fd, chan->input, chan->output, data);
+	}
+}
+
+void close_chan(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	/* Close in reverse order as open in case more than one of them
+	 * refers to the same device and they save and restore that device's
+	 * state.  Then, the first one opened will have the original state,
+	 * so it must be the last closed.
+	 */
+        for(ele = chans->prev; ele != chans; ele = ele->prev){
+                chan = list_entry(ele, struct chan, list);
+		if(!chan->opened) continue;
+		if(chan->ops->close != NULL)
+			(*chan->ops->close)(chan->fd, chan->data);
+		chan->opened = 0;
+		chan->fd = -1;
+	}
+}
+
+int write_chan(struct list_head *chans, const char *buf, int len, 
+	       int write_irq)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int n, ret = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->output || (chan->ops->write == NULL)) continue;
+		n = chan->ops->write(chan->fd, buf, len, chan->data);
+		if(chan->primary){
+			ret = n;
+			if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){
+				reactivate_fd(chan->fd, write_irq);
+				if(ret == -EAGAIN) ret = 0;
+			}
+		}
+	}
+	return(ret);
+}
+
+int console_write_chan(struct list_head *chans, const char *buf, int len)
+{
+	struct list_head *ele;
+	struct chan *chan;
+	int n, ret = 0;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->output || (chan->ops->console_write == NULL))
+			continue;
+		n = chan->ops->console_write(chan->fd, buf, len, chan->data);
+		if(chan->primary) ret = n;
+	}
+	return(ret);
+}
+
+int chan_window_size(struct list_head *chans, unsigned short *rows_out,
+		      unsigned short *cols_out)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary){
+			if(chan->ops->window_size == NULL) return(0);
+			return(chan->ops->window_size(chan->fd, chan->data,
+						      rows_out, cols_out));
+		}
+	}
+	return(0);
+}
+
+void free_one_chan(struct chan *chan)
+{
+	list_del(&chan->list);
+	if(chan->ops->free != NULL)
+		(*chan->ops->free)(chan->data);
+	free_irq_by_fd(chan->fd);
+	if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
+	kfree(chan);
+}
+
+void free_chan(struct list_head *chans)
+{
+	struct list_head *ele, *next;
+	struct chan *chan;
+
+	list_for_each_safe(ele, next, chans){
+		chan = list_entry(ele, struct chan, list);
+		free_one_chan(chan);
+	}
+}
+
+struct chan_type {
+	char *key;
+	struct chan_ops *ops;
+};
+
+struct chan_type chan_table[] = {
+#ifdef CONFIG_FD_CHAN
+	{ "fd", &fd_ops },
+#else
+	{ "fd", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_NULL_CHAN
+	{ "null", &null_ops },
+#else
+	{ "null", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_PORT_CHAN
+	{ "port", &port_ops },
+#else
+	{ "port", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_PTY_CHAN
+	{ "pty", &pty_ops },
+	{ "pts", &pts_ops },
+#else
+	{ "pty", &not_configged_ops },
+	{ "pts", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_TTY_CHAN
+	{ "tty", &tty_ops },
+#else
+	{ "tty", &not_configged_ops },
+#endif
+
+#ifdef CONFIG_XTERM_CHAN
+	{ "xterm", &xterm_ops },
+#else
+	{ "xterm", &not_configged_ops },
+#endif
+};
+
+static struct chan *parse_chan(char *str, int pri, int device, 
+			       struct chan_opts *opts)
+{
+	struct chan_type *entry;
+	struct chan_ops *ops;
+	struct chan *chan;
+	void *data;
+	int i;
+
+	ops = NULL;
+	data = NULL;
+	for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){
+		entry = &chan_table[i];
+		if(!strncmp(str, entry->key, strlen(entry->key))){
+			ops = entry->ops;
+			str += strlen(entry->key);
+			break;
+		}
+	}
+	if(ops == NULL){
+		printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", 
+		       str);
+		return(NULL);
+	}
+	if(ops->init == NULL) return(NULL); 
+	data = (*ops->init)(str, device, opts);
+	if(data == NULL) return(NULL);
+
+	chan = kmalloc(sizeof(*chan), GFP_KERNEL);
+	if(chan == NULL) return(NULL);
+	*chan = ((struct chan) { list :	 	LIST_HEAD_INIT(chan->list),
+				 primary :	1,
+				 input :	0,
+				 output :	0,
+				 opened : 	0,
+				 fd :		-1,
+				 pri :		pri,
+				 ops :		ops,
+				 data :		data });
+	return(chan);
+}
+
+int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
+		    struct chan_opts *opts)
+{
+	struct chan *new, *chan;
+	char *in, *out;
+
+	if(!list_empty(chans)){
+		chan = list_entry(chans->next, struct chan, list);
+		if(chan->pri >= pri) return(0);
+		free_chan(chans);
+		INIT_LIST_HEAD(chans);
+	}
+
+	if((out = strchr(str, ',')) != NULL){
+		in = str;
+		*out = '\0';
+		out++;
+		new = parse_chan(in, pri, device, opts);
+		if(new == NULL) return(-1);
+		new->input = 1;
+		list_add(&new->list, chans);
+
+		new = parse_chan(out, pri, device, opts);
+		if(new == NULL) return(-1);
+		list_add(&new->list, chans);
+		new->output = 1;
+	}
+	else {
+		new = parse_chan(str, pri, device, opts);
+		if(new == NULL) return(-1);
+		list_add(&new->list, chans);
+		new->input = 1;
+		new->output = 1;
+	}
+	return(0);
+}
+
+int chan_out_fd(struct list_head *chans)
+{
+	struct list_head *ele;
+	struct chan *chan;
+
+	list_for_each(ele, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(chan->primary && chan->output)
+			return(chan->fd);
+	}
+	return(-1);
+}
+
+void chan_interrupt(struct list_head *chans, struct tq_struct *task,
+		    struct tty_struct *tty, int irq, void *dev)
+{
+	struct list_head *ele, *next;
+	struct chan *chan;
+	int err;
+	char c;
+
+	list_for_each_safe(ele, next, chans){
+		chan = list_entry(ele, struct chan, list);
+		if(!chan->input || (chan->ops->read == NULL)) continue;
+		do {
+			if((tty != NULL) && 
+			   (tty->flip.count >= TTY_FLIPBUF_SIZE)){
+				queue_task(task, &tq_timer);
+				goto out;
+			}
+			err = chan->ops->read(chan->fd, &c, chan->data);
+			if(err > 0) tty_receive_char(tty, c);
+		} while(err > 0);
+		if(err == 0) reactivate_fd(chan->fd, irq);
+		if(err == -EIO){
+			if(chan->primary){
+				if(tty != NULL) tty_hangup(tty);
+				line_disable(dev, irq);
+				close_chan(chans);
+				free_chan(chans);
+				return;
+			}
+			else {
+				if(chan->ops->close != NULL)
+					chan->ops->close(chan->fd, chan->data);
+				free_one_chan(chan);
+			}
+		}
+	}
+ out:
+	if(tty) tty_flip_buffer_push(tty);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/chan_user.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,236 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include "kern_util.h"
+#include "user_util.h"
+#include "chan_user.h"
+#include "user.h"
+#include "helper.h"
+#include "os.h"
+
+void generic_close(int fd, void *unused)
+{
+	close(fd);
+}
+
+int generic_read(int fd, char *c_out, void *unused)
+{
+	int n;
+
+	n = read(fd, c_out, sizeof(*c_out));
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-EIO);
+	return(1);
+}
+
+int generic_write(int fd, const char *buf, int n, void *unused)
+{
+	int count;
+
+	count = write(fd, buf, n);
+	if(count < 0) return(-errno);
+	return(count);
+}
+
+int generic_console_write(int fd, const char *buf, int n, void *unused)
+{
+	struct termios save, new;
+	int err;
+
+	if(isatty(fd)){
+		tcgetattr(fd, &save);
+		new = save;
+		new.c_oflag |= OPOST;
+		tcsetattr(fd, TCSAFLUSH, &new);
+	}
+	err = generic_write(fd, buf, n, NULL);
+	if(isatty(fd)) tcsetattr(fd, TCSAFLUSH, &save);
+	return(err);
+}
+
+int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+			unsigned short *cols_out)
+{
+	struct winsize size;
+	int ret = 0;
+
+	if(ioctl(fd, TIOCGWINSZ, &size) == 0){
+		ret = ((*rows_out != size.ws_row) || 
+		       (*cols_out != size.ws_col));
+		*rows_out = size.ws_row;
+		*cols_out = size.ws_col;
+	}
+	return(ret);
+}
+
+void generic_free(void *data)
+{
+	kfree(data);
+}
+
+static void winch_handler(int sig)
+{
+}
+
+struct winch_data {
+	int pty_fd;
+	int pipe_fd;
+	int close_me;
+};
+
+static int winch_thread(void *arg)
+{
+	struct winch_data *data = arg;
+	sigset_t sigs;
+	int pty_fd, pipe_fd;
+	char c = 1;
+
+	close(data->close_me);
+	pty_fd = data->pty_fd;
+	pipe_fd = data->pipe_fd;
+	if(write(pipe_fd, &c, sizeof(c)) != sizeof(c))
+		printk("winch_thread : failed to write synchronization "
+		       "byte, errno = %d\n", errno);
+
+	signal(SIGWINCH, winch_handler);
+	sigfillset(&sigs);
+	sigdelset(&sigs, SIGWINCH);
+	if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
+		printk("winch_thread : sigprocmask failed, errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	if(setsid() < 0){
+		printk("winch_thread : setsid failed, errno = %d\n", errno);
+		exit(1);
+	}
+
+	if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){
+		printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if(tcsetpgrp(pty_fd, os_getpid()) < 0){
+		printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
+		exit(1);
+	}
+
+	if(read(pipe_fd, &c, sizeof(c)) != sizeof(c))
+		printk("winch_thread : failed to read synchronization byte, "
+		       "errno = %d\n", errno);
+
+	while(1){
+		pause();
+
+		if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){
+			printk("winch_thread : write failed, errno = %d\n",
+			       errno);
+		}
+	}
+}
+
+static int tracer_winch[2];
+
+static void tracer_winch_handler(int sig)
+{
+	char c = 1;
+
+	if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
+		printk("tracer_winch_handler - write failed, errno = %d\n",
+		       errno);
+}
+
+void setup_tracer_winch(void)
+{
+	int err;
+
+	err = os_pipe(tracer_winch, 1, 1);
+	if(err){
+		printk("setup_tracer_winch : os_pipe failed, errno = %d\n", 
+		       -err);
+		return;
+	}
+	signal(SIGWINCH, tracer_winch_handler);
+}
+
+static int winch_tramp(int fd, void *device_data, int *fd_out)
+{
+	struct winch_data data;
+	unsigned long stack;
+	int fds[2], pid, n, err;
+	char c;
+
+	err = os_pipe(fds, 1, 1);
+	if(err){
+		printk("winch_tramp : os_pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+
+	data = ((struct winch_data) { pty_fd :		fd,
+				      pipe_fd :		fds[1],
+				      close_me :	fds[0] } );
+	pid = run_helper_thread(winch_thread, &data, 0, &stack, 0);
+	if(pid < 0){
+		printk("fork of winch_thread failed - errno = %d\n", errno);
+		return(pid);
+	}
+
+	close(fds[1]);
+	*fd_out = fds[0];
+	n = read(fds[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("winch_tramp : failed to read synchronization byte\n");
+		printk("read returned %d, errno = %d\n", n, errno);
+		printk("fd %d will not support SIGWINCH\n", fd);
+		*fd_out = -1;
+	}
+	return(pid);
+}
+
+void register_winch(int fd, void *device_data)
+{
+	int pid, thread, thread_fd;
+	char c = 1;
+
+	if(!isatty(fd)) return;
+
+	pid = tcgetpgrp(fd);
+	if(pid == tracing_pid)
+		register_winch_irq(tracer_winch[0], fd, -1, device_data);
+	else if(pid == -1){
+		thread = winch_tramp(fd, device_data, &thread_fd);
+		if(fd != -1){
+			register_winch_irq(thread_fd, fd, thread, device_data);
+
+			if(write(thread_fd, &c, sizeof(c)) != sizeof(c))
+				printk("register_winch : failed to write "
+				       "synchronization byte\n");
+		}
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/daemon.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,35 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+#define SWITCH_VERSION 3
+
+struct daemon_data {
+	char *sock_type;
+	char *ctl_sock;
+	void *ctl_addr;
+	void *data_addr;
+	void *local_addr;
+	int fd;
+	int control;
+	void *dev;
+};
+
+extern struct net_user_info daemon_user_info;
+
+extern int daemon_user_write(int fd, void *buf, int len, 
+			     struct daemon_data *pri);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/daemon_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/kernel.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "daemon.h"
+#include "daemon_kern.h"
+
+struct daemon_data daemon_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		sock_type :	"unix",
+		ctl_sock :	"/tmp/uml.ctl",
+		ctl_addr :	NULL,
+		data_addr :	NULL,
+		local_addr :	NULL,
+		fd :		-1,
+		control :	-1,
+		dev :		NULL,
+	}
+};
+
+void daemon_init(struct net_device *dev, int index)
+{
+	struct uml_net_private *pri;
+	struct daemon_data *dpri;
+
+	init_etherdev(dev, 0);
+	pri = dev->priv;
+	dpri = (struct daemon_data *) pri->user;
+	*dpri = daemon_priv[index];
+	printk("daemon backend (uml_switch version %d) - %s:%s", 
+	       SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock);
+	printk("\n");
+}
+
+static unsigned short daemon_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int daemon_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_recvfrom(fd, (*skb)->mac.raw, 
+			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int daemon_write(int fd, struct sk_buff **skb,
+			struct uml_net_private *lp)
+{
+	return(daemon_user_write(fd, (*skb)->data, (*skb)->len, 
+				 (struct daemon_data *) &lp->user));
+}
+
+static struct net_kern_info daemon_kern_info = {
+	init:			daemon_init,
+	protocol:		daemon_protocol,
+	read:			daemon_read,
+	write:			daemon_write,
+};
+
+static int daemon_count = 0;
+
+int daemon_setup(char *str, struct uml_net *dev)
+{
+	int err, n = daemon_count;
+
+	dev->user = &daemon_user_info;
+	dev->kern = &daemon_kern_info;
+	dev->private_size = sizeof(struct daemon_data);
+	dev->transport_index = daemon_count++;
+	if(*str != ',') return(0);
+	str++;
+ 	if(*str != ','){
+ 		err = setup_etheraddr(str, dev->mac);
+ 		if(!err) dev->have_mac = 1;
+ 	}
+	str = strchr(str, ',');
+	if(str == NULL) return(0);
+	*str++ = '\0';
+	if(*str != ',') daemon_priv[n].sock_type = str;
+	str = strchr(str, ',');
+	if(str == NULL) return(0);
+	*str++ = '\0';
+	if(*str != ',') daemon_priv[n].ctl_sock = str;
+	str = strchr(str, ',');
+	if(str == NULL) return(0);
+	*str = '\0';
+	printk(KERN_WARNING "daemon_setup : Ignoring data socket "
+	       "specification\n");
+	return(0);
+}
+
+static struct transport daemon_transport = {
+	list :	LIST_HEAD_INIT(daemon_transport.list),
+	name :	"daemon",
+	setup : daemon_setup
+};
+
+static int register_daemon(void)
+{
+	register_transport(&daemon_transport);
+	return(1);
+}
+
+__initcall(register_daemon);
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/daemon_kern.h b/arch/um/drivers/daemon_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/daemon_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_DAEMON_KERN_H
+#define __UM_DAEMON_KERN_H
+
+#include "net_kern.h"
+
+extern int daemon_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/daemon_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include "net_user.h"
+#include "daemon.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "user.h"
+#include "os.h"
+
+#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+enum request_type { REQ_NEW_CONTROL };
+
+#define SWITCH_MAGIC 0xfeedface
+
+struct request_v3 {
+	unsigned long magic;
+	int version;
+	enum request_type type;
+	struct sockaddr_un sock;
+};
+
+static struct sockaddr_un *new_addr(void *name, int len)
+{
+	struct sockaddr_un *sun;
+
+	sun = um_kmalloc(sizeof(struct sockaddr_un));
+	if(sun == NULL){
+		printk("new_addr: allocation of sockaddr_un failed\n");
+		return(NULL);
+	}
+	sun->sun_family = AF_UNIX;
+	memcpy(sun->sun_path, name, len);
+	return(sun);
+}
+
+static int connect_to_switch(struct daemon_data *pri)
+{
+	struct sockaddr_un *ctl_addr = pri->ctl_addr;
+	struct sockaddr_un *local_addr = pri->local_addr;
+	struct sockaddr_un *sun;
+	struct request_v3 req;
+	int fd, n, err;
+
+	if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
+		printk("daemon_open : control socket failed, errno = %d\n", 
+		       errno);		
+		return(-errno);
+	}
+
+	if(connect(pri->control, (struct sockaddr *) ctl_addr, 
+		   sizeof(*ctl_addr)) < 0){
+		printk("daemon_open : control connect failed, errno = %d\n",
+		       errno);
+		err = -errno;
+		goto out;
+	}
+
+	if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
+		printk("daemon_open : data socket failed, errno = %d\n", 
+		       errno);
+		err = -errno;
+		goto out;
+	}
+	if(bind(fd, (struct sockaddr *) local_addr, sizeof(*local_addr)) < 0){
+		printk("daemon_open : data bind failed, errno = %d\n", 
+		       errno);
+		err = -errno;
+		goto out_close;
+	}
+
+	sun = um_kmalloc(sizeof(struct sockaddr_un));
+	if(sun == NULL){
+		printk("new_addr: allocation of sockaddr_un failed\n");
+		err = -ENOMEM;
+		goto out_close;
+	}
+
+	req.magic = SWITCH_MAGIC;
+	req.version = SWITCH_VERSION;
+	req.type = REQ_NEW_CONTROL;
+	req.sock = *local_addr;
+	n = write(pri->control, &req, sizeof(req));
+	if(n != sizeof(req)){
+		printk("daemon_open : control setup request returned %d, "
+		       "errno = %d\n", n, errno);
+		err = -ENOTCONN;
+		goto out;		
+	}
+
+	n = read(pri->control, sun, sizeof(*sun));
+	if(n != sizeof(*sun)){
+		printk("daemon_open : read of data socket returned %d, "
+		       "errno = %d\n", n, errno);
+		err = -ENOTCONN;
+		goto out_close;		
+	}
+
+	pri->data_addr = sun;
+	return(fd);
+
+ out_close:
+	close(fd);
+ out:
+	close(pri->control);
+	return(err);
+}
+
+static void daemon_user_init(void *data, void *dev)
+{
+	struct daemon_data *pri = data;
+	struct timeval tv;
+	struct {
+		char zero;
+		int pid;
+		int usecs;
+	} name;
+
+	if(!strcmp(pri->sock_type, "unix"))
+		pri->ctl_addr = new_addr(pri->ctl_sock, 
+					 strlen(pri->ctl_sock) + 1);
+	name.zero = 0;
+	name.pid = os_getpid();
+	gettimeofday(&tv, NULL);
+	name.usecs = tv.tv_usec;
+	pri->local_addr = new_addr(&name, sizeof(name));
+	pri->dev = dev;
+	pri->fd = connect_to_switch(pri);
+	if(pri->fd < 0){
+		kfree(pri->local_addr);
+		pri->local_addr = NULL;
+	}
+}
+
+static int daemon_open(void *data)
+{
+	struct daemon_data *pri = data;
+	return(pri->fd);
+}
+
+static void daemon_remove(void *data)
+{
+	struct daemon_data *pri = data;
+
+	close(pri->fd);
+	close(pri->control);
+	if(pri->data_addr != NULL) kfree(pri->data_addr);
+	if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
+	if(pri->local_addr != NULL) kfree(pri->local_addr);
+}
+
+int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
+{
+	struct sockaddr_un *data_addr = pri->data_addr;
+
+	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+}
+
+static int daemon_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+struct net_user_info daemon_user_info = {
+	init:		daemon_user_init,
+	open:		daemon_open,
+	close:	 	NULL,
+	remove:	 	daemon_remove,
+	set_mtu:	daemon_set_mtu,
+	add_address:	NULL,
+	delete_address: NULL,
+	max_packet:	MAX_PACKET - ETH_HEADER_OTHER
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/fd.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,92 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include "user.h"
+#include "user_util.h"
+#include "chan_user.h"
+
+struct fd_chan {
+	int fd;
+	int raw;
+	struct termios tt;
+};
+
+void *fd_init(char *str, int device, struct chan_opts *opts)
+{
+	struct fd_chan *data;
+	char *end;
+	int n;
+
+	if(*str != ':'){
+		printk("fd_init : channel type 'fd' must specify a file "
+		       "descriptor\n");
+		return(NULL);
+	}
+	str++;
+	n = strtoul(str, &end, 0);
+	if(*end != '\0'){
+		printk("fd_init : couldn't parse file descriptor '%s'\n", str);
+		return(NULL);
+	}
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct fd_chan) { fd : 	n,
+				    raw : 	opts->raw });
+	return(data);
+}
+
+int fd_open(int input, int output, int primary, void *d)
+{
+	struct fd_chan *data = d;
+
+	if(data->raw && isatty(data->fd)){
+		tcgetattr(data->fd, &data->tt);
+		raw(data->fd, 0);
+	}
+	return(data->fd);
+}
+
+void fd_close(int fd, void *d)
+{
+	struct fd_chan *data = d;
+
+	if(data->raw && isatty(fd)){
+		tcsetattr(fd, TCSAFLUSH, &data->tt);
+		data->raw = 0;
+	}
+}
+
+int fd_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct fd_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops fd_ops = {
+	init:		fd_init,
+	open:		fd_open,
+	close:		fd_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	fd_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		1,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/harddog_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,192 @@
+/* UML hardware watchdog, shamelessly stolen from:
+ *
+ *	SoftDog	0.05:	A Software Watchdog Device
+ *
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
+ *
+ *	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.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *	Software only watchdog driver. Unlike its big brother the WDT501P
+ *	driver this won't always recover a failed machine.
+ *
+ *  03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
+ *	Modularised.
+ *	Added soft_margin; use upon insmod to change the timer delay.
+ *	NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
+ *	    minors.
+ *
+ *  19980911 Alan Cox
+ *	Made SMP safe for 2.3.x
+ *
+ *  20011127 Joel Becker (jlbec@evilplan.org>
+ *	Added soft_noboot; Allows testing the softdog trigger without 
+ *	requiring a recompile.
+ *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
+ */
+ 
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "helper.h"
+#include "mconsole.h"
+
+MODULE_LICENSE("GPL");
+
+static int timer_alive;
+
+static int harddog_in_fd = -1;
+static int harddog_out_fd = -1;
+
+/*
+ *	Allow only one person to hold it open
+ */
+ 
+extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock);
+
+static int harddog_open(struct inode *inode, struct file *file)
+{
+	int err;
+	char *sock = NULL;
+
+	if(timer_alive)
+		return -EBUSY;
+#ifdef CONFIG_HARDDOG_NOWAYOUT	 
+	MOD_INC_USE_COUNT;
+#endif
+
+#ifdef CONFIG_MCONSOLE
+	sock = mconsole_notify_socket();
+#endif
+	err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
+	if(err) return(err);
+
+	timer_alive = 1;
+	return 0;
+}
+
+extern void stop_watchdog(int in_fd, int out_fd);
+
+static int harddog_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *	Shut off the timer.
+	 */
+	lock_kernel();
+
+	stop_watchdog(harddog_in_fd, harddog_out_fd);
+	harddog_in_fd = -1;
+	harddog_out_fd = -1;
+
+	timer_alive=0;
+	unlock_kernel();
+	return 0;
+}
+
+extern int ping_watchdog(int fd);
+
+static ssize_t harddog_write(struct file *file, const char *data, size_t len,
+			     loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/*
+	 *	Refresh the timer.
+	 */
+	if(len)
+		return(ping_watchdog(harddog_out_fd));
+	return 0;
+}
+
+static int harddog_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOC_SETTIMEOUT,
+		0,
+		"UML Hardware Watchdog"
+	};
+	switch (cmd) {
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			if(copy_to_user((struct harddog_info *)arg, &ident,
+					sizeof(ident)))
+				return -EFAULT;
+			return 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0,(int *)arg);
+		case WDIOC_KEEPALIVE:
+			return(ping_watchdog(harddog_out_fd));
+	}
+}
+
+static struct file_operations harddog_fops = {
+	owner:		THIS_MODULE,
+	write:		harddog_write,
+	ioctl:		harddog_ioctl,
+	open:		harddog_open,
+	release:	harddog_release,
+};
+
+static struct miscdevice harddog_miscdev = {
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&harddog_fops,
+};
+
+static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
+
+static int __init harddog_init(void)
+{
+	int ret;
+
+	ret = misc_register(&harddog_miscdev);
+
+	if (ret)
+		return ret;
+
+	printk(banner);
+
+	return(0);
+}
+
+static void __exit harddog_exit(void)
+{
+	misc_deregister(&harddog_miscdev);
+}
+
+module_init(harddog_init);
+module_exit(harddog_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/harddog_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,134 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include "user_util.h"
+#include "user.h"
+#include "helper.h"
+#include "mconsole.h"
+#include "os.h"
+
+struct dog_data {
+	int stdin;
+	int stdout;
+	int close_me[2];
+};
+
+static void pre_exec(void *d)
+{
+	struct dog_data *data = d;
+
+	dup2(data->stdin, 0);
+	dup2(data->stdout, 1);
+	dup2(data->stdout, 2);
+	close(data->stdin);
+	close(data->stdout);
+	close(data->close_me[0]);
+	close(data->close_me[1]);
+}
+
+int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
+{
+	struct dog_data data;
+	int in_fds[2], out_fds[2], pid, n, err;
+	char pid_buf[sizeof("nnnnn\0")], c;
+	char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL };
+	char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, 
+				  NULL };
+	char **args = NULL;
+
+	err = os_pipe(in_fds, 1, 0);
+	if(err){
+		printk("harddog_open - os_pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+
+	err = os_pipe(out_fds, 1, 0);
+	if(err){
+		printk("harddog_open - os_pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+
+	data.stdin = out_fds[0];
+	data.stdout = in_fds[1];
+	data.close_me[0] = out_fds[1];
+	data.close_me[1] = in_fds[0];
+
+	if(sock != NULL){
+		mconsole_args[2] = sock;
+		args = mconsole_args;
+	}
+	else {
+		sprintf(pid_buf, "%d", tracing_pid);
+		args = pid_args;
+	}
+
+	pid = run_helper(pre_exec, &data, args, NULL);
+
+	close(out_fds[0]);
+	close(in_fds[1]);
+
+	if(pid < 0){
+		err = -pid;
+		printk("harddog_open - run_helper failed, errno = %d\n", err);
+		goto out;
+	}
+
+	n = read(in_fds[0], &c, sizeof(c));
+	if(n == 0){
+		printk("harddog_open - EOF on watchdog pipe\n");
+		helper_wait(pid);
+		err = -EIO;
+		goto out;
+	}
+	else if(n < 0){
+		printk("harddog_open - read of watchdog pipe failed, "
+		       "errno = %d\n", errno);
+		helper_wait(pid);
+		err = -errno;
+		goto out;
+	}
+	*in_fd_ret = in_fds[0];
+	*out_fd_ret = out_fds[1];
+	return(0);
+ out:
+	close(out_fds[1]);
+	close(in_fds[0]);
+	return(err);
+}
+
+void stop_watchdog(int in_fd, int out_fd)
+{
+	close(in_fd);
+	close(out_fd);
+}
+
+int ping_watchdog(int fd)
+{
+	int n;
+	char c = '\n';
+
+	n = write(fd, &c, sizeof(c));
+	if(n < sizeof(c)){
+		printk("ping_watchdog - write failed, errno = %d\n",
+		       errno);
+		return(-errno);
+	}
+	return 1;
+
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/hostaudio_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,264 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/module.h"
+#include "linux/version.h"
+#include "linux/init.h"
+#include "linux/slab.h"
+#include "linux/fs.h"
+#include "linux/sound.h"
+#include "linux/soundcard.h"
+#include "kern_util.h"
+#include "init.h"
+#include "hostaudio.h"
+
+char *dsp = HOSTAUDIO_DEV_DSP;
+char *mixer = HOSTAUDIO_DEV_MIXER;
+
+#ifndef MODULE
+static int set_dsp(char *name, int *add)
+{
+	dsp = uml_strdup(name);
+	return(0);
+}
+
+__uml_setup("dsp=", set_dsp,
+"dsp=<dsp device>\n"
+"    This is used to specify the host dsp device to the hostaudio driver.\n"
+"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
+);
+
+static int set_mixer(char *name, int *add)
+{
+	mixer = uml_strdup(name);
+	return(0);
+}
+
+__uml_setup("mixer=", set_mixer,
+"mixer=<mixer device>\n"
+"    This is used to specify the host mixer device to the hostaudio driver.\n"
+"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
+);
+#endif
+
+/* /dev/dsp file operations */
+
+static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, 
+			      loff_t *ppos)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: read called, count = %d\n", count);
+#endif
+
+        return(hostaudio_read_user(state, buffer, count, ppos));
+}
+
+static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+			       size_t count, loff_t *ppos)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: write called, count = %d\n", count);
+#endif
+        return(hostaudio_write_user(state, buffer, count, ppos));
+}
+
+static unsigned int hostaudio_poll(struct file *file, 
+				   struct poll_table_struct *wait)
+{
+        unsigned int mask = 0;
+
+#ifdef DEBUG
+        printk("hostaudio: poll called (unimplemented)\n");
+#endif
+
+        return(mask);
+}
+
+static int hostaudio_ioctl(struct inode *inode, struct file *file, 
+			   unsigned int cmd, unsigned long arg)
+{
+        struct hostaudio_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostaudio: ioctl called, cmd = %u\n", cmd);
+#endif
+
+        return(hostaudio_ioctl_user(state, cmd, arg));
+}
+
+static int hostaudio_open(struct inode *inode, struct file *file)
+{
+        struct hostaudio_state *state;
+        int r = 0, w = 0;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostaudio: open called (host: %s)\n", dsp);
+#endif
+
+        state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
+        if(state == NULL) return(-ENOMEM);
+
+        if(file->f_mode & FMODE_READ) r = 1;
+        if(file->f_mode & FMODE_WRITE) w = 1;
+
+        ret = hostaudio_open_user(state, r, w, dsp);
+        if(ret < 0){
+		kfree(state);
+		return(ret);
+        }
+
+        file->private_data = state;
+        return(0);
+}
+
+static int hostaudio_release(struct inode *inode, struct file *file)
+{
+        struct hostaudio_state *state = file->private_data;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostaudio: release called\n");
+#endif
+
+        ret = hostaudio_release_user(state);
+        kfree(state);
+
+        return(ret);
+}
+
+/* /dev/mixer file operations */
+
+static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, 
+				  unsigned int cmd, unsigned long arg)
+{
+        struct hostmixer_state *state = file->private_data;
+
+#ifdef DEBUG
+        printk("hostmixer: ioctl called\n");
+#endif
+
+        return(hostmixer_ioctl_mixdev_user(state, cmd, arg));
+}
+
+static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
+{
+        struct hostmixer_state *state;
+        int r = 0, w = 0;
+        int ret;
+
+#ifdef DEBUG
+        printk("hostmixer: open called (host: %s)\n", mixer);
+#endif
+
+        state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL);
+        if(state == NULL) return(-ENOMEM);
+
+        if(file->f_mode & FMODE_READ) r = 1;
+        if(file->f_mode & FMODE_WRITE) w = 1;
+
+        ret = hostmixer_open_mixdev_user(state, r, w, mixer);
+        
+        if(ret < 0){
+		kfree(state);
+		return(ret);
+        }
+
+        file->private_data = state;
+        return(0);
+}
+
+static int hostmixer_release(struct inode *inode, struct file *file)
+{
+        struct hostmixer_state *state = file->private_data;
+	int ret;
+
+#ifdef DEBUG
+        printk("hostmixer: release called\n");
+#endif
+
+        ret = hostmixer_release_mixdev_user(state);
+        kfree(state);
+
+        return(ret);
+}
+
+
+/* kernel module operations */
+
+static struct file_operations hostaudio_fops = {
+        owner:          THIS_MODULE,
+        llseek:         no_llseek,
+        read:           hostaudio_read,
+        write:          hostaudio_write,
+        poll:           hostaudio_poll,
+        ioctl:          hostaudio_ioctl,
+        mmap:           NULL,
+        open:           hostaudio_open,
+        release:        hostaudio_release,
+};
+
+static struct file_operations hostmixer_fops = {
+        owner:          THIS_MODULE,
+        llseek:         no_llseek,
+        ioctl:          hostmixer_ioctl_mixdev,
+        open:           hostmixer_open_mixdev,
+        release:        hostmixer_release,
+};
+
+struct {
+	int dev_audio;
+	int dev_mixer;
+} module_data;
+
+MODULE_AUTHOR("Steve Schmidtke");
+MODULE_DESCRIPTION("UML Audio Relay");
+MODULE_LICENSE("GPL");
+
+static int __init hostaudio_init_module(void)
+{
+        printk(KERN_INFO "UML Audio Relay\n");
+
+	module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
+        if(module_data.dev_audio < 0){
+                printk(KERN_ERR "hostaudio: couldn't register DSP device!\n");
+                return -ENODEV;
+        }
+
+	module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1);
+        if(module_data.dev_mixer < 0){
+                printk(KERN_ERR "hostmixer: couldn't register mixer "
+		       "device!\n");
+                unregister_sound_dsp(module_data.dev_audio);
+                return -ENODEV;
+        }
+
+        return 0;
+}
+
+static void __exit hostaudio_cleanup_module (void)
+{
+       unregister_sound_mixer(module_data.dev_mixer);
+       unregister_sound_dsp(module_data.dev_audio);
+}
+
+module_init(hostaudio_init_module);
+module_exit(hostaudio_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/hostaudio_user.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,149 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "hostaudio.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "os.h"
+
+/* /dev/dsp file operations */
+
+ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, 
+			    size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+
+#ifdef DEBUG
+        printk("hostaudio: read_user called, count = %d\n", count);
+#endif
+
+        ret = read(state->fd, buffer, count);
+
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
+			     size_t count, loff_t *ppos)
+{
+	ssize_t ret;
+
+#ifdef DEBUG
+        printk("hostaudio: write_user called, count = %d\n", count);
+#endif
+
+        ret = write(state->fd, buffer, count);
+
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, 
+			 unsigned long arg)
+{
+	int ret;
+#ifdef DEBUG
+        printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
+#endif
+
+        ret = ioctl(state->fd, cmd, arg);
+	
+        if(ret < 0) return(-errno);
+        return(ret);
+}
+
+int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
+{
+#ifdef DEBUG
+        printk("hostaudio: open_user called\n");
+#endif
+
+        state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+
+        if(state->fd >= 0) return(0);
+
+        printk("hostaudio_open_user failed to open '%s', errno = %d\n",
+	       dsp, errno);
+        
+        return(-errno); 
+}
+
+int hostaudio_release_user(struct hostaudio_state *state)
+{
+#ifdef DEBUG
+        printk("hostaudio: release called\n");
+#endif
+        if(state->fd >= 0){
+		close(state->fd);
+		state->fd=-1;
+        }
+
+        return(0);
+}
+
+/* /dev/mixer file operations */
+
+int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
+				unsigned int cmd, unsigned long arg)
+{
+	int ret;
+#ifdef DEBUG
+        printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
+#endif
+
+        ret = ioctl(state->fd, cmd, arg);
+	if(ret < 0) 
+		return(-errno);
+	return(ret);
+}
+
+int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
+			       char *mixer)
+{
+#ifdef DEBUG
+        printk("hostmixer: open_user called\n");
+#endif
+
+        state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
+
+        if(state->fd >= 0) return(0);
+
+        printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n",
+	       mixer, errno);
+        
+        return(-errno); 
+}
+
+int hostmixer_release_mixdev_user(struct hostmixer_state *state)
+{
+#ifdef DEBUG
+        printk("hostmixer: release_user called\n");
+#endif
+
+        if(state->fd >= 0){
+		close(state->fd);
+		state->fd = -1;
+        }
+
+        return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/line.c b/arch/um/drivers/line.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/line.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,479 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/list.h"
+#include "linux/devfs_fs_kernel.h"
+#include "asm/irq.h"
+#include "chan_kern.h"
+#include "irq_user.h"
+#include "line.h"
+#include "kern.h"
+#include "user_util.h"
+#include "os.h"
+
+#define LINE_BUFSIZE 4096
+
+void line_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct line *dev = data;
+
+	if(dev->count > 0) 
+		chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, 
+			       dev);
+}
+
+void line_timer_cb(void *arg)
+{
+	struct line *dev = arg;
+
+	line_interrupt(dev->driver->read_irq, dev, NULL);
+}
+
+void buffer_data(struct line *line, const char *buf, int len)
+{
+	int end;
+
+	if(line->buffer == NULL){
+		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
+		if(line->buffer == NULL){
+			printk("buffer_data - atomic allocation failed\n");
+			return;
+		}
+		line->head = line->buffer;
+		line->tail = line->buffer;
+	}
+	end = line->buffer + LINE_BUFSIZE - line->tail;
+	if(len < end){
+		memcpy(line->tail, buf, len);
+		line->tail += len;
+	}
+	else {
+		memcpy(line->tail, buf, end);
+		buf += end;
+		len -= end;
+		memcpy(line->buffer, buf, len);
+		line->tail = line->buffer + len;
+	}
+}
+
+static int flush_buffer(struct line *line)
+{
+	int n, count;
+
+	if((line->buffer == NULL) || (line->head == line->tail)) return(1);
+
+	if(line->tail < line->head){
+		count = line->buffer + LINE_BUFSIZE - line->head;
+		n = write_chan(&line->chan_list, line->head, count,
+			       line->driver->write_irq);
+		if(n < 0) return(n);
+		if(n == count) line->head = line->buffer;
+		else {
+			line->head += n;
+			return(0);
+		}
+	}
+
+	count = line->tail - line->head;
+	n = write_chan(&line->chan_list, line->head, count, 
+		       line->driver->write_irq);
+	if(n < 0) return(n);
+
+	line->head += n;
+	return(line->head == line->tail);
+}
+
+int line_write(struct line *lines, struct tty_struct *tty, const char *buf, 
+	       int len)
+{
+	struct line *line;
+	unsigned long flags;
+	int n, err, i;
+
+	if(tty->stopped) return 0;
+
+	i = minor(tty->device) - tty->driver.minor_start;
+	line = &lines[i];
+
+	if(line->head != line->tail){
+		local_irq_save(flags);
+		buffer_data(line, buf, len);
+		err = flush_buffer(line);
+		local_irq_restore(flags);
+		if(err <= 0) return(len);
+	}
+	else {
+		n = write_chan(&line->chan_list, buf, len, 
+			       line->driver->write_irq);
+		if(n < 0) return(n);
+		if(n < len) buffer_data(line, buf + n, len - n);
+	}
+	return(len);
+}
+
+void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct line *dev = data;
+	struct tty_struct *tty = dev->tty;
+	int err;
+
+	err = flush_buffer(dev);
+	if(err == 0) return;
+	else if(err < 0){
+		dev->head = dev->buffer;
+		dev->tail = dev->buffer;
+	}
+
+	if(tty == NULL) return;
+
+	if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
+	   (tty->ldisc.write_wakeup != NULL))
+		(tty->ldisc.write_wakeup)(tty);
+	
+	/* BLOCKING mode
+	 * In blocking mode, everything sleeps on tty->write_wait.
+	 * Sleeping in the console driver would break non-blocking
+	 * writes.
+	 */
+
+	if (waitqueue_active(&tty->write_wait))
+		wake_up_interruptible(&tty->write_wait);
+
+}
+
+int line_write_room(struct tty_struct *tty)
+{
+	struct line *dev = tty->driver_data;
+	int n;
+
+	if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
+
+	n = dev->head - dev->tail;
+	if(n <= 0) n = LINE_BUFSIZE + n;
+	return(n - 1);
+}
+
+int line_setup_irq(int fd, int input, int output, void *data)
+{
+	struct line *line = data;
+	struct line_driver *driver = line->driver;
+	int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM;
+
+	if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, 
+				       line_interrupt, flags, 
+				       driver->read_irq_name, line);
+	if(err) return(err);
+	if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, 
+					line_write_interrupt, flags, 
+					driver->write_irq_name, line);
+	line->have_irq = 1;
+	return(err);
+}
+
+void line_disable(struct line *line, int current_irq)
+{
+	if(!line->have_irq) return;
+
+	if(line->driver->read_irq == current_irq)
+		free_irq_later(line->driver->read_irq, line);
+	else
+		free_irq(line->driver->read_irq, line);
+
+	if(line->driver->write_irq == current_irq)
+		free_irq_later(line->driver->write_irq, line);
+	else
+		free_irq(line->driver->write_irq, line);
+
+	line->have_irq = 0;
+}
+
+int line_open(struct line *lines, struct tty_struct *tty,
+	      struct chan_opts *opts)
+{
+	struct line *line;
+	int n, err = 0;
+
+	if(tty == NULL) n = 0;
+	else n = minor(tty->device) - tty->driver.minor_start;
+	line = &lines[n];
+
+	down(&line->sem);
+	if(line->count == 0){
+		if(!line->valid){
+			err = -ENODEV;
+			goto out;
+		}
+		if(list_empty(&line->chan_list)){
+			err = parse_chan_pair(line->init_str, &line->chan_list,
+					      line->init_pri, n, opts);
+			if(err) goto out;
+			err = open_chan(&line->chan_list);
+			if(err) goto out;
+		}
+		enable_chan(&line->chan_list, line);
+		INIT_TQUEUE(&line->task, line_timer_cb, line);
+	}
+
+	if(!line->sigio){
+		chan_enable_winch(&line->chan_list, line);
+		line->sigio = 1;
+	}
+
+	/* This is outside the if because the initial console is opened
+	 * with tty == NULL
+	 */
+	line->tty = tty;
+
+	if(tty != NULL){
+		tty->driver_data = line;
+		chan_window_size(&line->chan_list, &tty->winsize.ws_row, 
+				 &tty->winsize.ws_col);
+	}
+
+	line->count++;
+ out:
+	up(&line->sem);
+	return(err);
+}
+
+void line_close(struct line *lines, struct tty_struct *tty)
+{
+	struct line *line;
+	int n;
+
+	if(tty == NULL) n = 0;
+	else n = minor(tty->device) - tty->driver.minor_start;
+	line = &lines[n];
+
+	line->count--;
+
+	/* I don't like this, but I can't think of anything better.  What's
+	 * going on is that the tty is in the process of being closed for
+	 * the last time.  Its count hasn't been dropped yet, so it's still
+	 * at 1.  This may happen when line->count != 0 because of the initial
+	 * console open (without a tty) bumping it up to 1.
+	 */
+	if((line->tty != NULL) && (line->tty->count == 1))
+		line->tty = NULL;
+	if(line->count == 0)
+		line_disable(line, -1);
+}
+
+void close_lines(struct line *lines, int nlines)
+{
+	int i;
+
+	for(i = 0; i < nlines; i++)
+		close_chan(&lines[i].chan_list);
+}
+
+void line_setup(struct line *lines, int num, char *init)
+{
+	int i, n;
+	char *end;
+
+	if(*init == '=') n = -1;
+	else {
+		n = simple_strtoul(init, &end, 0);
+		if(*end != '='){
+			printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
+			       init);
+			return;
+		}
+		init = end;
+	}
+	init++;
+	if(n == -1){
+		for(i = 0; i < num; i++){
+			if(lines[i].init_pri <= INIT_ALL){
+				lines[i].init_pri = INIT_ALL;
+				if(!strcmp(init, "none")) lines[i].valid = 0;
+				else {
+					lines[i].init_str = init;
+					lines[i].valid = 1;
+				}
+			}
+		}
+	}
+	else if(lines[n].init_pri <= INIT_ONE){
+		lines[n].init_pri = INIT_ONE;
+		if(!strcmp(init, "none")) lines[n].valid = 0;
+		else {
+			lines[n].init_str = init;
+			lines[n].valid = 1;
+		}
+	}
+}
+
+void line_register_devfs(struct lines *set, struct line_driver *line_driver, 
+			 struct tty_driver *driver, struct line *lines,
+			 int nlines)
+{
+	int err, i, n;
+	char *from, *to;
+
+	driver->driver_name = line_driver->name;
+	driver->name = line_driver->devfs_name;
+	driver->major = line_driver->major;
+	driver->minor_start = line_driver->minor_start;
+	driver->type = line_driver->type;
+	driver->subtype = line_driver->subtype;
+	driver->magic = TTY_DRIVER_MAGIC;
+	driver->flags = TTY_DRIVER_REAL_RAW;
+
+	n = set->num;
+	driver->num = n;
+	driver->table = kmalloc(n * sizeof(driver->table[0]), GFP_KERNEL);
+	driver->termios = kmalloc(n * sizeof(driver->termios[0]), GFP_KERNEL);
+	driver->termios_locked = kmalloc(n * sizeof(driver->termios_locked[0]),
+					 GFP_KERNEL);
+	if((driver->table == NULL) || (driver->termios == NULL) ||
+	   (driver->termios_locked == NULL))
+		panic("Failed to allocate driver table");
+
+	memset(driver->table, 0, n * sizeof(driver->table[0]));
+	memset(driver->termios, 0, n * sizeof(driver->termios[0]));
+	memset(driver->termios_locked, 0, 
+	       n * sizeof(driver->termios_locked[0]));
+
+	driver->write_room = line_write_room;
+	driver->init_termios = tty_std_termios;
+
+	driver->refcount = &set->refcount;
+
+	if (tty_register_driver(driver))
+		panic("line_register_devfs : Couldn't register driver\n");
+
+	from = line_driver->symlink_from;
+	to = line_driver->symlink_to;
+	err = devfs_mk_symlink(NULL, from, 0, to, NULL, NULL);
+	if(err) printk("Symlink creation from /dev/%s to /dev/%s "
+		       "returned %d\n", from, to, err);
+
+	for(i = 0; i < nlines; i++){
+		if(!lines[i].valid) 
+			tty_unregister_devfs(driver, driver->minor_start + i);
+	}
+}
+
+void lines_init(struct line *lines, int nlines)
+{
+	int i;
+
+	for(i = 0; i < nlines; i++){
+		INIT_LIST_HEAD(&lines[i].chan_list);
+		sema_init(&lines[i].sem, 1);
+	}
+}
+
+struct winch {
+	struct list_head list;
+	int fd;
+	int tty_fd;
+	int pid;
+	struct line *line;
+};
+
+void winch_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	struct winch *winch = data;
+	struct tty_struct *tty;
+	int err;
+	char c;
+
+	err = generic_read(winch->fd, &c, NULL);
+	if(err < 0){
+		if(err != -EAGAIN){
+			printk("winch_interrupt : read failed, errno = %d\n", 
+			       -err);
+			printk("fd %d is losing SIGWINCH support\n", 
+			       winch->tty_fd);
+			free_irq(irq, data);
+			return;
+		}
+		goto out;
+	}
+	tty = winch->line->tty;
+	if(tty != NULL){
+		chan_window_size(&winch->line->chan_list, 
+				 &tty->winsize.ws_row, 
+				 &tty->winsize.ws_col);
+		kill_pg(tty->pgrp, SIGWINCH, 1);
+	}
+ out:
+	reactivate_fd(winch->fd, WINCH_IRQ);
+}
+
+LIST_HEAD(winch_handlers);
+
+void register_winch_irq(int fd, int tty_fd, int pid, void *line)
+{
+	struct winch *winch;
+
+	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
+	if(winch == NULL){
+		printk("register_winch_irq - kmalloc failed\n");
+		return;
+	}
+	*winch = ((struct winch) { list : 	LIST_HEAD_INIT(winch->list),
+				   fd : 	fd,
+				   tty_fd :	tty_fd,
+				   pid : 	pid,
+				   line :	line });
+	list_add(&winch->list, &winch_handlers);
+	if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, 
+			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+			  "winch", winch) < 0)
+		printk("register_winch_irq - failed to register IRQ\n");
+}
+
+static void winch_cleanup(void)
+{
+	struct list_head *ele;
+	struct winch *winch;
+
+	list_for_each(ele, &winch_handlers){
+		winch = list_entry(ele, struct winch, list);
+		close(winch->fd);
+		free_irq_by_fd(winch->fd);
+		if(winch->pid != -1) os_kill_process(winch->pid);
+	}
+}
+
+__uml_exitcall(winch_cleanup);
+
+char *add_xterm_umid(char *base)
+{
+	char *umid, *title;
+	int len;
+
+	umid = get_umid(1);
+	if(umid == NULL) return(base);
+	
+	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
+	title = kmalloc(len, GFP_KERNEL);
+	if(title == NULL){
+		printk("Failed to allocate buffer for xterm title\n");
+		return(base);
+	}
+
+	strncpy(title, base, len);
+	len -= strlen(title);
+	snprintf(&title[strlen(title)], len, " (%s)", umid);
+	return(title);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mcast.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,32 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct mcast_data {
+	char *addr;
+	unsigned short port;
+	void *mcast_addr;
+	int ttl;
+	unsigned char hwaddr[ETH_ADDR_LEN];
+	int hw_setup;
+	void *dev;
+};
+
+extern struct net_user_info mcast_user_info;
+
+extern int mcast_user_write(int fd, void *buf, int len, 
+			    struct mcast_data *pri);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mcast_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,154 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ */
+
+#include "linux/kernel.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/in.h"
+#include "linux/inet.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "mcast.h"
+#include "mcast_kern.h"
+
+struct mcast_data mcast_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		addr:		"239.192.168.1",
+		port:		1102,
+		ttl:		1,
+	}
+};
+
+void mcast_init(struct net_device *dev, int index)
+{
+	struct uml_net_private *pri;
+	struct mcast_data *dpri;
+
+	init_etherdev(dev, 0);
+	pri = dev->priv;
+	dpri = (struct mcast_data *) pri->user;
+	*dpri = mcast_priv[index];
+	printk("mcast backend ");
+	printk("multicast adddress: %s:%u, TTL:%u ",
+	       dpri->addr, dpri->port, dpri->ttl);
+
+	printk("\n");
+}
+
+static unsigned short mcast_protocol(struct sk_buff *skb)
+{
+	return eth_type_trans(skb, skb->dev);
+}
+
+static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_recvfrom(fd, (*skb)->mac.raw, 
+			    (*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int mcast_write(int fd, struct sk_buff **skb,
+			struct uml_net_private *lp)
+{
+	return mcast_user_write(fd, (*skb)->data, (*skb)->len, 
+				 (struct mcast_data *) &lp->user);
+}
+
+static struct net_kern_info mcast_kern_info = {
+	init:			mcast_init,
+	protocol:		mcast_protocol,
+	read:			mcast_read,
+	write:			mcast_write,
+};
+
+static int mcast_count = 0;
+
+int mcast_setup(char *str, struct uml_net *dev)
+{
+	int err, n = mcast_count;
+	int num = 0;
+	char *p1, *p2;
+
+	dev->user = &mcast_user_info;
+	dev->kern = &mcast_kern_info;
+	dev->private_size = sizeof(struct mcast_data);
+	dev->transport_index = mcast_count++;
+
+	/* somewhat more sophisticated parser, needed for in_aton */
+
+	p1 = str;
+	if (*str == ',')
+		p1++;
+	while (p1 && *p1) {
+		if ((p2 = strchr(p1, ',')))
+			*p2++ = '\0';
+		if (strlen(p1) > 0) {
+			switch (num) {
+			case 0:
+				/* First argument: Ethernet address */
+				err = setup_etheraddr(p1, dev->mac);
+				if (!err) 
+					dev->have_mac = 1;
+				break;
+			case 1:
+				/* Second argument: Multicast group */
+				mcast_priv[n].addr = p1;
+				break;
+			case 2:
+				/* Third argument: Port number */
+				mcast_priv[n].port = 
+					htons(simple_strtoul(p1, NULL, 10));
+				break;
+			case 3:
+				/* Fourth argument: TTL */
+				mcast_priv[n].ttl = 
+						simple_strtoul(p1, NULL, 10);
+				break;
+			}
+		}
+		p1 = p2;
+		num++;
+	}
+
+	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n",
+		mcast_priv[n].addr, mcast_priv[n].port,
+		mcast_priv[n].ttl);
+
+	return(0);
+}
+
+static struct transport mcast_transport = {
+	list :	LIST_HEAD_INIT(mcast_transport.list),
+	name :	"mcast",
+	setup : mcast_setup
+};
+
+static int register_mcast(void)
+{
+	register_transport(&mcast_transport);
+	return(1);
+}
+
+__initcall(register_mcast);
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mcast_kern.h b/arch/um/drivers/mcast_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mcast_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_MCAST_KERN_H
+#define __UM_MCAST_KERN_H
+
+#include "net_kern.h"
+
+extern int mcast_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mcast_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,175 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <linux/inet.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include "net_user.h"
+#include "mcast.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "user.h"
+
+#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+
+static struct sockaddr_in *new_addr(char *addr, unsigned short port)
+{
+	struct sockaddr_in *sin;
+
+	sin = um_kmalloc(sizeof(struct sockaddr_in));
+	if(sin == NULL){
+		printk("new_addr: allocation of sockaddr_in failed\n");
+		return(NULL);
+	}
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = in_aton(addr);
+	sin->sin_port = port;
+	return(sin);
+}
+
+static void mcast_user_init(void *data, void *dev)
+{
+	struct mcast_data *pri = data;
+
+	pri->mcast_addr = new_addr(pri->addr, pri->port);
+	pri->dev = dev;
+}
+
+static int mcast_open(void *data)
+{
+	struct mcast_data *pri = data;
+	struct sockaddr_in *sin = pri->mcast_addr;
+	struct ip_mreq mreq;
+	int fd, yes = 1;
+
+
+	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) {
+		fd = -EINVAL;
+		goto out;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+		printk("mcast_open : data socket failed, errno = %d\n", 
+		       errno);
+		fd = -ENOMEM;
+		goto out;
+	}
+
+	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+		printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* set ttl according to config */
+	if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
+		       sizeof(pri->ttl)) < 0) {
+		printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* set LOOP, so data does get fed back to local sockets */
+	if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+		printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
+			errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}
+
+	/* bind socket to mcast address */
+	if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
+		printk("mcast_open : data bind failed, errno = %d\n", errno);
+		close(fd);
+		fd = -EINVAL;
+		goto out;
+	}		
+	
+	/* subscribe to the multicast group */
+	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
+	mreq.imr_interface.s_addr = 0;
+	if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, 
+		       &mreq, sizeof(mreq)) < 0) {
+		printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
+			errno);
+		printk("There appears not to be a multicast-capable network "
+		       "interface on the host.\n");
+		printk("eth0 should be configured in order to use the "
+		       "multicast transport.\n");
+		close(fd);
+		fd = -EINVAL;
+	}
+
+ out:
+	return(fd);
+}
+
+static void mcast_close(int fd, void *data)
+{
+	struct ip_mreq mreq;
+	struct mcast_data *pri = data;
+	struct sockaddr_in *sin = pri->mcast_addr;
+
+	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
+	mreq.imr_interface.s_addr = 0;
+	if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
+		       &mreq, sizeof(mreq)) < 0) {
+		printk("mcast_open: IP_DROP_MEMBERSHIP failed, error = %d\n",
+			errno);
+	}
+
+	close(fd);
+}
+
+int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
+{
+	struct sockaddr_in *data_addr = pri->mcast_addr;
+
+	return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+}
+
+static int mcast_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+struct net_user_info mcast_user_info = {
+	init:		mcast_user_init,
+	open:		mcast_open,
+	close:	 	mcast_close,
+	remove:	 	NULL,
+	set_mtu:	mcast_set_mtu,
+	add_address:	NULL,
+	delete_address: NULL,
+	max_packet:	MAX_PACKET - ETH_HEADER_OTHER
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mconsole_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/slab.h"
+#include "linux/init.h"
+#include "linux/notifier.h"
+#include "linux/reboot.h"
+#include "linux/utsname.h"
+#include "linux/ctype.h"
+#include "linux/interrupt.h"
+#include "linux/sysrq.h"
+#include "linux/tqueue.h"
+#include "linux/module.h"
+#include "linux/proc_fs.h"
+#include "asm/irq.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mconsole.h"
+#include "mconsole_kern.h"
+#include "irq_user.h"
+#include "init.h"
+#include "os.h"
+#include "umid.h"
+
+static int do_unlink_socket(struct notifier_block *notifier, 
+			    unsigned long what, void *data)
+{
+	return(mconsole_unlink_socket());
+}
+
+
+static struct notifier_block reboot_notifier = {
+	notifier_call:		do_unlink_socket,
+	priority:		0,
+};
+
+LIST_HEAD(mc_requests);
+
+void mc_task_proc(void *unused)
+{
+	struct mconsole_entry *req;
+	unsigned long flags;
+	int done;
+
+	do {
+		save_flags(flags);
+		req = list_entry(mc_requests.next, struct mconsole_entry, 
+				 list);
+		list_del(&req->list);
+		done = list_empty(&mc_requests);
+		restore_flags(flags);
+		req->request.cmd->handler(&req->request);
+		kfree(req);
+	} while(!done);
+}
+
+struct tq_struct mconsole_task = {
+	routine:	mc_task_proc,
+	data: 		NULL
+};
+
+void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int fd;
+	struct mconsole_entry *new;
+	struct mc_request req;
+
+	fd = (int) dev_id;
+	while (mconsole_get_request(fd, &req)){
+		if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
+		else {
+			new = kmalloc(sizeof(req), GFP_ATOMIC);
+			if(new == NULL)
+				mconsole_reply(&req, "Out of memory", 1, 0);
+			else {
+				new->request = req;
+				list_add(&new->list, &mc_requests);
+			}
+		}
+	}
+	if(!list_empty(&mc_requests)) schedule_task(&mconsole_task);
+	reactivate_fd(fd, MCONSOLE_IRQ);
+}
+
+void mconsole_version(struct mc_request *req)
+{
+	char version[256];
+
+	sprintf(version, "%s %s %s %s %s", system_utsname.sysname, 
+		system_utsname.nodename, system_utsname.release, 
+		system_utsname.version, system_utsname.machine);
+	mconsole_reply(req, version, 0, 0);
+}
+
+#define UML_MCONSOLE_HELPTEXT \
+"Commands:
+    version - Get kernel version
+    help - Print this message
+    halt - Halt UML
+    reboot - Reboot UML
+    config <dev>=<config> - Add a new device to UML; 
+	same syntax as command line
+    remove <dev> - Remove a device from UML
+    sysrq <letter> - Performs the SysRq action controlled by the letter
+    cad - invoke the Ctl-Alt-Del handler
+"
+
+void mconsole_help(struct mc_request *req)
+{
+	mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
+}
+
+void mconsole_halt(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	machine_halt();
+}
+
+void mconsole_reboot(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	machine_restart(NULL);
+}
+
+extern void ctrl_alt_del(void);
+
+void mconsole_cad(struct mc_request *req)
+{
+	mconsole_reply(req, "", 0, 0);
+	ctrl_alt_del();
+}
+
+void mconsole_go(struct mc_request *req)
+{
+	mconsole_reply(req, "Not stopped", 1, 0);
+}
+
+void mconsole_stop(struct mc_request *req)
+{
+	deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
+	os_set_fd_block(req->originating_fd, 1);
+	mconsole_reply(req, "", 0, 0);
+	while(mconsole_get_request(req->originating_fd, req)){
+		if(req->cmd->handler == mconsole_go) break;
+		(*req->cmd->handler)(req);
+	}
+	os_set_fd_block(req->originating_fd, 0);
+	reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
+	mconsole_reply(req, "", 0, 0);
+}
+
+LIST_HEAD(mconsole_devices);
+
+void mconsole_register_dev(struct mc_device *new)
+{
+	list_add(&new->list, &mconsole_devices);
+}
+
+static struct mc_device *mconsole_find_dev(char *name)
+{
+	struct list_head *ele;
+	struct mc_device *dev;
+
+	list_for_each(ele, &mconsole_devices){
+		dev = list_entry(ele, struct mc_device, list);
+		if(!strncmp(name, dev->name, strlen(dev->name)))
+			return(dev);
+	}
+	return(NULL);
+}
+
+void mconsole_config(struct mc_request *req)
+{
+	struct mc_device *dev;
+	char *ptr = req->request.data;
+	int err;
+
+	ptr += strlen("config");
+	while(isspace(*ptr)) ptr++;
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "Bad configuration option", 1, 0);
+		return;
+	}
+	err = (*dev->config)(&ptr[strlen(dev->name)]);
+	mconsole_reply(req, "", err, 0);
+}
+
+void mconsole_remove(struct mc_request *req)
+{
+	struct mc_device *dev;	
+	char *ptr = req->request.data;
+	int err;
+
+	ptr += strlen("remove");
+	while(isspace(*ptr)) ptr++;
+	dev = mconsole_find_dev(ptr);
+	if(dev == NULL){
+		mconsole_reply(req, "Bad remove option", 1, 0);
+		return;
+	}
+	err = (*dev->remove)(&ptr[strlen(dev->name)]);
+	mconsole_reply(req, "", err, 0);
+}
+
+#ifdef CONFIG_MAGIC_SYSRQ
+void mconsole_sysrq(struct mc_request *req)
+{
+	char *ptr = req->request.data;
+
+	ptr += strlen("sysrq");
+	while(isspace(*ptr)) ptr++;
+
+	handle_sysrq(*ptr, &current->thread.regs, NULL);
+	mconsole_reply(req, "", 0, 0);
+}
+#else
+void mconsole_sysrq(struct mc_request *req)
+{
+	mconsole_reply(req, "Sysrq not compiled in", 1, 0);
+}
+#endif
+
+static char *notify_socket = NULL;
+
+int mconsole_init(void)
+{
+	int err, sock;
+	char file[256];
+
+	if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
+	snprintf(mconsole_socket_name, sizeof(file), "%s", file);
+
+	sock = create_unix_socket(file, sizeof(file));
+	if (sock < 0){
+		printk("Failed to initialize management console\n");
+		return(1);
+	}
+
+	register_reboot_notifier(&reboot_notifier);
+
+	err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
+			     SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
+			     "mconsole", (void *)sock);
+	if (err){
+		printk("Failed to get IRQ for management console\n");
+		return(1);
+	}
+
+	if(notify_socket != NULL){
+		notify_socket = uml_strdup(notify_socket);
+		if(notify_socket != NULL)
+			mconsole_notify(notify_socket, MCONSOLE_SOCKET,
+					mconsole_socket_name, 
+					strlen(mconsole_socket_name) + 1);
+		else printk(KERN_ERR "mconsole_setup failed to strdup "
+			    "string\n");
+	}
+
+	printk("mconsole (version %d) initialized on %s\n", 
+	       MCONSOLE_VERSION, mconsole_socket_name);
+	return(0);
+}
+
+__initcall(mconsole_init);
+
+static int write_proc_mconsole(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	char *buf;
+
+	buf = kmalloc(count + 1, GFP_KERNEL);
+	if(buf == NULL) 
+		return(-ENOMEM);
+
+	if(copy_from_user(buf, buffer, count))
+		return(-EFAULT);
+	buf[count] = '\0';
+
+	mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
+	return(count);
+}
+
+static int create_proc_mconsole(void)
+{
+	struct proc_dir_entry *ent;
+
+	if(notify_socket == NULL) return(0);
+
+	ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
+	if(ent == NULL){
+		printk("create_proc_mconsole : create_proc_entry failed\n");
+		return(0);
+	}
+
+	ent->read_proc = NULL;
+	ent->write_proc = write_proc_mconsole;
+	return(0);
+}
+
+__initcall(create_proc_mconsole);
+
+#define NOTIFY "=notify:"
+
+static int mconsole_setup(char *str)
+{
+	if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
+		str += strlen(NOTIFY);
+		notify_socket = str;
+	}
+	else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
+	return(1);
+}
+
+__setup("mconsole", mconsole_setup);
+
+__uml_help(mconsole_setup,
+"mconsole=notify:<socket>\n"
+"    Requests that the mconsole driver send a message to the named Unix\n"
+"    socket containing the name of the mconsole socket.  This also serves\n"
+"    to notify outside processes when UML has booted far enough to respond\n"
+"    to mconsole requests.\n\n"
+);
+
+static int notify_panic(struct notifier_block *self, unsigned long unused1,
+			void *ptr)
+{
+	char *message = ptr;
+
+	if(notify_socket == NULL) return(0);
+
+	mconsole_notify(notify_socket, MCONSOLE_PANIC, message, 
+			strlen(message) + 1);
+	return(0);
+}
+
+static struct notifier_block panic_exit_notifier = {
+	notifier_call :		notify_panic,
+	next :			NULL,
+	priority :		1
+};
+
+static int add_notifier(void)
+{
+	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
+	return(0);
+}
+
+__initcall(add_notifier);
+
+char *mconsole_notify_socket(void)
+{
+	return(notify_socket);
+}
+
+EXPORT_SYMBOL(mconsole_notify_socket);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mconsole_user.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include "user.h"
+#include "mconsole.h"
+#include "umid.h"
+
+static struct mconsole_command commands[] = {
+	{ "version", mconsole_version, 1 },
+	{ "halt", mconsole_halt, 0 },
+	{ "reboot", mconsole_reboot, 0 },
+	{ "config", mconsole_config, 0 },
+	{ "remove", mconsole_remove, 0 },
+	{ "sysrq", mconsole_sysrq, 1 },
+	{ "help", mconsole_help, 1 },
+	{ "cad", mconsole_cad, 1 },
+	{ "stop", mconsole_stop, 0 },
+	{ "go", mconsole_go, 1 },
+};
+
+char mconsole_socket_name[256];
+
+int mconsole_reply_v0(struct mc_request *req, char *reply)
+{
+        struct iovec iov;
+        struct msghdr msg;
+
+        iov.iov_base = reply;
+        iov.iov_len = strlen(reply);
+
+        msg.msg_name = &(req->origin);
+        msg.msg_namelen = req->originlen;
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_control = NULL;
+        msg.msg_controllen = 0;
+        msg.msg_flags = 0;
+
+        return sendmsg(req->originating_fd, &msg, 0);
+}
+
+static struct mconsole_command *mconsole_parse(struct mc_request *req)
+{
+	struct mconsole_command *cmd;
+	int i;
+
+	for(i=0;i<sizeof(commands)/sizeof(commands[0]);i++){
+		cmd = &commands[i];
+		if(!strncmp(req->request.data, cmd->command, 
+			    strlen(cmd->command))){
+			return(cmd);
+		}
+	}
+	return(NULL);
+}
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+
+#define STRINGX(x) #x
+#define STRING(x) STRINGX(x)
+
+int mconsole_get_request(int fd, struct mc_request *req)
+{
+	int len;
+
+	req->originlen = sizeof(req->origin);
+	req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
+			    (struct sockaddr *) req->origin, &req->originlen);
+	if (req->len < 0)
+		return 0;
+
+	req->originating_fd = fd;
+
+	if(req->request.magic != MCONSOLE_MAGIC){
+		/* Unversioned request */
+		len = MIN(sizeof(req->request.data) - 1, 
+			  strlen((char *) &req->request));
+		memmove(req->request.data, &req->request, len);
+		req->request.data[len] = '\0';
+
+		req->request.magic = MCONSOLE_MAGIC;
+		req->request.version = 0;
+		req->request.len = len;
+
+		mconsole_reply_v0(req, "ERR Version 0 mconsole clients are "
+				  "not supported by this driver");
+		return(0);
+	}
+
+	if(req->request.len >= MCONSOLE_MAX_DATA){
+		mconsole_reply(req, "Request too large", 1, 0);
+		return(0);
+	}
+	if(req->request.version != MCONSOLE_VERSION){
+		mconsole_reply(req, "This driver only supports version " 
+                               STRING(MCONSOLE_VERSION) " clients", 1, 0);
+	}
+	
+	req->request.data[req->request.len] = '\0';
+	req->cmd = mconsole_parse(req);
+	if(req->cmd == NULL){
+		mconsole_reply(req, "Unknown command", 1, 0);
+		return(0);
+	}
+
+	return(1);
+}
+
+int mconsole_reply(struct mc_request *req, char *str, int err, int more)
+{
+	struct mconsole_reply reply;
+	int total, len, n;
+
+	total = strlen(str);
+	do {
+		reply.err = err;
+
+		/* err can only be true on the first packet */
+		err = 0;
+
+		len = MIN(total, MCONSOLE_MAX_DATA - 1);
+
+		if(len == total) reply.more = more;
+		else reply.more = 1;
+
+		memcpy(reply.data, str, len);
+		reply.data[len] = '\0';
+		total -= len;
+		reply.len = len + 1;
+
+		len = sizeof(reply) + reply.len - sizeof(reply.data);
+
+		n = sendto(req->originating_fd, &reply, len, 0,
+			   (struct sockaddr *) req->origin, req->originlen);
+
+		if(n < 0) return(-errno);
+	} while(total > 0);
+	return(0);
+}
+
+int mconsole_unlink_socket(void)
+{
+	unlink(mconsole_socket_name);
+	return 0;
+}
+
+static int notify_sock = -1;
+
+int mconsole_notify(char *sock_name, int type, const void *data, int len)
+{
+	struct sockaddr_un target;
+	struct mconsole_notify packet;
+	int n, err;
+
+	if(notify_sock < 0){
+		notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+		if(notify_sock < 0){
+			printk("mconsole_notify - socket failed, errno = %d\n",
+			       errno);
+			return(-errno);
+		}
+	}
+
+	target.sun_family = AF_UNIX;
+	strcpy(target.sun_path, sock_name);
+
+	packet.magic = MCONSOLE_MAGIC;
+	packet.version = MCONSOLE_VERSION;
+	packet.type = type;
+	len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len;
+	packet.len = len;
+	memcpy(packet.data, data, len);
+
+	err = 0;
+	len = sizeof(packet) + packet.len - sizeof(packet.data);
+	n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, 
+		   sizeof(target));
+	if(n < 0){
+		printk("mconsole_notify - sendto failed, errno = %d\n", errno);
+		err = -errno;
+	}
+	return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/mmapper_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,148 @@
+/*
+ * arch/um/drivers/mmapper_kern.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ */
+#include <linux/kdev_t.h>
+#include <linux/time.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h> 
+#include <linux/slab.h>
+#include <linux/init.h> 
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/smplock.h>
+#include <asm/pgtable.h>
+#include "mem_user.h"
+#include "user_util.h"
+ 
+static unsigned long mmapper_size;
+static unsigned long p_buf = 0;
+static char *v_buf = NULL;
+
+static ssize_t
+mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	if(*ppos > mmapper_size)
+		return -EINVAL;
+
+	if(count + *ppos > mmapper_size)
+		count = count + *ppos - mmapper_size;
+
+	if(count < 0)
+		return -EINVAL;
+ 
+	copy_to_user(buf,&v_buf[*ppos],count);
+	
+	return count;
+}
+
+static ssize_t
+mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	if(*ppos > mmapper_size)
+		return -EINVAL;
+
+	if(count + *ppos > mmapper_size)
+		count = count + *ppos - mmapper_size;
+
+	if(count < 0)
+		return -EINVAL;
+
+	copy_from_user(&v_buf[*ppos],buf,count);
+	
+	return count;
+}
+
+static int 
+mmapper_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	 unsigned long arg)
+{
+	return(-ENOIOCTLCMD);
+}
+
+static int 
+mmapper_mmap(struct file *file, struct vm_area_struct * vma)
+{
+	int ret = -EINVAL;
+	int size;
+
+	lock_kernel();
+	if (vma->vm_pgoff != 0)
+		goto out;
+	
+	size = vma->vm_end - vma->vm_start;
+	if(size > mmapper_size) return(-EFAULT);
+
+	/* XXX A comment above remap_page_range says it should only be
+	 * called when the mm semaphore is held
+	 */
+	if (remap_page_range(vma, vma->vm_start, p_buf, size, 
+			     vma->vm_page_prot))
+		goto out;
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static int
+mmapper_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int 
+mmapper_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations mmapper_fops = {
+	owner:		THIS_MODULE,
+	read:		mmapper_read,
+	write:		mmapper_write,
+	ioctl:		mmapper_ioctl,
+	mmap:		mmapper_mmap,
+	open:		mmapper_open,
+	release:	mmapper_release,
+};
+
+static int __init mmapper_init(void)
+{
+	printk(KERN_INFO "Mapper v0.1\n");
+
+	v_buf = (char *) find_iomem("mmapper", &mmapper_size);
+	if(mmapper_size == 0) return(0);
+
+	p_buf = __pa(v_buf);
+
+	devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, 
+			30, 0, S_IFCHR | S_IRUGO | S_IWUGO, 
+			&mmapper_fops, NULL); 
+	devfs_mk_symlink(NULL, "mmapper0", DEVFS_FL_DEFAULT, "mmapper",
+			 NULL, NULL);
+	return(0);
+}
+
+static void mmapper_exit(void)
+{
+}
+
+module_init(mmapper_init);
+module_exit(mmapper_exit);
+
+MODULE_AUTHOR("Greg Lonnon <glonnon@ridgerun.com>");
+MODULE_DESCRIPTION("DSPLinux simulator mmapper driver");
+/*
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/net_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/netdevice.h"
+#include "linux/rtnetlink.h"
+#include "linux/skbuff.h"
+#include "linux/socket.h"
+#include "linux/spinlock.h"
+#include "linux/module.h"
+#include "linux/init.h"
+#include "linux/etherdevice.h"
+#include "linux/list.h"
+#include "linux/inetdevice.h"
+#include "linux/ctype.h"
+#include "linux/bootmem.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "mconsole_kern.h"
+#include "init.h"
+#include "irq_user.h"
+
+LIST_HEAD(opened);
+
+struct uml_net devices[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] = 
+	{
+		dev:		NULL,
+		user:		NULL,
+		kern:		NULL,
+		private_size:	0,
+	}
+};
+
+static int uml_net_rx(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	int pkt_len;
+	struct sk_buff *skb;
+
+	/* If we can't allocate memory, try again next round. */
+	if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
+		lp->stats.rx_dropped++;
+		reactivate_fd(lp->fd, UM_ETH_IRQ);
+		return 0;
+	}
+
+	skb->dev = dev;
+	skb_put(skb, dev->mtu);
+	skb->mac.raw = skb->data;
+	pkt_len = (*lp->read)(lp->fd, &skb, lp);
+
+	reactivate_fd(lp->fd, UM_ETH_IRQ);
+	if (pkt_len > 0) {
+		skb_trim(skb, pkt_len);
+		skb->protocol = (*lp->protocol)(skb);
+		netif_rx(skb);
+
+		lp->stats.rx_bytes += skb->len;
+		lp->stats.rx_packets++;
+		return pkt_len;
+	}
+
+	kfree_skb(skb);
+	return pkt_len;
+}
+
+void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct uml_net_private *lp = dev->priv;
+	int err;
+
+	if (netif_running(dev)) {
+		spin_lock(&lp->lock);
+		while((err = uml_net_rx(dev)) > 0) ;
+		if(err < 0) {
+			printk(KERN_ERR 
+			       "Device '%s' read returned %d, shutting it "
+			       "down\n", dev->name, err);
+			dev->flags &= ~IFF_UP;
+			dev_close(dev);
+		}
+		spin_unlock(&lp->lock);
+	}
+}
+
+static int uml_net_open(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	char addr[sizeof("255.255.255.255\0")];
+	int err;
+
+	spin_lock(&lp->lock);
+
+	if(lp->fd >= 0){
+		err = -ENXIO;
+		goto out;
+	}
+
+	if(!lp->have_mac){
+ 		dev_ip_addr(dev, addr, &lp->mac[2]);
+ 		set_ether_mac(dev, lp->mac);
+	}
+
+	lp->fd = (*lp->open)(&lp->user);
+	if(lp->fd < 0){
+		err = lp->fd;
+		goto out;
+	}
+
+	err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,
+			     SA_INTERRUPT | SA_SHIRQ, dev->name, dev);
+	if(err != 0){
+		printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);
+		if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
+		lp->fd = -1;
+		err = -ENETUNREACH;
+	}
+
+	lp->tl.data = (unsigned long) &lp->user;
+	netif_start_queue(dev);
+
+	list_add(&lp->list, &opened);
+	MOD_INC_USE_COUNT;
+ out:
+	spin_unlock(&lp->lock);
+	return(err);
+}
+
+static int uml_net_close(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	
+	netif_stop_queue(dev);
+	spin_lock(&lp->lock);
+
+	free_irq(dev->irq, dev);
+	if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
+	lp->fd = -1;
+	list_del(&lp->list);
+	
+	MOD_DEC_USE_COUNT;
+	spin_unlock(&lp->lock);
+	return 0;
+}
+
+static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	unsigned long flags;
+	int len;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	len = (*lp->write)(lp->fd, &skb, lp);
+
+	if(len == skb->len) {
+		lp->stats.tx_packets++;
+		lp->stats.tx_bytes += skb->len;
+		dev->trans_start = jiffies;
+		netif_start_queue(dev);
+
+		/* this is normally done in the interrupt when tx finishes */
+		netif_wake_queue(dev);
+	} 
+	else if(len == 0){
+		netif_start_queue(dev);
+		lp->stats.tx_dropped++;
+	}
+	else {
+		netif_start_queue(dev);
+		printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);
+	}
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static struct net_device_stats *uml_net_get_stats(struct net_device *dev)
+{
+	struct uml_net_private *lp = dev->priv;
+	return &lp->stats;
+}
+
+static void uml_net_set_multicast_list(struct net_device *dev)
+{
+	if (dev->flags & IFF_PROMISC) return;
+	else if (dev->mc_count)	dev->flags |= IFF_ALLMULTI;
+	else dev->flags &= ~IFF_ALLMULTI;
+}
+
+static void uml_net_tx_timeout(struct net_device *dev)
+{
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+static int uml_net_set_mac(struct net_device *dev, void *addr)
+{
+	struct uml_net_private *lp = dev->priv;
+	struct sockaddr *hwaddr = addr;
+
+	spin_lock(&lp->lock);
+	memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
+	spin_unlock(&lp->lock);
+
+	return(0);
+}
+
+static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct uml_net_private *lp = dev->priv;
+	int err = 0;
+
+	spin_lock(&lp->lock);
+
+	new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
+	if(new_mtu < 0){
+		err = new_mtu;
+		goto out;
+	}
+
+	dev->mtu = new_mtu;
+
+ out:
+	spin_unlock(&lp->lock);
+	return err;
+}
+
+static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return(-EINVAL);
+}
+
+void uml_net_user_timer_expire(unsigned long _conn)
+{
+#ifdef undef
+	struct connection *conn = (struct connection *)_conn;
+
+	dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
+	do_connect(conn);
+#endif
+}
+
+static int eth_configure(struct uml_net *device, int n)
+{
+	struct net_device *dev;
+	struct uml_net_private *lp;
+	int save, err;
+
+	device->private_size += sizeof(struct uml_net_private) + 
+		sizeof(((struct uml_net_private *) 0)->user);
+
+	printk(KERN_INFO "Netdevice %d ", n);
+	if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
+				    device->mac[0], device->mac[1], 
+				    device->mac[2], device->mac[3], 
+				    device->mac[4], device->mac[5]);
+	printk(": ");
+	dev = kmalloc(sizeof(*dev) + device->private_size, GFP_KERNEL);
+	if(dev == NULL){
+		printk(KERN_ERR "eth_configure: failed to allocate device\n");
+		return(1);
+	}
+	snprintf(dev->name, sizeof(dev->name), "eth%d", n);
+	dev->priv = (void *) &dev[1];
+	device->dev = dev;
+
+	(*device->kern->init)(dev, device->transport_index);
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if(err)
+		return(1);
+
+	dev->mtu = device->user->max_packet;
+	dev->open = uml_net_open;
+	dev->hard_start_xmit = uml_net_start_xmit;
+	dev->stop = uml_net_close;
+	dev->get_stats = uml_net_get_stats;
+	dev->set_multicast_list = uml_net_set_multicast_list;
+	dev->tx_timeout = uml_net_tx_timeout;
+	dev->set_mac_address = uml_net_set_mac;
+	dev->change_mtu = uml_net_change_mtu;
+	dev->do_ioctl = uml_net_ioctl;
+	dev->watchdog_timeo = (HZ >> 1);
+	dev->irq = UM_ETH_IRQ;
+
+	lp = dev->priv;
+
+	/* lp.user is the first four bytes of the transport data, which
+	 * has already been initialized.  This structure assignment will
+	 * overwrite that, so we make sure that .user gets overwritten with
+	 * what it already has.
+	 */
+	save = lp->user[0];
+	*lp = ((struct uml_net_private) 
+		{ list : 		LIST_HEAD_INIT(lp->list),
+		  lock :		SPIN_LOCK_UNLOCKED,
+		  dev :			dev,
+		  fd :			-1,
+		  mac :			{ 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
+		  have_mac :		device->have_mac,
+		  protocol :		device->kern->protocol,
+		  open :		device->user->open,
+		  close :		device->user->close,
+		  remove :		device->user->remove,
+		  read :		device->kern->read,
+		  write :		device->kern->write,
+		  add_address :		device->user->add_address,
+		  delete_address : 	device->user->delete_address,
+		  set_mtu :		device->user->set_mtu,
+		  user : 		{ save } });
+	init_timer(&lp->tl);
+	lp->tl.function = uml_net_user_timer_expire;
+	memset(&lp->stats, 0, sizeof(lp->stats));
+	if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac));
+
+	if(device->user->init) 
+		(*device->user->init)(&lp->user, dev);
+	if(device->have_mac)
+		set_ether_mac(dev, device->mac);
+	return(0);
+}
+
+static int eth_parse(char *str, int *index_out, char **str_out)
+{
+	char *end;
+	int n;
+
+	n = simple_strtoul(str, &end, 0);
+	if(end == str){
+		printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);
+		return(1);
+	}
+	if((n < 0) || (n > sizeof(devices)/sizeof(devices[0]))){
+		printk(KERN_ERR "eth_setup: device %d out of range\n", n);
+		return(1);
+	}
+	str = end;
+	if(*str != '='){
+		printk(KERN_ERR 
+		       "eth_setup: expected '=' after device number\n");
+		return(1);
+	}
+	str++;
+	if(devices[n].dev != NULL){
+		printk(KERN_ERR "eth_setup: Device %d already configured\n",
+		       n);
+		return(1);
+	}
+	if(index_out) *index_out = n;
+	*str_out = str;
+	return(0);
+}
+
+struct eth_init {
+	struct list_head list;
+	char *init;
+	int index;
+};
+
+struct list_head transports = LIST_HEAD_INIT(transports);
+
+struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
+
+void register_transport(struct transport *new)
+{
+	struct list_head *ele, *next;
+	struct eth_init *eth;
+	char *str;
+	int err;
+
+	list_add(&new->list, &transports);
+
+	list_for_each_safe(ele, next, &eth_cmd_line){
+		eth = list_entry(ele, struct eth_init, list);
+		if(!strncmp(eth->init, new->name, strlen(new->name))){
+			str = eth->init + strlen(new->name);
+			err = new->setup(str, &devices[eth->index]);
+			if(!err) eth_configure(&devices[eth->index], 
+					       eth->index);
+			list_del(&eth->list);
+		}
+	}
+}
+
+static int eth_setup_common(char *str, int index)
+{
+	struct list_head *ele;
+	struct transport *transport;
+
+	list_for_each(ele, &transports){
+		transport = list_entry(ele, struct transport, list);
+		if(!strncmp(str, transport->name, strlen(transport->name))){
+			str += strlen(transport->name);
+			return(transport->setup(str, &devices[index]));
+		}
+	}
+
+	return(-1);
+}
+
+static int eth_setup(char *str)
+{
+	struct eth_init *new;
+	int n, err;
+
+	err = eth_parse(str, &n, &str);
+	if(err) return(1);
+
+	new = alloc_bootmem(sizeof(new));
+	if(new == NULL){
+		printk("eth_init : alloc_bootmem failed\n");
+		return(1);
+	}
+	*new = ((struct eth_init) { list : 	LIST_HEAD_INIT(new->list),
+				    index : 	n,
+				    init :	str });
+	list_add_tail(&new->list, &eth_cmd_line);
+	return(1);
+}
+
+__setup("eth", eth_setup);
+__uml_help(eth_setup,
+"eth[0-9]+=<transport>,<options>\n"
+"    Configure a network device.\n\n"
+);
+
+int ndev = 0;
+
+static int eth_init(void)
+{
+	struct list_head *ele, *next;
+	struct eth_init *eth;
+	int err;
+
+	list_for_each_safe(ele, next, &eth_cmd_line){
+		eth = list_entry(ele, struct eth_init, list);
+		err = eth_setup_common(eth->init, eth->index);
+		if(!err) eth_configure(&devices[eth->index], eth->index);
+		if(err >= 0) list_del(&eth->list);
+	}
+	
+	return(1);
+}
+
+__initcall(eth_init);
+
+static int net_config(char *str)
+{
+	int err, n;
+
+	err = eth_parse(str, &n, &str);
+	if(err) return(err);
+
+	str = uml_strdup(str);
+	if(str == NULL){
+		printk(KERN_ERR "net_config failed to strdup string\n");
+		return(1);
+	}
+	err = eth_setup_common(str, n);
+	if(err){
+		kfree(str);
+		return(err);
+	}
+	err = eth_configure(&devices[n], n);
+	return(err);
+}
+
+static int net_remove(char *str)
+{
+	struct net_device *dev;
+	struct uml_net_private *lp;
+	int n;
+
+	if(!isdigit(*str)) return(-1);
+	n = *str - '0';
+	if(devices[n].dev == NULL) return(0);
+	dev = devices[n].dev;
+	lp = dev->priv;
+	if(lp->fd > 0) return(-1);
+	if(lp->remove != NULL) (*lp->remove)(&lp->user);
+	unregister_netdev(dev);
+	devices[n].dev = NULL;
+	return(0);
+}
+
+static struct mc_device net_mc = {
+	name:		"eth",
+	config:		net_config,
+	remove:		net_remove,
+};
+
+static int uml_inetaddr_event(struct notifier_block *this, unsigned long event,
+			      void *ptr)
+{
+	struct in_ifaddr *ifa = ptr;
+	u32 addr = ifa->ifa_address;
+	u32 netmask = ifa->ifa_mask;
+	struct net_device *dev = ifa->ifa_dev->dev;
+	struct uml_net_private *lp;
+	void (*proc)(unsigned char *, unsigned char *, void *);
+	unsigned char addr_buf[4], netmask_buf[4];
+
+	if(dev->open != uml_net_open) return(NOTIFY_DONE);
+
+	lp = dev->priv;
+
+	proc = NULL;
+	switch (event){
+	case NETDEV_UP:
+		proc = lp->add_address;
+		break;
+	case NETDEV_DOWN:
+		proc = lp->delete_address;
+		break;
+	}
+	if(proc != NULL){
+		addr_buf[0] = addr & 0xff;
+		addr_buf[1] = (addr >> 8) & 0xff;
+		addr_buf[2] = (addr >> 16) & 0xff;
+		addr_buf[3] = addr >> 24;
+		netmask_buf[0] = netmask & 0xff;
+		netmask_buf[1] = (netmask >> 8) & 0xff;
+		netmask_buf[2] = (netmask >> 16) & 0xff;
+		netmask_buf[3] = netmask >> 24;
+		(*proc)(addr_buf, netmask_buf, &lp->user);
+	}
+	return(NOTIFY_DONE);
+}
+
+struct notifier_block uml_inetaddr_notifier = {
+	notifier_call:		uml_inetaddr_event,
+};
+
+static int uml_net_init(void)
+{
+	struct list_head *ele;
+	struct uml_net_private *lp;	
+	struct in_device *ip;
+	struct in_ifaddr *in;
+
+	mconsole_register_dev(&net_mc);
+	register_inetaddr_notifier(&uml_inetaddr_notifier);
+
+	/* Devices may have been opened already, so the uml_inetaddr_notifier
+	 * didn't get a chance to run for them.  This fakes it so that
+	 * addresses which have already been set up get handled properly.
+	 */
+	list_for_each(ele, &opened){
+		lp = list_entry(ele, struct uml_net_private, list);
+		ip = lp->dev->ip_ptr;
+		if(ip == NULL) continue;
+		in = ip->ifa_list;
+		while(in != NULL){
+			uml_inetaddr_event(NULL, NETDEV_UP, in);
+			in = in->ifa_next;
+		}
+	}	
+
+	return(0);
+}
+
+__initcall(uml_net_init);
+
+static void close_devices(void)
+{
+	struct list_head *ele;
+	struct uml_net_private *lp;	
+
+	list_for_each(ele, &opened){
+		lp = list_entry(ele, struct uml_net_private, list);
+		if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
+		if(lp->remove != NULL) (*lp->remove)(&lp->user);
+	}
+}
+
+__uml_exitcall(close_devices);
+
+int setup_etheraddr(char *str, unsigned char *addr)
+{
+	char *end;
+	int i;
+
+	for(i=0;i<6;i++){
+		addr[i] = simple_strtoul(str, &end, 16);
+		if((end == str) ||
+		   ((*end != ':') && (*end != ',') && (*end != '\0'))){
+			printk(KERN_ERR 
+			       "setup_etheraddr: failed to parse '%s' "
+			       "as an ethernet address\n", str);
+			return(-1);
+		}
+		str = end + 1;
+	}
+	if(addr[0] & 1){
+		printk(KERN_ERR 
+		       "Attempt to assign a broadcast ethernet address to a "
+		       "device disallowed\n");
+		return(-1);
+	}
+	return(0);
+}
+
+void dev_ip_addr(void *d, char *buf, char *bin_buf)
+{
+	struct net_device *dev = d;
+	struct in_device *ip = dev->ip_ptr;
+	struct in_ifaddr *in;
+	u32 addr;
+
+	if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
+		printk(KERN_WARNING "dev_ip_addr - device not assigned an "
+		       "IP address\n");
+		return;
+	}
+	addr = in->ifa_address;
+	sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, 
+		(addr >> 16) & 0xff, addr >> 24);
+	if(bin_buf){
+		bin_buf[0] = addr & 0xff;
+		bin_buf[1] = (addr >> 8) & 0xff;
+		bin_buf[2] = (addr >> 16) & 0xff;
+		bin_buf[3] = addr >> 24;
+	}
+}
+
+void set_ether_mac(void *d, unsigned char *addr)
+{
+	struct net_device *dev = d;
+
+	memcpy(dev->dev_addr, addr, ETH_ALEN);	
+}
+
+struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
+{
+	if((skb != NULL) && (skb_tailroom(skb) < extra)){
+	  	struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
+		dev_kfree_skb(skb);
+		skb = skb2;
+	}
+	if(skb != NULL) skb_put(skb, extra);
+	return(skb);
+}
+
+void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, 
+					void *), 
+		    void *arg)
+{
+	struct net_device *dev = d;
+	struct in_device *ip = dev->ip_ptr;
+	struct in_ifaddr *in;
+	unsigned char address[4], netmask[4];
+
+	if(ip == NULL) return;
+	in = ip->ifa_list;
+	while(in != NULL){
+		address[0] = in->ifa_address & 0xff;
+		address[1] = (in->ifa_address >> 8) & 0xff;
+		address[2] = (in->ifa_address >> 16) & 0xff;
+		address[3] = in->ifa_address >> 24;
+		netmask[0] = in->ifa_mask & 0xff;
+		netmask[1] = (in->ifa_mask >> 8) & 0xff;
+		netmask[2] = (in->ifa_mask >> 16) & 0xff;
+		netmask[3] = in->ifa_mask >> 24;
+		(*cb)(address, netmask, arg);
+		in = in->ifa_next;
+	}
+}
+
+void *get_output_buffer(int *len_out)
+{
+	void *ret;
+
+	ret = (void *) __get_free_pages(GFP_KERNEL, 0);
+	if(ret) *len_out = PAGE_SIZE;
+	else *len_out = 0;
+	return(ret);
+}
+
+void free_output_buffer(void *buffer)
+{
+	free_pages((unsigned long) buffer, 0);
+}
+
+int tap_setup_common(char *str, char *type, char **dev_name, char *mac, 
+		     int *have_mac, char **gate_addr)
+{
+	int err;
+
+	if(*str != ','){
+		printk(KERN_ERR 
+		       "ethertap_setup: expected ',' after '%s'\n", type);
+		return(1);
+	}
+	str++;
+	if(*str != ',') *dev_name = str;
+	str = strchr(str, ',');
+	if(str == NULL) return(0);
+	*str++ = '\0';
+	if(*str != ','){
+		err = setup_etheraddr(str, mac);
+		if(!err) *have_mac = 1;
+	}
+	str = strchr(str, ',');
+	if(str == NULL) return(0);
+	*str++ = '\0';
+	if(*str != '\0') *gate_addr = str;
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/net_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,232 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "net_user.h"
+#include "helper.h"
+#include "os.h"
+
+int tap_open_common(void *dev, char *gate_addr)
+{
+	int tap_addr[4];
+
+	if(gate_addr == NULL) return(0);
+	if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
+		  &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
+		printk("Invalid tap IP address - '%s'\n", 
+		       gate_addr);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+void tap_check_ips(char *gate_addr, char *eth_addr)
+{
+	int tap_addr[4];
+
+	if((gate_addr != NULL) && 
+	   (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
+		   &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) &&
+	   (eth_addr[0] == tap_addr[0]) && 
+	   (eth_addr[1] == tap_addr[1]) && 
+	   (eth_addr[2] == tap_addr[2]) && 
+	   (eth_addr[3] == tap_addr[3])){
+		printk("The tap IP address and the UML eth IP address"
+		       " must be different\n");
+	}
+}
+
+void read_output(int fd, char *output, int len)
+{
+	int remain, n, actual;
+	char c;
+
+	if(output == NULL){
+		output = &c;
+		len = sizeof(c);
+	}
+		
+	*output = '\0';
+	if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){
+		printk("read_output - read of length failed, errno = %d\n",
+		       errno);
+		return;
+	}
+
+	while(remain != 0){
+		n = (remain < len) ? remain : len;
+		actual = read(fd, output, n);
+		if(actual != n){
+			printk("read_output - read of data failed, "
+			       "errno = %d\n", errno);
+			return;
+		}
+		remain -= actual;
+	}
+	return;
+}
+
+int net_read(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = read(fd,  buf,  len)) < 0) && (errno == EINTR)) ;
+
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);
+}
+
+int net_recvfrom(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = recvfrom(fd,  buf,  len, 0, NULL, NULL)) < 0) && 
+	      (errno == EINTR)) ;
+
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);
+}
+
+int net_write(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+int net_send(int fd, void *buf, int len)
+{
+	int n;
+
+	while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
+{
+	int n;
+
+	while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to,
+			   sock_len)) < 0) && (errno == EINTR)) ;
+	if(n < 0){
+		if(errno == EAGAIN) return(0);
+		return(-errno);
+	}
+	else if(n == 0) return(-ENOTCONN);
+	return(n);	
+}
+
+struct change_pre_exec_data {
+	int close_me;
+	int stdout;
+};
+
+static void change_pre_exec(void *arg)
+{
+	struct change_pre_exec_data *data = arg;
+
+	close(data->close_me);
+	dup2(data->stdout, 1);
+}
+
+static int change_tramp(char **argv, char *output, int output_len)
+{
+	int pid, fds[2], err;
+	struct change_pre_exec_data pe_data;
+
+	err = os_pipe(fds, 1, 0);
+	if(err){
+		printk("change_tramp - pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+	pe_data.close_me = fds[0];
+	pe_data.stdout = fds[1];
+	pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
+
+	close(fds[1]);
+	read_output(fds[0], output, output_len);
+	waitpid(pid, NULL, 0);	
+	return(pid);
+}
+
+static void change(char *dev, char *what, unsigned char *addr,
+		   unsigned char *netmask)
+{
+	char addr_buf[sizeof("255.255.255.255\0")];
+	char netmask_buf[sizeof("255.255.255.255\0")];
+	char version[sizeof("nnnnn\0")];
+	char *argv[] = { "uml_net", version, what, dev, addr_buf, 
+			 netmask_buf, NULL };
+	char *output;
+	int output_len, pid;
+
+	sprintf(version, "%d", UML_NET_VERSION);
+	sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
+	sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 
+		netmask[2], netmask[3]);
+
+	output_len = page_size();
+	output = um_kmalloc(output_len);
+	if(output == NULL)
+		printk("change : failed to allocate output buffer\n");
+
+	pid = change_tramp(argv, output, output_len);
+	if(pid < 0) return;
+
+	if(output != NULL){
+		printk("%s", output);
+		kfree(output);
+	}
+}
+
+void open_addr(unsigned char *addr, unsigned char *netmask, void *arg)
+{
+	change(arg, "add", addr, netmask);
+}
+
+void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
+{
+	change(arg, "del", addr, netmask);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/null.c b/arch/um/drivers/null.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/null.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,53 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include "chan_user.h"
+#include "os.h"
+
+static int null_chan;
+
+void *null_init(char *str, int device, struct chan_opts *opts)
+{
+	return(&null_chan);
+}
+
+int null_open(int input, int output, int primary, void *d)
+{
+	return(os_open_file(DEV_NULL, of_rdwr(OPENFLAGS()), 0));
+}
+
+int null_read(int fd, char *c_out, void *unused)
+{
+	return(-ENODEV);
+}
+
+void null_free(void *data)
+{
+}
+
+struct chan_ops null_ops = {
+	init:		null_init,
+	open:		null_open,
+	close:		generic_close,
+	read:		null_read,
+	write:		generic_write,
+	console_write:	generic_console_write,
+	window_size:	generic_window_size,
+	free:		null_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/port.h b/arch/um/drivers/port.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/port.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,30 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PORT_H__
+#define __PORT_H__
+
+extern void *port_data(int port);
+extern int port_wait(void *data);
+extern void port_kern_close(void *d);
+extern int port_connection(int fd, int *socket_out, int *pid_out);
+extern int port_listen_fd(int port);
+extern void port_read(int fd, void *data);
+extern void port_kern_free(void *d);
+extern int port_rcv_fd(int fd);
+extern void port_remove_dev(void *d);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/port_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,254 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/list.h"
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/irq.h"
+#include "linux/spinlock.h"
+#include "linux/errno.h"
+#include "asm/semaphore.h"
+#include "asm/errno.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "port.h"
+#include "init.h"
+#include "os.h"
+
+struct port_list {
+	struct list_head list;
+	struct semaphore sem;
+	int port;
+	int fd;
+	spinlock_t lock;
+	struct list_head pending;
+	struct list_head connections;
+};
+
+struct port_dev {
+	struct port_list *port;
+	int fd;
+ 	int helper_pid;
+ 	int telnetd_pid;
+};
+
+struct connection {
+	struct list_head list;
+	int fd;
+ 	int helper_pid;
+	int socket[2];
+	int telnetd_pid;
+	struct port_list *port;
+};
+
+static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct connection *conn = data;
+	int fd;
+
+	list_del(&conn->list);
+
+ 	fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
+	if(fd < 0){
+		printk("os_accept_connection returned %d\n", -fd);
+		os_close_file(conn->fd);
+	}
+	conn->fd = fd;
+	list_add(&conn->list, &conn->port->connections);
+
+	up(&conn->port->sem);
+}
+
+struct list_head ports = LIST_HEAD_INIT(ports);
+
+static void port_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct port_list *port = data;
+	struct connection *conn;
+	int fd, socket[2], pid;
+
+	fd = port_connection(port->fd, socket, &pid);
+	if(fd < 0){
+		printk("port_connection returned %d\n", -fd);
+		goto out;
+	}
+
+	conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
+	if(conn == NULL){
+		printk("port_interrupt : failed to allocate connection\n");
+		goto out_close;
+	}
+	*conn = ((struct connection) 
+		{ list :	LIST_HEAD_INIT(conn->list),
+		  fd :		fd,
+		  socket : 	{ socket[0], socket[1] },
+		  telnetd_pid :	pid,
+		  port :	port });
+
+	if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, 
+			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+			  "telnetd", conn)){
+		printk(KERN_ERR "Failed to get IRQ for telnetd\n");
+		goto out_free;
+	}
+
+	list_add(&conn->list, &port->pending);
+	goto out;
+
+ out_free:
+	kfree(conn);
+ out_close:
+	os_close_file(fd);
+	if(pid != -1) os_kill_process(pid);
+ out:
+	reactivate_fd(port->fd, ACCEPT_IRQ);
+} 
+
+void *port_data(int port_num)
+{
+	struct list_head *ele;
+	struct port_list *port;
+	struct port_dev *dev;
+	int fd;
+
+	list_for_each(ele, &ports){
+		port = list_entry(ele, struct port_list, list);
+		if(port->port == port_num) goto found;
+	}
+	port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
+	if(port == NULL){
+		printk(KERN_ERR "Allocation of port list failed\n");
+		return(NULL);
+	}
+
+	fd = port_listen_fd(port_num);
+	if(fd < 0){
+		printk(KERN_ERR "binding to port %d failed, errno = %d\n",
+		       port_num, -fd);
+		goto out_free;
+	}
+	if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, 
+			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port",
+			  port)){
+		printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
+		goto out_close;
+	}
+
+	*port = ((struct port_list) 
+		{ list : 	LIST_HEAD_INIT(port->list),
+		  sem :		__SEMAPHORE_INITIALIZER(port->sem, 0),
+		  lock :	SPIN_LOCK_UNLOCKED,
+		  port : 	port_num,
+		  fd : 		fd,
+		  pending :	LIST_HEAD_INIT(port->pending),
+		  connections :	LIST_HEAD_INIT(port->connections) });
+	list_add(&port->list, &ports);
+
+ found:
+	dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
+	if(dev == NULL){
+		printk(KERN_ERR "Allocation of port device entry failed\n");
+		return(NULL);
+	}
+
+ 	*dev = ((struct port_dev) { port : 		port,
+ 				    fd :		-1,
+ 				    helper_pid : 	-1 });
+	return(dev);
+
+ out_free:
+	kfree(port);
+ out_close:
+	os_close_file(fd);
+	return(NULL);
+}
+
+void port_remove_dev(void *d)
+{
+	struct port_dev *dev = d;
+
+  	if(dev->helper_pid != -1)
+ 		os_kill_process(dev->helper_pid);
+ 	if(dev->telnetd_pid != -1)
+ 		os_kill_process(dev->telnetd_pid);
+ 	dev->helper_pid = -1;
+}
+
+static void free_port(void)
+{
+	struct list_head *ele;
+	struct port_list *port;
+
+	list_for_each(ele, &ports){
+		port = list_entry(ele, struct port_list, list);
+ 		free_irq(ACCEPT_IRQ, port);
+		os_close_file(port->fd);
+	}
+}
+
+__uml_exitcall(free_port);
+
+int port_wait(void *data)
+{
+	struct port_dev *dev = data;
+	struct connection *conn;
+	struct port_list *port = dev->port;
+
+	while(1){
+		if(down_interruptible(&port->sem)) return(-ERESTARTSYS);
+
+		spin_lock(&port->lock);
+
+		conn = list_entry(port->connections.next, struct connection, 
+				  list);
+		list_del(&conn->list);
+		spin_unlock(&port->lock);
+
+		os_shutdown_socket(conn->socket[0], 1, 1);
+		os_close_file(conn->socket[0]);
+		os_shutdown_socket(conn->socket[1], 1, 1);
+		os_close_file(conn->socket[1]);	
+
+		/* This is done here because freeing an IRQ can't be done
+		 * within the IRQ handler.  So, pipe_interrupt always ups
+		 * the semaphore regardless of whether it got a successful
+		 * connection.  Then we loop here throwing out failed 
+		 * connections until a good one is found.
+		 */
+		free_irq(TELNETD_IRQ, conn);
+
+		if(conn->fd >= 0) break;
+		os_close_file(conn->fd);
+		kfree(conn);
+	}
+
+	dev->fd = conn->fd;
+	dev->helper_pid = conn->helper_pid;
+	dev->telnetd_pid = conn->telnetd_pid;
+	kfree(conn);
+
+	return(dev->fd);
+}
+
+void port_kern_free(void *d)
+{
+	struct port_dev *dev = d;
+
+ 	if(dev->helper_pid != -1) os_kill_process(dev->telnetd_pid);
+ 	if(dev->telnetd_pid != -1) os_kill_process(dev->telnetd_pid);
+	kfree(dev);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/port_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,227 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "chan_user.h"
+#include "port.h"
+#include "helper.h"
+#include "os.h"
+
+struct port_chan {
+	int raw;
+	struct termios tt;
+	void *kernel_data;
+};
+
+void *port_init(char *str, int device, struct chan_opts *opts)
+{
+	struct port_chan *data;
+	void *kern_data;
+	char *end;
+	int port;
+
+	if(*str != ':'){
+		printk("port_init : channel type 'port' must specify a "
+		       "port number\n");
+		return(NULL);
+	}
+	str++;
+	port = strtoul(str, &end, 0);
+	if(*end != '\0'){
+		printk("port_init : couldn't parse port '%s'\n", str);
+		return(NULL);
+	}
+
+	if((kern_data = port_data(port)) == NULL) return(NULL);
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct port_chan) { raw : 		opts->raw,
+				      kernel_data :	kern_data });
+	
+	return(data);
+}
+
+int port_open(int input, int output, int primary, void *d)
+{
+	struct port_chan *data = d;
+	int fd;
+
+	fd = port_wait(data->kernel_data);
+	if((fd >= 0) && data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	return(fd);
+}
+
+void port_close(int fd, void *d)
+{
+	struct port_chan *data = d;
+
+	port_remove_dev(data->kernel_data);
+	close(fd);
+}
+
+int port_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct port_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+void port_free(void *d)
+{
+	struct port_chan *data = d;
+
+	port_kern_free(data->kernel_data);
+	kfree(data);
+}
+
+struct chan_ops port_ops = {
+	init:		port_init,
+	open:		port_open,
+	close:		port_close,
+	read:	        generic_read,
+	write:		generic_write,
+	console_write:	port_console_write,
+	window_size:	generic_window_size,
+	free:		port_free,
+	winch:		1,
+};
+
+int port_listen_fd(int port)
+{
+	struct sockaddr_in addr;
+	int fd, err;
+
+	fd = socket(PF_INET, SOCK_STREAM, 0);
+	if(fd == -1) return(-errno);
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){
+		err = -errno;
+		goto out;
+	}
+  
+	if(listen(fd, 1) < 0){
+		err = -errno;
+		goto out;
+	}
+
+	return(fd);
+ out:
+	os_close_file(fd);
+	return(err);
+}
+
+int port_rcv_fd(int fd)
+{
+	int new, n;
+	char buf[CMSG_SPACE(sizeof(new))];
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = NULL;
+	msg.msg_iovlen = 0;
+	msg.msg_control = buf;
+	msg.msg_controllen = sizeof(buf);
+	msg.msg_flags = 0;
+
+	n = recvmsg(fd, &msg, 0);
+	if(n < 0){
+		printk("rcv_fd : recvmsg failed - errno = %d\n", errno);
+		return(-1);
+	}
+  
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if(cmsg == NULL){
+		printk("rcv_fd didn't receive anything, error = %d\n", errno);
+		return(-1);
+	}
+	if((cmsg->cmsg_level != SOL_SOCKET) || 
+	   (cmsg->cmsg_type != SCM_RIGHTS)){
+		printk("rcv_fd didn't receive a descriptor\n");
+		return(-1);
+	}
+
+	new = ((int *) CMSG_DATA(cmsg))[0];
+	return(new);
+}
+
+struct port_pre_exec_data {
+	int sock_fd;
+	int pipe_fd;
+};
+
+void port_pre_exec(void *arg)
+{
+	struct port_pre_exec_data *data = arg;
+
+	dup2(data->sock_fd, 0);
+	dup2(data->sock_fd, 1);
+	dup2(data->sock_fd, 2);
+	close(data->sock_fd);
+	dup2(data->pipe_fd, 3);
+	os_shutdown_socket(3, 1, 0);
+	close(data->pipe_fd);
+}
+
+int port_connection(int fd, int *socket, int *pid_out)
+{
+	int new, err;
+	char *argv[] = { "/usr/sbin/in.telnetd", "-L", 
+			 "/usr/lib/uml/port-helper", NULL };
+	struct port_pre_exec_data data;
+
+	if((new = accept(fd, NULL, 0)) < 0) return(-errno);
+
+	err = os_pipe(socket, 0, 0);
+	if(err) goto out_close;
+
+	data = ((struct port_pre_exec_data)
+		{ sock_fd : 		new,
+		  pipe_fd :		socket[1] });
+
+	err = run_helper(port_pre_exec, &data, argv, NULL);
+	if(err < 0) goto out_shutdown;
+
+	*pid_out = err;
+	return(new);
+
+ out_shutdown:
+	os_shutdown_socket(socket[0], 1, 1);
+	close(socket[0]);
+	os_shutdown_socket(socket[1], 1, 1);	
+	close(socket[1]);
+ out_close:
+	close(new);
+	return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/pty.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,156 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "chan_user.h"
+#include "user.h"
+#include "user_util.h"
+#include "kern_util.h"
+
+struct pty_chan {
+	void (*announce)(char *dev_name, int dev);
+	int dev;
+	int raw;
+	struct termios tt;
+};
+
+void *pty_chan_init(char *str, int device, struct chan_opts *opts)
+{
+	struct pty_chan *data;
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct pty_chan) { announce : 	opts->announce, 
+				     dev : 		device,
+				     raw : 		opts->raw });
+	return(data);
+}
+
+int pts_open(int input, int output, int primary, void *d)
+{
+	struct pty_chan *data = d;
+	int fd;
+
+	if((fd = get_pty()) < 0){
+		printk("open_pts : Failed to open pts\n");
+		return(-errno);
+	}
+	if(data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	if(data->announce) (*data->announce)(ptsname(fd), data->dev);
+	return(fd);
+}
+
+int getmaster(char *line)
+{
+	struct stat stb;
+	char *pty, *bank, *cp;
+	int master;
+
+	pty = &line[strlen("/dev/ptyp")];
+	for (bank = "pqrs"; *bank; bank++) {
+		line[strlen("/dev/pty")] = *bank;
+		*pty = '0';
+		if (stat(line, &stb) < 0)
+			break;
+		for (cp = "0123456789abcdef"; *cp; cp++) {
+			*pty = *cp;
+			master = open(line, O_RDWR);
+			if (master >= 0) {
+				char *tp = &line[strlen("/dev/")];
+				int ok;
+
+				/* verify slave side is usable */
+				*tp = 't';
+				ok = access(line, R_OK|W_OK) == 0;
+				*tp = 'p';
+				if (ok) return(master);
+				(void) close(master);
+			}
+		}
+	}
+	return(-1);
+}
+
+struct grantpt_info {
+	int fd;
+	int res;
+	int err;
+};
+
+static void grantpt_cb(void *arg)
+{
+	struct grantpt_info *info = arg;
+
+	info->res = grantpt(info->fd);
+	info->err = errno;
+}
+
+int pty_open(int input, int output, int primary, void *d)
+{
+	struct pty_chan *data = d;
+	int fd;
+	char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
+	struct grantpt_info info;
+
+	fd = getmaster(dev);
+	if(fd < 0) return(-errno);
+	
+	info.fd = fd;
+	tracing_cb(grantpt_cb, &info);
+	unlockpt(fd);
+
+	if(data->raw) raw(fd, 0);
+	if(data->announce) (*data->announce)(dev, data->dev);
+	return(fd);
+}
+
+int pty_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct pty_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops pty_ops = {
+	init:		pty_chan_init,
+	open:		pty_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	pty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+struct chan_ops pts_ops = {
+	init:		pty_chan_init,
+	open:		pts_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	pty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/slip.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,34 @@
+#ifndef __UM_SLIP_H
+#define __UM_SLIP_H
+
+#define BUF_SIZE 1500
+
+struct slip_data {
+	void *dev;
+	char name[sizeof("slnnnnn\0")];
+	char *addr;
+	char *gate_addr;
+	int slave;
+	char buf[2 * BUF_SIZE];
+	int pos;
+	int esc;
+};
+
+extern struct net_user_info slip_user_info;
+
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
+extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/slip_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,109 @@
+#include "linux/kernel.h"
+#include "linux/stddef.h"
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/if_arp.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "kern.h"
+#include "slip.h"
+#include "slip_kern.h"
+
+struct slip_data slip_priv[MAX_UML_NETDEV] = {
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		addr:		NULL,
+		gate_addr:	NULL,
+		slave:		-1,
+		buf: 		{ 0 },
+		pos:		0,
+		esc:		0,
+	}
+};
+
+void slip_init(struct net_device *dev, int index)
+{
+	struct uml_net_private *private;
+	struct slip_data *spri;
+
+	private = dev->priv;
+	spri = (struct slip_data *) private->user;
+	*spri = slip_priv[index];
+	strncpy(dev->name, "umn", IFNAMSIZ);
+	dev->init = NULL;
+	dev->hard_header_len = 0;
+	dev->addr_len = 4;
+	dev->type = ARPHRD_ETHER;
+	dev->tx_queue_len = 256;
+	dev->flags = IFF_NOARP;
+	if(register_netdev(dev))
+		printk(KERN_ERR "Couldn't initialize umn\n");
+	printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr);
+}
+
+static unsigned short slip_protocol(struct sk_buff *skbuff)
+{
+	return(htons(ETH_P_IP));
+}
+
+static int slip_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, 
+			      (struct slip_data *) &lp->user));
+}
+
+static int slip_write(int fd, struct sk_buff **skb,
+		      struct uml_net_private *lp)
+{
+	return(slip_user_write(fd, (*skb)->data, (*skb)->len, 
+			       (struct slip_data *) &lp->user));
+}
+
+struct net_kern_info slip_kern_info = {
+	init:			slip_init,
+	protocol:		slip_protocol,
+	read:			slip_read,
+	write:			slip_write,
+};
+
+static int slip_count = 0;
+
+int slip_setup(char *str, struct uml_net *dev)
+{
+	int n = slip_count;
+
+	dev->user = &slip_user_info;
+	dev->kern = &slip_kern_info;
+	dev->private_size = sizeof(struct slip_data);
+	dev->transport_index = slip_count++;
+	if(*str != ',') return(0);
+	str++;
+	if(str[0] != '\0') slip_priv[n].gate_addr = str;
+	return(0);
+}
+
+static struct transport slip_transport = {
+	list :	LIST_HEAD_INIT(slip_transport.list),
+	name :	"slip",
+	setup : slip_setup
+};
+
+static int register_slip(void)
+{
+	register_transport(&slip_transport);
+	return(1);
+}
+
+__initcall(register_slip);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/slip_kern.h b/arch/um/drivers/slip_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/slip_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,8 @@
+#ifndef __UM_SLIP_KERN_H
+#define __UM_SLIP_KERN_H
+
+#include "net_kern.h"
+
+extern int slip_setup(char *arg, struct uml_net *dev);
+
+#endif
diff -Nru a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/slip_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,333 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/errno.h>
+#include <sys/termios.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "net_user.h"
+#include "slip.h"
+#include "helper.h"
+#include "os.h"
+
+void slip_user_init(void *data, void *dev)
+{
+	struct slip_data *pri = data;
+
+	pri->dev = dev;
+}
+
+static int set_up_tty(int fd)
+{
+	int i;
+	struct termios tios;
+
+	if (tcgetattr(fd, &tios) < 0) {
+		printk("could not get initial terminal attributes\n");
+		return(-1);
+	}
+
+	tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
+	tios.c_iflag = IGNBRK | IGNPAR;
+	tios.c_oflag = 0;
+	tios.c_lflag = 0;
+	for (i = 0; i < NCCS; i++)
+		tios.c_cc[i] = 0;
+	tios.c_cc[VMIN] = 1;
+	tios.c_cc[VTIME] = 0;
+
+	cfsetospeed(&tios, B38400);
+	cfsetispeed(&tios, B38400);
+
+	if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+		printk("failed to set terminal attributes\n");
+		return(-1);
+	}
+	return(0);
+}
+
+struct slip_pre_exec_data {
+	int stdin;
+	int stdout;
+	int close_me;
+};
+
+static void slip_pre_exec(void *arg)
+{
+	struct slip_pre_exec_data *data = arg;
+
+	if(data->stdin != -1) dup2(data->stdin, 0);
+	dup2(data->stdout, 1);
+	close(data->close_me);
+}
+
+static int slip_tramp(char **argv, int fd)
+{
+	struct slip_pre_exec_data pe_data;
+	char *output;
+	int status, pid, fds[2], err, output_len;
+
+	err = os_pipe(fds, 1, 0);
+	if(err){
+		printk("slip_tramp : pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+
+	err = 0;
+	pe_data.stdin = fd;
+	pe_data.stdout = fds[1];
+	pe_data.close_me = fds[0];
+	pid = run_helper(slip_pre_exec, &pe_data, argv, NULL);
+
+	if(pid < 0) err = pid;
+	else {
+		output_len = page_size();
+		output = um_kmalloc(output_len);
+		if(output == NULL)
+			printk("slip_tramp : failed to allocate output "
+			       "buffer\n");
+
+		close(fds[1]);
+		read_output(fds[0], output, output_len);
+		if(output != NULL){
+			printk("%s", output);
+			kfree(output);
+		}
+		if(waitpid(pid, &status, 0) < 0) err = errno;
+		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+			printk("'%s' didn't exit with status 0\n", argv[0]);
+			err = EINVAL;
+		}
+	}
+	return(err);
+}
+
+static int slip_open(void *data)
+{
+	struct slip_data *pri = data;
+	char version_buf[sizeof("nnnnn\0")];
+	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+	char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 
+			 NULL };
+	int sfd, mfd, disc, sencap, err;
+
+	if((mfd = get_pty()) < 0){
+		printk("umn : Failed to open pty\n");
+		return(-1);
+	}
+	if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){
+		printk("Couldn't open tty for slip line\n");
+		return(-1);
+	}
+	if(set_up_tty(sfd)) return(-1);
+	pri->slave = sfd;
+	pri->pos = 0;
+	pri->esc = 0;
+	if(pri->gate_addr != NULL){
+		sprintf(version_buf, "%d", UML_NET_VERSION);
+		strcpy(gate_buf, pri->gate_addr);
+
+		err = slip_tramp(argv, sfd);
+
+		if(err != 0){
+			printk("slip_tramp failed - errno = %d\n", err);
+			return(-err);
+		}
+		if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){
+			printk("SIOCGIFNAME failed, errno = %d\n", errno);
+			return(-errno);
+		}
+		iter_addresses(pri->dev, open_addr, pri->name);
+	}
+	else {
+		disc = N_SLIP;
+		if(ioctl(sfd, TIOCSETD, &disc) < 0){
+			printk("Failed to set slip line discipline - "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+		sencap = 0;
+		if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
+			printk("Failed to sett slip encapsulation - "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+	}
+	return(mfd);
+}
+
+static void slip_close(int fd, void *data)
+{
+	struct slip_data *pri = data;
+	char version_buf[sizeof("nnnnn\0")];
+	char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 
+			 NULL };
+	int err;
+
+	if(pri->gate_addr != NULL)
+		iter_addresses(pri->dev, close_addr, pri->name);
+
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+
+	err = slip_tramp(argv, -1);
+
+	if(err != 0)
+		printk("slip_tramp failed - errno = %d\n", err);
+	close(fd);
+	close(pri->slave);
+	pri->slave = -1;
+}
+
+/* SLIP protocol characters. */
+#define END             0300		/* indicates end of frame	*/
+#define ESC             0333		/* indicates byte stuffing	*/
+#define ESC_END         0334		/* ESC ESC_END means END 'data'	*/
+#define ESC_ESC         0335		/* ESC ESC_ESC means ESC 'data'	*/
+
+static int slip_unesc(struct slip_data *sl, unsigned char c)
+{
+	int ret;
+
+	switch(c){
+	case END:
+		sl->esc = 0;
+		ret = sl->pos;
+		sl->pos = 0;
+		return(ret);
+	case ESC:
+		sl->esc = 1;
+		return(0);
+	case ESC_ESC:
+		if(sl->esc){
+			sl->esc = 0;
+			c = ESC;
+		}
+		break;
+	case ESC_END:
+		if(sl->esc){
+			sl->esc = 0;
+			c = END;
+		}
+		break;
+	}
+	sl->buf[sl->pos++] = c;
+	return(0);
+}
+
+int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
+{
+	int i, n, size, start;
+
+	n = net_read(fd, &pri->buf[pri->pos], sizeof(pri->buf) - pri->pos);
+	if(n <= 0) return(n);
+
+	start = pri->pos;
+	for(i = 0; i < n; i++){
+		size = slip_unesc(pri, pri->buf[start + i]);
+		if(size){
+			memcpy(buf, pri->buf, size);
+			return(size);
+		}
+	}
+	return(0);
+}
+
+static int slip_esc(unsigned char *s, unsigned char *d, int len)
+{
+	unsigned char *ptr = d;
+	unsigned char c;
+
+	/*
+	 * Send an initial END character to flush out any
+	 * data that may have accumulated in the receiver
+	 * due to line noise.
+	 */
+
+	*ptr++ = END;
+
+	/*
+	 * For each byte in the packet, send the appropriate
+	 * character sequence, according to the SLIP protocol.
+	 */
+
+	while (len-- > 0) {
+		switch(c = *s++) {
+		case END:
+			*ptr++ = ESC;
+			*ptr++ = ESC_END;
+			break;
+		case ESC:
+			*ptr++ = ESC;
+			*ptr++ = ESC_ESC;
+			break;
+		default:
+			*ptr++ = c;
+			break;
+		}
+	}
+	*ptr++ = END;
+	return (ptr - d);
+}
+
+int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
+{
+	int actual, n;
+
+	actual = slip_esc(buf, pri->buf, len);
+	n = net_write(fd, pri->buf, actual);
+	if(n < 0) return(n);
+	else return(len);
+}
+
+static int slip_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
+			  void *data)
+{
+	struct slip_data *pri = data;
+
+	if(pri->slave == -1) return;
+	open_addr(addr, netmask, pri->name);
+}
+
+static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct slip_data *pri = data;
+
+	if(pri->slave == -1) return;
+	close_addr(addr, netmask, pri->name);
+}
+
+struct net_user_info slip_user_info = {
+	init:		slip_user_init,
+	open:		slip_open,
+	close:	 	slip_close,
+	remove:	 	NULL,
+	set_mtu:	slip_set_mtu,
+	add_address:	slip_add_addr,
+	delete_address: slip_del_addr,
+	max_packet:	BUF_SIZE
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/ssl.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,226 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/fs.h"
+#include "linux/tty.h"
+#include "linux/tty_driver.h"
+#include "linux/major.h"
+#include "linux/mm.h"
+#include "linux/init.h"
+#include "asm/termbits.h"
+#include "asm/irq.h"
+#include "line.h"
+#include "ssl.h"
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "init.h"
+#include "irq_user.h"
+#include "2_5compat.h"
+
+static int ssl_version = 1;
+
+static struct tty_driver ssl_driver;
+
+static int ssl_refcount = 0;
+
+#define NR_PORTS 64
+
+void ssl_announce(char *dev_name, int dev)
+{
+	printk(KERN_INFO "Serial line %d assigned device '%s'\n", dev,
+	       dev_name);
+}
+
+static struct chan_opts opts = {
+	announce: 	ssl_announce,
+	xterm_title:	"Serial Line #%d",
+	raw:		1,
+	tramp_stack :	0,
+};
+
+static struct line_driver driver = {
+	name :			"UML serial line",
+	devfs_name :		"tts/%d",
+	major :			TTYAUX_MAJOR,
+	minor_start :		64,
+	type :		 	TTY_DRIVER_TYPE_SERIAL,
+	subtype :	 	0,
+	read_irq :		SSL_IRQ,
+	read_irq_name :		"ssl",
+	write_irq :		SSL_WRITE_IRQ,
+	write_irq_name :	"ssl-write",
+	symlink_from :		"serial",
+	symlink_to :		"tts",
+};
+
+static struct line serial_lines[NR_PORTS] = 
+	{ [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
+
+static struct lines lines = LINES_INIT(NR_PORTS);
+
+int ssl_open(struct tty_struct *tty, struct file *filp)
+{
+	return(line_open(serial_lines, tty, &opts));
+}
+
+static void ssl_close(struct tty_struct *tty, struct file * filp)
+{
+	line_close(serial_lines, tty);
+}
+
+static int ssl_write(struct tty_struct * tty, int from_user,
+		     const unsigned char *buf, int count)
+{
+	return(line_write(serial_lines, tty, buf, count));
+}
+
+static void ssl_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	line_write(serial_lines, tty, &ch, sizeof(ch));
+}
+
+static void ssl_flush_chars(struct tty_struct *tty)
+{
+	return;
+}
+
+static int ssl_chars_in_buffer(struct tty_struct *tty)
+{
+	return(0);
+}
+
+static void ssl_flush_buffer(struct tty_struct *tty)
+{
+	return;
+}
+
+static int ssl_ioctl(struct tty_struct *tty, struct file * file,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret;
+
+	ret = 0;
+	switch(cmd){
+	case TCGETS:
+	case TCSETS:
+	case TCFLSH:
+	case TCSETSF:
+	case TCSETSW:
+	case TCGETA:
+	case TIOCMGET:
+		ret = -ENOIOCTLCMD;
+		break;
+	default:
+		printk(KERN_ERR 
+		       "Unimplemented ioctl in ssl_ioctl : 0x%x\n", cmd);
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	return(ret);
+}
+
+static void ssl_throttle(struct tty_struct * tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_throttle\n");
+}
+
+static void ssl_unthrottle(struct tty_struct * tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_unthrottle\n");
+}
+
+static void ssl_set_termios(struct tty_struct *tty, 
+			    struct termios *old_termios)
+{
+}
+
+static void ssl_stop(struct tty_struct *tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_stop\n");
+}
+
+static void ssl_start(struct tty_struct *tty)
+{
+	printk(KERN_ERR "Someone should implement ssl_start\n");
+}
+
+void ssl_hangup(struct tty_struct *tty)
+{
+}
+
+static int ssl_init_done = 0;
+
+int ssl_init(void)
+{
+	char *new_title;
+
+	printk(KERN_INFO "Initializing software serial port version %d\n", 
+	       ssl_version);
+
+	ssl_driver = ((struct tty_driver)
+		      {
+			      refcount :	&ssl_refcount,
+			      open :	 	ssl_open,
+			      close :	 	ssl_close,
+			      write :	 	ssl_write,
+			      put_char :	ssl_put_char,
+			      flush_chars :	ssl_flush_chars,
+			      chars_in_buffer :	ssl_chars_in_buffer,
+			      flush_buffer :	ssl_flush_buffer,
+			      ioctl :	 	ssl_ioctl,
+			      throttle :	ssl_throttle,
+			      unthrottle :	ssl_unthrottle,
+			      set_termios :	ssl_set_termios,
+			      stop :	 	ssl_stop,
+			      start :	 	ssl_start,
+			      hangup :	 	ssl_hangup
+		      });
+
+	line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, 
+			    sizeof(serial_lines)/sizeof(serial_lines[0]));
+
+	lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
+
+	new_title = add_xterm_umid(opts.xterm_title);
+	if(new_title != NULL) opts.xterm_title = new_title;
+
+	ssl_init_done = 1;
+	return(0);
+}
+
+__initcall(ssl_init);
+
+static int ssl_chan_setup(char *str)
+{
+	line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
+		   str);
+	return(1);
+}
+
+__setup("ssl", ssl_chan_setup);
+__channel_help(ssl_chan_setup, "ssl");
+
+static void ssl_exit(void)
+{
+	if(!ssl_init_done) return;
+	close_lines(serial_lines, 
+		    sizeof(serial_lines)/sizeof(serial_lines[0]));
+}
+
+__uml_exitcall(ssl_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/ssl.h b/arch/um/drivers/ssl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/ssl.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SSL_H__
+#define __SSL_H__
+
+extern int ssl_read(int fd, int line);
+extern void ssl_receive_char(int line, char ch);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/stdio_console.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,211 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/posix_types.h"
+#include "linux/tty.h"
+#include "linux/tty_flip.h"
+#include "linux/types.h"
+#include "linux/major.h"
+#include "linux/kdev_t.h"
+#include "linux/console.h"
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "linux/list.h"
+#include "linux/init.h"
+#include "linux/interrupt.h"
+#include "linux/slab.h"
+#include "asm/current.h"
+#include "asm/softirq.h"
+#include "asm/hardirq.h"
+#include "asm/irq.h"
+#include "stdio_console.h"
+#include "line.h"
+#include "chan_kern.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+#include "init.h"
+#include "2_5compat.h"
+
+#define MAX_TTYS (8)
+
+static struct tty_driver console_driver;
+
+static struct chan_ops init_console_ops = {
+	init : 		NULL,
+	open : 		NULL,
+	close :		NULL,
+	read : 		NULL,
+	write :		NULL,
+	console_write :	generic_write,
+	window_size :	NULL,
+	free : 		NULL,
+	winch:		0,
+};
+
+static struct chan init_console_chan = {
+	list : 		{ },
+	primary :	1,
+	input :		0,
+	output :	1,
+	opened :	1,
+	fd :		1,
+	pri :		INIT_STATIC,
+	ops :		&init_console_ops,
+	data :		NULL
+};
+
+void stdio_announce(char *dev_name, int dev)
+{
+	printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev,
+	       dev_name);
+}
+
+static struct chan_opts opts = {
+	announce: 	stdio_announce,
+	xterm_title:	"Virtual Console #%d",
+	raw:		1,
+	tramp_stack :	0,
+};
+
+static struct line_driver driver = {
+	name :			"UML console",
+	devfs_name :		"vc/%d",
+	major :			TTY_MAJOR,
+	minor_start :		0,
+	type :		 	TTY_DRIVER_TYPE_CONSOLE,
+	subtype :	 	SYSTEM_TYPE_CONSOLE,
+	read_irq :		CONSOLE_IRQ,
+	read_irq_name :		"console",
+	write_irq :		CONSOLE_WRITE_IRQ,
+	write_irq_name :	"console-write",
+	symlink_from :		"ttys",
+	symlink_to :		"vc",
+};
+
+static struct lines console_lines = LINES_INIT(MAX_TTYS);
+
+struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
+			      [ 1 ... MAX_TTYS - 1 ] = 
+			      LINE_INIT(CONFIG_CON_CHAN, &driver) };
+
+static int open_console(struct tty_struct *tty)
+{
+	return(line_open(vts, tty, &opts));
+}
+
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+	return(open_console(tty));
+}
+
+static void con_close(struct tty_struct *tty, struct file *filp)
+{
+	line_close(vts, tty);
+}
+
+static int con_write(struct tty_struct *tty, int from_user, 
+		     const unsigned char *buf, int count)
+{
+	return(line_write(vts, tty, buf, count));
+}
+
+static void set_termios(struct tty_struct *tty, struct termios * old)
+{
+}
+
+static int chars_in_buffer(struct tty_struct *tty)
+{
+	return(0);
+}
+
+static int con_init_done = 0;
+
+int stdio_init(void)
+{
+	char *new_title;
+
+	printk(KERN_INFO "Initializing stdio console driver\n");
+
+	console_driver = ((struct tty_driver)
+		      {
+			      open :	 	con_open,
+			      close :	 	con_close,
+			      write :	 	con_write,
+			      chars_in_buffer :	chars_in_buffer,
+			      set_termios :	set_termios
+		      });
+
+	line_register_devfs(&console_lines, &driver, &console_driver, vts, 
+			    sizeof(vts)/sizeof(vts[0]));
+
+	lines_init(vts, sizeof(vts)/sizeof(vts[0]));
+
+	new_title = add_xterm_umid(opts.xterm_title);
+	if(new_title != NULL) opts.xterm_title = new_title;
+
+	open_console(NULL);
+	con_init_done = 1;
+	return(0);
+}
+
+__initcall(stdio_init);
+
+static void console_write(struct console *console, const char *string, 
+			  unsigned len)
+{
+	console_write_chan(&vts[console->index].chan_list, string, len);
+}
+
+static kdev_t console_device(struct console *c)
+{
+	return mk_kdev(TTY_MAJOR, c->index);
+}
+
+static int console_setup(struct console *co, char *options)
+{
+	return(0);
+}
+
+static struct console stdiocons = INIT_CONSOLE("tty", console_write, 
+					       console_device, console_setup,
+					       CON_PRINTBUFFER);
+
+void stdio_console_init(void)
+{
+	INIT_LIST_HEAD(&vts[0].chan_list);
+	list_add(&init_console_chan.list, &vts[0].chan_list);
+	register_console(&stdiocons);
+}
+
+static int console_chan_setup(char *str)
+{
+	line_setup(vts, sizeof(vts)/sizeof(vts[0]), str);
+	return(1);
+}
+
+__setup("con", console_chan_setup);
+__channel_help(console_chan_setup, "con");
+
+static void console_exit(void)
+{
+	if(!con_init_done) return;
+	line_close(vts, NULL);
+	close_lines(vts, sizeof(vts)/sizeof(vts[0]));
+}
+
+__uml_exitcall(console_exit);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/stdio_console.h b/arch/um/drivers/stdio_console.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/stdio_console.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,21 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STDIO_CONSOLE_H
+#define __STDIO_CONSOLE_H
+
+extern void save_console_flags(void);
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/tty.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,82 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include "chan_user.h"
+#include "user_util.h"
+#include "user.h"
+#include "os.h"
+
+struct tty_chan {
+	char *dev;
+	int raw;
+	struct termios tt;
+};
+
+void *tty_chan_init(char *str, int device, struct chan_opts *opts)
+{
+	struct tty_chan *data;
+
+	if(*str != ':'){
+		printk("tty_init : channel type 'tty' must specify "
+		       "a device\n");
+		return(NULL);
+	}
+	str++;
+
+	if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct tty_chan) { dev :	str,
+				     raw :	opts->raw });
+				     
+	return(data);
+}
+
+int tty_open(int input, int output, int primary, void *d)
+{
+	struct tty_chan *data = d;
+	int fd;
+
+	fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
+	if(fd < 0) return(fd);
+	if(data->raw){
+		tcgetattr(fd, &data->tt);
+		raw(fd, 0);
+	}
+	return(fd);
+}
+
+int tty_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct tty_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops tty_ops = {
+	init:		tty_chan_init,
+	open:		tty_open,
+	close:		generic_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	tty_console_write,
+	window_size:	generic_window_size,
+	free:		generic_free,
+	winch:		0,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/ubd_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,941 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+/* 2001-09-28...2002-04-17
+ * Partition stuff by James_McMechan@hotmail.com
+ * old style ubd by setting UBD_SHIFT to 0
+ */
+
+#define MAJOR_NR UBD_MAJOR
+#define UBD_SHIFT 4
+
+#include "linux/config.h"
+#include "linux/blk.h"
+#include "linux/blkdev.h"
+#include "linux/hdreg.h"
+#include "linux/ide.h"
+#include "linux/init.h"
+#include "linux/devfs_fs_kernel.h"
+#include "linux/cdrom.h"
+#include "linux/proc_fs.h"
+#include "linux/ctype.h"
+#include "linux/capability.h"
+#include "linux/mm.h"
+#include "linux/vmalloc.h"
+#include "linux/blkpg.h"
+#include "linux/genhd.h"
+#include "asm/segment.h"
+#include "asm/uaccess.h"
+#include "asm/irq.h"
+#include "asm/types.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mconsole_kern.h"
+#include "init.h"
+#include "irq_user.h"
+#include "ubd_user.h"
+#include "2_5compat.h"
+#include "os.h"
+
+static spinlock_t ubd_lock;
+static void (*do_ubd)(void);
+
+static int ubd_open(struct inode * inode, struct file * filp);
+static int ubd_release(struct inode * inode, struct file * file);
+static int ubd_ioctl(struct inode * inode, struct file * file,
+		     unsigned int cmd, unsigned long arg);
+static int ubd_revalidate(kdev_t rdev);
+
+#define MAX_DEV (8)
+#define MAX_MINOR (MAX_DEV << UBD_SHIFT)
+
+#define DEVICE_NR(n) (minor(n) >> UBD_SHIFT)
+
+/* number of bytes per sector */
+static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
+
+static struct block_device_operations ubd_blops = {
+        open:		ubd_open,
+        release:	ubd_release,
+        ioctl:		ubd_ioctl,
+        revalidate:	ubd_revalidate,
+};
+
+static struct hd_struct	ubd_part[MAX_MINOR] = 
+	{ [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
+
+static request_queue_t *ubd_queue;
+
+static int fake_major = 0;
+
+#define INIT_GENDISK(maj, name, parts, shift, blops) \
+{ \
+	major :		maj, \
+	major_name : 	name, \
+	minor_shift :	shift, \
+	part : 		parts, \
+	next : 		NULL, \
+	fops : 		blops, \
+	flags : 	0 \
+}
+
+static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part,
+						 UBD_SHIFT, &ubd_blops);
+static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part, 
+						  UBD_SHIFT, &ubd_blops);
+
+#ifdef CONFIG_BLK_DEV_UBD_SYNC
+#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 1, c : 0 })
+#else
+#define OPEN_FLAGS ((struct openflags) { r : 1, w : 1, s : 0, c : 0 })
+#endif
+
+static struct openflags global_openflags = OPEN_FLAGS;
+
+struct cow {
+	char *file;
+	int fd;
+	unsigned long *bitmap;
+	unsigned long bitmap_len;
+	int bitmap_offset;
+        int data_offset;
+};
+
+struct ubd {
+	char *file;
+	int is_dir;
+	int count;
+	int fd;
+	__u64 size;
+	struct openflags boot_openflags;
+	struct openflags openflags;
+	devfs_handle_t real;
+	devfs_handle_t fake;
+	struct cow cow;
+};
+
+#define DEFAULT_COW { \
+	file:			NULL, \
+        fd:			-1, \
+        bitmap:			NULL, \
+	bitmap_offset:		0, \
+        data_offset:		0, \
+}
+
+#define DEFAULT_UBD { \
+	file: 			NULL, \
+	is_dir:			0, \
+	count:			0, \
+	fd:			-1, \
+	size:			-1, \
+	boot_openflags:		OPEN_FLAGS, \
+	openflags:		OPEN_FLAGS, \
+	real:			NULL, \
+	fake:			NULL, \
+        cow:			DEFAULT_COW, \
+}
+
+struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
+
+static int ubd0_init(void)
+{
+	if(ubd_dev[0].file == NULL)
+		ubd_dev[0].file = "root_fs";
+	return(0);
+}
+
+__initcall(ubd0_init);
+
+static struct hd_driveid ubd_id = {
+        cyls:		0,
+	heads:		128,
+	sectors:	32,
+};
+
+static int fake_ide = 0;
+static struct proc_dir_entry *proc_ide_root = NULL;
+static struct proc_dir_entry *proc_ide = NULL;
+
+static void make_proc_ide(void)
+{
+	proc_ide_root = proc_mkdir("ide", 0);
+	proc_ide = proc_mkdir("ide0", proc_ide_root);
+}
+
+static int proc_ide_read_media(char *page, char **start, off_t off, int count,
+			       int *eof, void *data)
+{
+	int len;
+
+	strcpy(page, "disk\n");
+	len = strlen("disk\n");
+	len -= off;
+	if (len < count){
+		*eof = 1;
+		if (len <= 0) return 0;
+	}
+	else len = count;
+	*start = page + off;
+	return len;
+	
+}
+
+static void make_ide_entries(char *dev_name)
+{
+	struct proc_dir_entry *dir, *ent;
+	char name[64];
+
+	if(!fake_ide) return;
+	if(proc_ide_root == NULL) make_proc_ide();
+	dir = proc_mkdir(dev_name, proc_ide);
+	ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
+	if(!ent) return;
+	ent->nlink = 1;
+	ent->data = NULL;
+	ent->read_proc = proc_ide_read_media;
+	ent->write_proc = NULL;
+	sprintf(name,"ide0/%s", dev_name);
+	proc_symlink(dev_name, proc_ide_root, name);
+}
+
+static int fake_ide_setup(char *str)
+{
+	fake_ide = 1;
+	return(1);
+}
+
+__setup("fake_ide", fake_ide_setup);
+
+__uml_help(fake_ide_setup,
+"fake_ide\n"
+"    Create ide0 entries that map onto ubd devices.\n\n"
+);
+
+static int ubd_setup_common(char *str, int *index_out)
+{
+	struct openflags flags = global_openflags;
+	char *backing_file;
+	int n;
+
+	if(index_out) *index_out = -1;
+	n = *str++;
+	if(n == '='){
+		char *end;
+		int major;
+
+		if(!strcmp(str, "sync")){
+			global_openflags.s = 1;
+			return(0);
+		}
+		major = simple_strtoul(str, &end, 0);
+		if(*end != '\0'){
+			printk(KERN_ERR 
+			       "ubd_setup : didn't parse major number\n");
+			return(1);
+		}
+		fake_gendisk.major = major;
+		fake_major = major;
+		printk(KERN_INFO "Setting extra ubd major number to %d\n",
+		       major);
+		return(0);
+	}
+
+	if(n < '0'){
+		printk(KERN_ERR "ubd_setup : index out of range\n"); }
+
+	if((n >= '0') && (n <= '9')) n -= '0';
+	else if((n >= 'a') && (n <= 'z')) n -= 'a';
+	else {
+		printk(KERN_ERR "ubd_setup : device syntax invalid\n");
+		return(1);
+	}
+	if(n >= MAX_DEV){
+		printk(KERN_ERR "ubd_setup : index out of range "
+		       "(%d devices)\n", MAX_DEV);	
+		return(1);
+	}
+
+	if(ubd_dev[n].file != NULL){
+		printk(KERN_ERR "ubd_setup : device already configured\n");
+		return(1);
+	}
+
+	if(index_out) *index_out = n;
+
+	if (*str == 'r'){
+		flags.w = 0;
+		str++;
+	}
+	if (*str == 's'){
+		flags.s = 1;
+		str++;
+	}
+	if(*str++ != '='){
+		printk(KERN_ERR "ubd_setup : Expected '='\n");
+		return(1);
+	}
+	backing_file = strchr(str, ',');
+	if(backing_file){
+		*backing_file = '\0';
+		backing_file++;
+	}
+	ubd_dev[n].file = str;
+	if(ubd_is_dir(ubd_dev[n].file))
+		ubd_dev[n].is_dir = 1;
+	ubd_dev[n].cow.file = backing_file;
+	ubd_dev[n].boot_openflags = flags;
+	return(0);
+}
+
+static int ubd_setup(char *str)
+{
+	ubd_setup_common(str, NULL);
+	return(1);
+}
+
+__setup("ubd", ubd_setup);
+__uml_help(ubd_setup,
+"ubd<n>=<filename>\n"
+"    This is used to associate a device with a file in the underlying\n"
+"    filesystem. Usually, there is a filesystem in the file, but \n"
+"    that's not required. Swap devices containing swap files can be\n"
+"    specified like this. Also, a file which doesn't contain a\n"
+"    filesystem can have its contents read in the virtual \n"
+"    machine by running dd on the device. n must be in the range\n"
+"    0 to 7. Appending an 'r' to the number will cause that device\n"
+"    to be mounted read-only. For example ubd1r=./ext_fs. Appending\n"
+"    an 's' (has to be _after_ 'r', if there is one) will cause data\n"
+"    to be written to disk on the host immediately.\n\n"
+);
+
+static int fakehd(char *str)
+{
+	printk(KERN_INFO 
+	       "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
+	ubd_gendisk.major_name = "hd";
+	return(1);
+}
+
+__setup("fakehd", fakehd);
+__uml_help(fakehd,
+"fakehd\n"
+"    Change the ubd device name to \"hd\".\n\n"
+);
+
+static void do_ubd_request(request_queue_t * q);
+
+int thread_fd = -1;
+
+int intr_count = 0;
+
+static void ubd_finish(int error)
+{
+	int nsect;
+
+	if(error){
+		end_request(CURRENT, 0);
+		return;
+	}
+	nsect = CURRENT->current_nr_sectors;
+	CURRENT->sector += nsect;
+	CURRENT->buffer += nsect << 9;
+	CURRENT->errors = 0;
+	CURRENT->nr_sectors -= nsect;
+	CURRENT->current_nr_sectors = 0;
+	end_request(CURRENT, 1);
+}
+
+static void ubd_handler(void)
+{
+	struct io_thread_req req;
+	int n;
+
+	do_ubd = NULL;
+	intr_count++;
+	n = read_ubd_fs(thread_fd, &req, sizeof(req));
+	if(n != sizeof(req)){
+		printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
+		       "errno = %d\n", os_getpid(), -n);
+		spin_lock(&ubd_lock);
+		end_request(CURRENT, 0);
+		spin_unlock(&ubd_lock);
+		return;
+	}
+        
+        if((req.offset != ((__u64) (CURRENT->sector)) << 9) ||
+	   (req.length != (CURRENT->current_nr_sectors) << 9))
+		panic("I/O op mismatch");
+	
+	spin_lock(&ubd_lock);
+	ubd_finish(req.error);
+	reactivate_fd(thread_fd, UBD_IRQ);	
+	do_ubd_request(ubd_queue);
+	spin_unlock(&ubd_lock);
+}
+
+static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
+{
+	ubd_handler();
+}
+
+static int io_pid = -1;
+
+void kill_io_thread(void)
+{
+	if(io_pid != -1) kill(io_pid, SIGKILL);
+}
+
+__uml_exitcall(kill_io_thread);
+
+int sync = 0;
+
+devfs_handle_t ubd_dir_handle;
+devfs_handle_t ubd_fake_dir_handle;
+
+static int ubd_add(int n)
+{
+ 	devfs_handle_t real, fake;
+	char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
+ 	int err;
+
+	if(ubd_dev[n].file == NULL) return(-1);
+ 
+ 	err = ubd_revalidate(mk_kdev(MAJOR_NR, n << UBD_SHIFT));
+ 	if(err)
+ 		return(err);
+ 
+	sprintf(name, "%d", n);
+	real = devfs_register(ubd_dir_handle, name, DEVFS_FL_REMOVABLE, 
+			      MAJOR_NR, n << UBD_SHIFT,
+			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
+			      &ubd_blops, NULL);
+	if(fake_major != 0){
+		fake = devfs_register(ubd_fake_dir_handle, name, 
+				      DEVFS_FL_REMOVABLE, fake_major,
+				      n << UBD_SHIFT, 
+				      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
+				      S_IWGRP, &ubd_blops, NULL);
+ 		if(fake == NULL) return(-1);
+ 		ubd_dev[n].fake = fake;
+	}
+ 
+ 	if(real == NULL) return(-1);
+ 	ubd_dev[n].real = real;
+ 
+	if(!strcmp(ubd_gendisk.major_name, "ubd"))
+		sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n);
+	else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
+		     n + 'a');
+
+	make_ide_entries(dev_name);
+	return(0);
+}
+
+static int ubd_config(char *str)
+{
+	int n, err;
+
+	str = uml_strdup(str);
+	if(str == NULL){
+		printk(KERN_ERR "ubd_config failed to strdup string\n");
+		return(1);
+	}
+	err = ubd_setup_common(str, &n);
+	if(err){
+		kfree(str);
+		return(-1);
+	}
+	if(n == -1) return(0);
+
+	err = ubd_add(n);
+	if(err){
+		ubd_dev[n].file = NULL;
+		return(err);
+	}
+
+	return(0);
+}
+
+static int ubd_remove(char *str)
+{
+	struct ubd *dev;
+	int n;
+
+	if(!isdigit(*str)) return(-1);
+	n = *str - '0';
+	if(n > MAX_DEV) return(-1);
+	dev = &ubd_dev[n];
+	if(dev->file == NULL) return(0);
+	if(dev->count > 0) return(-1);
+	if(dev->real != NULL) devfs_unregister(dev->real);
+	if(dev->fake != NULL) devfs_unregister(dev->fake);
+	*dev = ((struct ubd) DEFAULT_UBD);
+	return(0);
+}
+
+static struct mc_device ubd_mc = {
+	name:		"ubd",
+	config:		ubd_config,
+	remove:		ubd_remove,
+};
+
+static int ubd_mc_init(void)
+{
+	mconsole_register_dev(&ubd_mc);
+	return(0);
+}
+
+__initcall(ubd_mc_init);
+
+static request_queue_t *ubd_get_queue(kdev_t device)
+{
+	return(ubd_queue);
+}
+
+int ubd_init(void)
+{
+        int i;
+
+	ubd_dir_handle = devfs_mk_dir (NULL, "ubd", NULL);
+	if(register_blkdev(MAJOR_NR, "ubd", &ubd_blops)){
+		printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR);
+		return -1;
+	}
+	ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
+	INIT_QUEUE(ubd_queue, do_ubd_request, &ubd_lock);
+	INIT_ELV(ubd_queue, &ubd_queue->elevator);
+	INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
+        add_gendisk(&ubd_gendisk);
+	if(fake_major != 0){
+		char name[sizeof("ubd_nnn\0")];
+
+		snprintf(name, sizeof(name), "ubd_%d", fake_major);
+		ubd_fake_dir_handle = devfs_mk_dir(NULL, name, NULL);
+		if(register_blkdev(fake_major, "ubd", &ubd_blops)){
+			printk(KERN_ERR "ubd: unable to get major %d\n",
+			       fake_major);
+			return -1;
+		}
+		blk_dev[fake_major].queue = ubd_get_queue;
+		INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
+                add_gendisk(&fake_gendisk);
+	}
+	for(i=0;i<MAX_DEV;i++) ubd_add(i);
+	return(0);
+}
+
+late_initcall(ubd_init);
+
+int ubd_driver_init(void){
+	unsigned long stack;
+	int err;
+
+	if(sync){
+		printk(KERN_INFO "ubd : Synchronous mode\n");
+		return(0);
+	}
+	stack = alloc_stack(0, 0);
+	io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
+				 &thread_fd);
+	if(io_pid < 0){
+		printk(KERN_ERR 
+		       "ubd : Failed to start I/O thread (errno = %d) - "
+		       "falling back to synchronous I/O\n", -io_pid);
+		return(0);
+	}
+	err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
+			     SA_INTERRUPT, "ubd", ubd_dev);
+	if(err != 0) printk(KERN_ERR 
+			    "um_request_irq failed - errno = %d\n", -err);
+	return(err);
+}
+
+device_initcall(ubd_driver_init);
+
+static void ubd_close(struct ubd *dev)
+{
+	close_fd(dev->fd);
+	if(dev->cow.file != NULL) {
+		close_fd(dev->cow.fd);
+		vfree(dev->cow.bitmap);
+		dev->cow.bitmap = NULL;
+	}
+}
+
+static int ubd_open_dev(struct ubd *dev)
+{
+	struct openflags flags;
+	int err, n, create_cow, *create_ptr;
+
+	create_cow = 0;
+	create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
+	dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
+				&dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
+				&dev->cow.data_offset, create_ptr);
+
+	if((dev->fd == -ENOENT) && create_cow){
+		n = dev - ubd_dev;
+		dev->fd = create_cow_file(dev->file, dev->cow.file, 
+					  dev->openflags, 1 << 9,
+					  &dev->cow.bitmap_offset, 
+					  &dev->cow.bitmap_len,
+					  &dev->cow.data_offset);
+		if(dev->fd >= 0){
+			printk(KERN_INFO "Creating \"%s\" as COW file for "
+			       "\"%s\"\n", dev->file, dev->cow.file);
+		}
+	}
+
+	if(dev->fd < 0) return(dev->fd);
+
+	if(dev->cow.file != NULL){
+		err = -ENOMEM;
+		dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
+		if(dev->cow.bitmap == NULL) goto error;
+		flush_tlb_kernel_vm();
+
+		err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
+				      dev->cow.bitmap_offset, 
+				      dev->cow.bitmap_len);
+		if(err) goto error;
+
+		flags = dev->openflags;
+		flags.w = 0;
+		err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, 
+				    NULL, NULL);
+		if(err < 0) goto error;
+		dev->cow.fd = err;
+	}
+	return(0);
+ error:
+	close_fd(dev->fd);
+	return(err);
+}
+
+static int ubd_file_size(struct ubd *dev, __u64 *size_out)
+{
+	char *file;
+
+	file = dev->cow.file ? dev->cow.file : dev->file;
+	return(os_file_size(file, size_out));
+}
+
+static int ubd_open(struct inode *inode, struct file *filp)
+{
+	struct ubd *dev;
+	int n, offset, err;
+
+	n = DEVICE_NR(inode->i_rdev);
+	dev = &ubd_dev[n];
+	if(n > MAX_DEV)
+		return -ENODEV;
+	offset = n << UBD_SHIFT;
+	if(dev->is_dir == 1)
+		return(0);
+
+	if(dev->count == 0){
+		dev->openflags = dev->boot_openflags;
+
+		err = ubd_open_dev(dev);
+		if(err){
+			printk(KERN_ERR "ubd%d: Can't open \"%s\": "
+			       "errno = %d\n", n, dev->file, -err);
+			return(err);
+		}
+		err = ubd_file_size(dev, &dev->size);
+		if(err) return(err);
+		ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset];
+	}
+	dev->count++;
+	if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
+	        if(--dev->count == 0) ubd_close(dev);
+	        return -EROFS;
+	}
+	return(0);
+}
+
+static int ubd_release(struct inode * inode, struct file * file)
+{
+        int n, offset;
+
+	n = DEVICE_NR(inode->i_rdev);
+	offset = n << UBD_SHIFT;
+	if(n > MAX_DEV)
+		return -ENODEV;
+	if(--ubd_dev[n].count == 0){
+		ubd_close(&ubd_dev[n]);
+		ubd_part[offset].nr_sects = 0;
+	}
+	return(0);
+}
+
+int cow_read = 0;
+int cow_write = 0;
+
+void cowify_req(struct io_thread_req *req, struct ubd *dev)
+{
+        int i, update_bitmap, sector = req->offset >> 9;
+
+	if(req->length > (sizeof(req->sector_mask) * 8) << 9)
+		panic("Operation too long");
+	if(req->op == UBD_READ) {
+		for(i = 0; i < req->length >> 9; i++){
+			if(ubd_test_bit(sector + i, (unsigned char *) 
+					dev->cow.bitmap)){
+				ubd_set_bit(i, (unsigned char *) 
+					    &req->sector_mask);
+				cow_read++;
+			}
+                }
+        } 
+        else {
+		update_bitmap = 0;
+		for(i = 0; i < req->length >> 9; i++){
+			cow_write++;
+			ubd_set_bit(i, (unsigned char *) 
+				    &req->sector_mask);
+			if(!ubd_test_bit(sector + i, (unsigned char *) 
+					 dev->cow.bitmap))
+				update_bitmap = 1;
+			ubd_set_bit(sector + i, (unsigned char *) 
+				    dev->cow.bitmap);
+		}
+		if(update_bitmap){
+			req->cow_offset = sector / (sizeof(unsigned long) * 8);
+			req->bitmap_words[0] = 
+				dev->cow.bitmap[req->cow_offset];
+			req->bitmap_words[1] = 
+				dev->cow.bitmap[req->cow_offset + 1];
+			req->cow_offset *= sizeof(unsigned long);
+			req->cow_offset += dev->cow.bitmap_offset;
+		}
+	}
+}
+
+static int prepare_request(struct request *req, struct io_thread_req *io_req)
+{
+	struct ubd *dev;
+	__u64 block;
+	int nsect, min, n;
+
+	if(req->rq_status == RQ_INACTIVE) return(1);
+
+	min = minor(req->rq_dev);
+	n = min >> UBD_SHIFT;
+	dev = &ubd_dev[n];
+	if(dev->is_dir){
+		strcpy(req->buffer, "HOSTFS:");
+		strcat(req->buffer, dev->file);
+		end_request(req, 1);
+		return(1);
+	}
+
+	if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
+		printk("Write attempted on readonly ubd device %d\n", n);
+		end_request(req, 0);
+		return(1);
+	}
+
+        req->sector += ubd_part[min].start_sect;
+        block = req->sector;
+        nsect = req->current_nr_sectors;
+
+	io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE;
+	io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
+	io_req->fds[1] = dev->fd;
+	io_req->offsets[0] = 0;
+	io_req->offsets[1] = dev->cow.data_offset;
+	io_req->offset = ((__u64) block) << 9;
+	io_req->length = nsect << 9;
+	io_req->buffer = req->buffer;
+	io_req->sectorsize = 1 << 9;
+	io_req->sector_mask = 0;
+	io_req->cow_offset = -1;
+	io_req->error = 0;
+
+        if(dev->cow.file != NULL) cowify_req(io_req, dev);
+	return(0);
+}
+
+static void do_ubd_request(request_queue_t *q)
+{
+	struct io_thread_req io_req;
+	struct request *req;
+	int err, n;
+
+	if(thread_fd == -1){
+		while(!list_empty(&q->queue_head)){
+			req = elv_next_request(q);
+			err = prepare_request(req, &io_req);
+			if(!err){
+				do_io(&io_req);
+				ubd_finish(io_req.error);
+			}
+		}
+	}
+	else {
+		if(do_ubd || list_empty(&q->queue_head)) return;
+		req = elv_next_request(q);
+		err = prepare_request(req, &io_req);
+		if(!err){
+			do_ubd = ubd_handler;
+			n = write_ubd_fs(thread_fd, (char *) &io_req, 
+					 sizeof(io_req));
+			if(n != sizeof(io_req))
+				printk("write to io thread failed, "
+				       "errno = %d\n", -n);
+		}
+	}
+}
+
+static int ubd_ioctl(struct inode * inode, struct file * file,
+		     unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+ 	struct ubd *dev;
+	int n, min, err;
+
+        if(!inode) return(-EINVAL);
+	min = minor(inode->i_rdev);
+	n = min >> UBD_SHIFT;
+	if(n > MAX_DEV)
+		return(-EINVAL);
+	dev = &ubd_dev[n];
+	switch (cmd) {
+	        struct hd_geometry g;
+		struct cdrom_volctrl volume;
+	case HDIO_GETGEO:
+		if(!loc) return(-EINVAL);
+		g.heads = 128;
+		g.sectors = 32;
+		g.cylinders = dev->size / (128 * 32 * hardsect_sizes[min]);
+		g.start = 2;
+		return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
+	case BLKGETSIZE:   /* Return device size */
+		if(!arg) return(-EINVAL);
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if(err)
+			return(err);
+		put_user(ubd_part[min].nr_sects, (long *) arg);
+		return(0);
+	case BLKRRPART: /* Re-read partition tables */
+		return(ubd_revalidate(inode->i_rdev));
+
+	case HDIO_SET_UNMASKINTR:
+		if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
+		if((arg > 1) || (min & ((1 << UBD_SHIFT) - 1)))
+			return(-EINVAL);
+		return(0);
+
+	case HDIO_GET_UNMASKINTR:
+		if(!arg)  return(-EINVAL);
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if(err)
+			return(err);
+		return(0);
+
+	case HDIO_GET_MULTCOUNT:
+		if(!arg)  return(-EINVAL);
+		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+		if(err)
+			return(err);
+		return(0);
+
+	case HDIO_SET_MULTCOUNT:
+		if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
+		if(min & ((1 << UBD_SHIFT) - 1))
+			return(-EINVAL);
+		return(0);
+
+	case HDIO_GET_IDENTITY:
+		ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[min]);
+		if(copy_to_user((char *) arg, (char *) &ubd_id, 
+				 sizeof(ubd_id)))
+			return(-EFAULT);
+		return(0);
+		
+	case CDROMVOLREAD:
+		if(copy_from_user(&volume, (char *) arg, sizeof(volume)))
+			return(-EFAULT);
+		volume.channel0 = 255;
+		volume.channel1 = 255;
+		volume.channel2 = 255;
+		volume.channel3 = 255;
+		if(copy_to_user((char *) arg, &volume, sizeof(volume)))
+			return(-EFAULT);
+		return(0);
+
+	default:
+		return blk_ioctl(inode->i_bdev, cmd, arg);
+	}
+}
+
+static int ubd_revalidate(kdev_t rdev)
+{
+	int i, n, offset, err, pcount = 1 << UBD_SHIFT;
+	struct ubd *dev;
+	struct hd_struct *part;
+
+	n = minor(rdev) >> UBD_SHIFT;
+	offset = n << UBD_SHIFT;
+	dev = &ubd_dev[n];
+	if(dev->is_dir) 
+		return(0);
+	
+	part = &ubd_part[offset];
+
+	/* clear all old partition counts */
+	for(i = 1; i < pcount; i++) {
+		part[i].start_sect = 0;
+		part[i].nr_sects = 0;
+	}
+
+	/* If it already has been opened we can check the partitions 
+	 * directly 
+	 */
+	if(dev->count){
+		part->start_sect = 0;
+		register_disk(&ubd_gendisk, mk_kdev(MAJOR_NR, offset), pcount, 
+			      &ubd_blops, part->nr_sects);
+	} 
+	else if(dev->file){
+		err = ubd_open_dev(dev);
+		if(err){
+			printk(KERN_ERR "unable to open %s for validation\n",
+			       dev->file);
+			return(err);
+		}
+
+		/* have to recompute sizes since we opened it */
+		err = ubd_file_size(dev, &dev->size);
+		if(err) {
+			ubd_close(dev);
+			return(err);
+		}
+		part->start_sect = 0;
+		part->nr_sects = dev->size / hardsect_sizes[offset];
+		register_disk(&ubd_gendisk, mk_kdev(MAJOR_NR, offset), pcount, 
+			      &ubd_blops, part->nr_sects);
+
+		/* we are done so close it */
+		ubd_close(dev);
+	} 
+	else return(-ENODEV);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/ubd_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,615 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ubd_user.h"
+#include "os.h"
+
+#include <endian.h>
+#include <byteswap.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define ntohll(x) (x)
+# define htonll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define ntohll(x)  bswap_64(x)
+# define htonll(x)  bswap_64(x)
+#else
+#error "__BYTE_ORDER not defined"
+#endif
+
+#define PATH_LEN_V1 256
+
+struct cow_header_v1 {
+	int magic;
+	int version;
+	char backing_file[PATH_LEN_V1];
+	time_t mtime;
+	__u64 size;
+	int sectorsize;
+};
+
+#define PATH_LEN_V2 MAXPATHLEN
+
+struct cow_header_v2 {
+	unsigned long magic;
+	unsigned long version;
+	char backing_file[PATH_LEN_V2];
+	time_t mtime;
+	__u64 size;
+	int sectorsize;
+};
+
+union cow_header {
+	struct cow_header_v1 v1;
+	struct cow_header_v2 v2;
+};
+
+#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+#define COW_VERSION 2
+
+static void sizes(__u64 size, int sectorsize, int bitmap_offset, 
+		  unsigned long *bitmap_len_out, int *data_offset_out)
+{
+	*bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+
+	*data_offset_out = bitmap_offset + *bitmap_len_out;
+	*data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
+	*data_offset_out *= sectorsize;
+}
+
+static int read_cow_header(int fd, int *magic_out, char **backing_file_out, 
+			   time_t *mtime_out, __u64 *size_out, 
+			   int *sectorsize_out, int *bitmap_offset_out)
+{
+	union cow_header *header;
+	char *file;
+	int err, n;
+	unsigned long version, magic;
+
+	header = um_kmalloc(sizeof(*header));
+	if(header == NULL){
+		printk("read_cow_header - Failed to allocate header\n");
+		return(-ENOMEM);
+	}
+	err = -EINVAL;
+	n = read(fd, header, sizeof(*header));
+	if(n < offsetof(typeof(header->v1), backing_file)){
+		printk("read_cow_header - short header\n");
+		goto out;
+	}
+
+	magic = header->v1.magic;
+	if(magic == COW_MAGIC) {
+		version = header->v1.version;
+	}
+	else if(magic == ntohl(COW_MAGIC)){
+		version = ntohl(header->v1.version);
+	}
+	else goto out;
+
+	*magic_out = COW_MAGIC;
+
+	if(version == 1){
+		if(n < sizeof(header->v1)){
+			printk("read_cow_header - failed to read V1 header\n");
+			goto out;
+		}
+		*mtime_out = header->v1.mtime;
+		*size_out = header->v1.size;
+		*sectorsize_out = header->v1.sectorsize;
+		*bitmap_offset_out = sizeof(header->v1);
+		file = header->v1.backing_file;
+	}
+	else if(version == 2){
+		if(n < sizeof(header->v2)){
+			printk("read_cow_header - failed to read V2 header\n");
+			goto out;
+		}
+		*mtime_out = ntohl(header->v2.mtime);
+		*size_out = ntohll(header->v2.size);
+		*sectorsize_out = ntohl(header->v2.sectorsize);
+		*bitmap_offset_out = sizeof(header->v2);
+		file = header->v2.backing_file;
+	}
+	else {
+		printk("read_cow_header - invalid COW version\n");
+		goto out;
+	}
+	err = -ENOMEM;
+	*backing_file_out = uml_strdup(file);
+	if(*backing_file_out == NULL){
+		printk("read_cow_header - failed to allocate backing file\n");
+		goto out;
+	}
+	err = 0;
+ out:
+	kfree(header);
+	return(err);
+}
+
+static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
+{
+	struct stat buf1, buf2;
+
+	if(from_cmdline == NULL) return(1);
+	if(!strcmp(from_cmdline, from_cow)) return(1);
+
+	if(stat(from_cmdline, &buf1) < 0){
+		printk("Couldn't stat '%s', errno = %d\n", from_cmdline, 
+		       errno);
+		return(1);
+	}
+	if(stat(from_cow, &buf2) < 0){
+		printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
+		return(1);
+	}
+	if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino))
+		return(1);
+
+	printk("Backing file mismatch - \"%s\" requested,\n"
+	       "\"%s\" specified in COW header of \"%s\"\n",
+	       from_cmdline, from_cow, cow);
+	return(0);
+}
+
+static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
+{
+	struct stat64 buf;
+	long long actual;
+	int err;
+
+  	if(stat64(file, &buf) < 0){
+		printk("Failed to stat backing file \"%s\", errno = %d\n",
+		       file, errno);
+		return(-errno);
+	}
+
+	err = os_file_size(file, &actual);
+	if(err){
+		printk("Failed to get size of backing file \"%s\", "
+		       "errno = %d\n", file, -err);
+		return(err);
+	}
+
+  	if(actual != size){
+		printk("Size mismatch (%ld vs %ld) of COW header vs backing "
+		       "file\n", size, actual);
+		return(-EINVAL);
+	}
+	if(buf.st_mtime != mtime){
+		printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
+		       "file\n", mtime, buf.st_mtime);
+		return(-EINVAL);
+	}
+	return(0);
+}
+
+int read_cow_bitmap(int fd, void *buf, int offset, int len)
+{
+	int err;
+
+	err = os_seek_file(fd, offset);
+	if(err != 0) return(-errno);
+	err = read(fd, buf, len);
+	if(err < 0) return(-errno);
+	return(0);
+}
+
+static int absolutize(char *to, int size, char *from)
+{
+	char save_cwd[256], *slash;
+	int remaining;
+
+	if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+		printk("absolutize : unable to get cwd - errno = %d\n", errno);
+		return(-1);
+	}
+	slash = strrchr(from, '/');
+	if(slash != NULL){
+		*slash = '\0';
+		if(chdir(from)){
+			*slash = '/';
+			printk("absolutize : Can't cd to '%s' - errno = %d\n",
+			       from, errno);
+			return(-1);
+		}
+		*slash = '/';
+		if(getcwd(to, size) == NULL){
+			printk("absolutize : unable to get cwd of '%s' - "
+			       "errno = %d\n", from, errno);
+			return(-1);
+		}
+		remaining = size - strlen(to);
+		if(strlen(slash) + 1 > remaining){
+			printk("absolutize : unable to fit '%s' into %d "
+			       "chars\n", from, size);
+			return(-1);
+		}
+		strcat(to, slash);
+	}
+	else {
+		if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+			printk("absolutize : unable to fit '%s' into %d "
+			       "chars\n", from, size);
+			return(-1);
+		}
+		strcpy(to, save_cwd);
+		strcat(to, "/");
+		strcat(to, from);
+	}
+	chdir(save_cwd);
+	return(0);
+}
+
+static int write_cow_header(char *cow_file, int fd, char *backing_file, 
+			    int sectorsize, long long *size)
+{
+        struct cow_header_v2 *header;
+	struct stat64 buf;
+	int err;
+
+	err = os_seek_file(fd, 0);
+	if(err != 0){
+		printk("write_cow_header - lseek failed, errno = %d\n", errno);
+		return(-errno);
+	}
+
+	err = -ENOMEM;
+	header = um_kmalloc(sizeof(*header));
+	if(header == NULL){
+		printk("Failed to allocate COW V2 header\n");
+		goto out;
+	}
+	header->magic = htonl(COW_MAGIC);
+	header->version = htonl(COW_VERSION);
+
+	err = -EINVAL;
+	if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+		printk("Backing file name \"%s\" is too long - names are "
+		       "limited to %d characters\n", backing_file, 
+		       sizeof(header->backing_file) - 1);
+		goto out_free;
+	}
+
+	if(absolutize(header->backing_file, sizeof(header->backing_file), 
+		      backing_file))
+		goto out_free;
+
+	err = stat64(header->backing_file, &buf);
+	if(err < 0){
+		printk("Stat of backing file '%s' failed, errno = %d\n",
+		       header->backing_file, errno);
+		err = -errno;
+		goto out_free;
+	}
+
+	err = os_file_size(header->backing_file, size);
+	if(err){
+		printk("Couldn't get size of backing file '%s', errno = %d\n",
+		       header->backing_file, -*size);
+		goto out_free;
+	}
+
+	header->mtime = htonl(buf.st_mtime);
+	header->size = htonll(*size);
+	header->sectorsize = htonl(sectorsize);
+
+	err = write(fd, header, sizeof(*header));
+	if(err != sizeof(*header)){
+		printk("Write of header to new COW file '%s' failed, "
+		       "errno = %d\n", cow_file, errno);
+		goto out_free;
+	}
+	err = 0;
+ out_free:
+	kfree(header);
+ out:
+	return(err);
+}
+
+int open_ubd_file(char *file, struct openflags *openflags, 
+		  char **backing_file_out, int *bitmap_offset_out, 
+		  unsigned long *bitmap_len_out, int *data_offset_out, 
+		  int *create_cow_out)
+{
+	time_t mtime;
+	__u64 size;
+	char *backing_file;
+        int fd, err, sectorsize, magic, same, mode = 0644;
+
+        if((fd = os_open_file(file, *openflags, mode)) < 0){
+		if((fd == -ENOENT) && (create_cow_out != NULL))
+			*create_cow_out = 1;
+                if(!openflags->w ||
+                   ((errno != EROFS) && (errno != EACCES))) return(-errno);
+		openflags->w = 0;
+                if((fd = os_open_file(file, *openflags, mode)) < 0) 
+			return(fd);
+        }
+	if(backing_file_out == NULL) return(fd);
+
+	err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, 
+			      &sectorsize, bitmap_offset_out);
+	if(err && (*backing_file_out != NULL)){
+		printk("Failed to read COW header from COW file \"%s\", "
+		       "errno = %d\n", file, err);
+		goto error;
+	}
+	if(err) return(fd);
+
+	if(backing_file_out == NULL) return(fd);
+	
+	same = same_backing_files(*backing_file_out, backing_file, file);
+
+	if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
+		printk("Switching backing file to '%s'\n", *backing_file_out);
+		err = write_cow_header(file, fd, *backing_file_out, 
+				       sectorsize, &size);
+		if(err){
+			printk("Switch failed, errno = %d\n", err);
+			return(err);
+		}
+	}
+	else {
+		*backing_file_out = backing_file;
+		err = backing_file_mismatch(*backing_file_out, size, mtime);
+		if(err) goto error;
+	}
+
+	sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
+	      data_offset_out);
+
+        return(fd);
+ error:
+	close(fd);
+	return(err);
+}
+
+int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
+		    int sectorsize, int *bitmap_offset_out, 
+		    unsigned long *bitmap_len_out, int *data_offset_out)
+{
+	__u64 blocks;
+	long zero;
+	int err, fd, i;
+	long long size;
+
+	flags.c = 1;
+	fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
+	if(fd < 0){
+		err = fd;
+		printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
+		       -err);
+		goto out;
+	}
+
+	err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
+	if(err) goto out_close;
+
+	blocks = (size + sectorsize - 1) / sectorsize;
+	blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
+	zero = 0;
+	for(i = 0; i < blocks; i++){
+		err = write(fd, &zero, sizeof(zero));
+		if(err != sizeof(zero)){
+			printk("Write of bitmap to new COW file '%s' failed, "
+			       "errno = %d\n", cow_file, errno);
+			goto out_close;
+		}
+	}
+
+	sizes(size, sectorsize, sizeof(struct cow_header_v2), 
+	      bitmap_len_out, data_offset_out);
+	*bitmap_offset_out = sizeof(struct cow_header_v2);
+
+	return(fd);
+
+ out_close:
+	close(fd);
+ out:
+	return(err);
+}
+
+int read_ubd_fs(int fd, void *buffer, int len)
+{
+	int n;
+
+	n = read(fd, buffer, len);
+	if(n < 0) return(-errno);
+	else return(n);
+}
+
+int write_ubd_fs(int fd, char *buffer, int len)
+{
+	int n;
+
+	n = write(fd, buffer, len);
+	if(n < 0) return(-errno);
+	else return(n);
+}
+
+int ubd_is_dir(char *file)
+{
+	struct stat64 buf;
+
+	if(stat64(file, &buf) < 0) return(0);
+	return(S_ISDIR(buf.st_mode));
+}
+
+void do_io(struct io_thread_req *req)
+{
+	char *buf;
+	unsigned long len;
+	int n, nsectors, start, end, bit;
+	__u64 off;
+
+	nsectors = req->length / req->sectorsize;
+	start = 0;
+	do {
+		bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
+		end = start;
+		while((end < nsectors) && 
+		      (ubd_test_bit(end, (unsigned char *) 
+				    &req->sector_mask) == bit))
+			end++;
+
+		off = req->offset + req->offsets[bit] + 
+			start * req->sectorsize;
+		len = (end - start) * req->sectorsize;
+		buf = &req->buffer[start * req->sectorsize];
+
+		if(os_seek_file(req->fds[bit], off) != 0){
+			printk("do_io - lseek failed : errno = %d\n", errno);
+			req->error = 1;
+			return;
+		}
+		if(req->op == UBD_READ){
+			n = 0;
+			do {
+				buf = &buf[n];
+				len -= n;
+				n = read(req->fds[bit], buf, len);
+				if (n < 0) {
+					printk("do_io - read returned %d : "
+					       "errno = %d fd = %d\n", n,
+					       errno, req->fds[bit]);
+					req->error = 1;
+					return;
+				}
+			} while((n < len) && (n != 0));
+			if (n < len) memset(&buf[n], 0, len - n);
+		}
+		else {
+			n = write(req->fds[bit], buf, len);
+			if(n != len){
+				printk("do_io - write returned %d : "
+				       "errno = %d fd = %d\n", n, 
+				       errno, req->fds[bit]);
+				req->error = 1;
+				return;
+			}
+		}
+
+		start = end;
+	} while(start < nsectors);
+
+	if(req->cow_offset != -1){
+		if(os_seek_file(req->fds[1], req->cow_offset) != 0){
+			printk("do_io - bitmap lseek failed : errno = %d\n",
+			       errno);
+			req->error = 1;
+			return;
+		}
+		n = write(req->fds[1], &req->bitmap_words, 
+			  sizeof(req->bitmap_words));
+		if(n != sizeof(req->bitmap_words)){
+			printk("do_io - bitmap update returned %d : "
+			       "errno = %d fd = %d\n", n, errno, req->fds[1]);
+			req->error = 1;
+			return;
+		}
+	}
+	req->error = 0;
+	return;
+}
+
+int kernel_fd = -1;
+
+int io_count = 0;
+
+int io_thread(void *arg)
+{
+	struct io_thread_req req;
+	int n;
+
+	signal(SIGWINCH, SIG_IGN);
+	while(1){
+		n = read(kernel_fd, &req, sizeof(req));
+		if(n < 0) printk("io_thread - read returned %d, errno = %d\n",
+				 n, errno);
+		else if(n < sizeof(req)){
+			printk("io_thread - short read : length = %d\n", n);
+			continue;
+		}
+		io_count++;
+		do_io(&req);
+		n = write(kernel_fd, &req, sizeof(req));
+		if(n != sizeof(req))
+			printk("io_thread - write failed, errno = %d\n",
+			       errno);
+	}
+}
+
+int start_io_thread(unsigned long sp, int *fd_out)
+{
+	int pid, fds[2], err;
+
+	err = os_pipe(fds, 1, 1);
+	if(err){
+		printk("start_io_thread - os_pipe failed, errno = %d\n", -err);
+		return(-1);
+	}
+	kernel_fd = fds[0];
+	*fd_out = fds[1];
+
+	pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
+		    NULL);
+	if(pid < 0){
+		printk("start_io_thread - clone failed : errno = %d\n", errno);
+		return(-errno);
+	}
+	return(pid);
+}
+
+#ifdef notdef
+int start_io_thread(unsigned long sp, int *fd_out)
+{
+	int pid;
+
+	if((kernel_fd = get_pty()) < 0) return(-1);
+	raw(kernel_fd, 0);
+	if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){
+		printk("Couldn't open tty for IO\n");
+		return(-1);
+	}
+
+	pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
+		    NULL);
+	if(pid < 0){
+		printk("start_io_thread - clone failed : errno = %d\n", errno);
+		return(-errno);
+	}
+	return(pid);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/drivers/xterm.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,178 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include "kern_util.h"
+#include "chan_user.h"
+#include "helper.h"
+#include "user_util.h"
+#include "user.h"
+#include "os.h"
+
+struct xterm_chan {
+	int pid;
+	int helper_pid;
+	char *title;
+	int device;
+	int raw;
+	struct termios tt;
+	unsigned long stack;
+};
+
+void *xterm_init(char *str, int device, struct chan_opts *opts)
+{
+	struct xterm_chan *data;
+
+	if((data = malloc(sizeof(*data))) == NULL) return(NULL);
+	*data = ((struct xterm_chan) { pid :		-1, 
+				       helper_pid :	-1,
+				       device :		device, 
+				       title :		opts->xterm_title,
+				       raw : 		opts->raw,
+				       stack :		opts->tramp_stack } );
+	return(data);
+}
+
+static char *terminal_emulator = "xterm";
+static char *title_switch = "-T";
+static char *exec_switch = "-e";
+
+static int __init xterm_setup(char *line, int *add)
+{
+	*add = 0;
+	terminal_emulator = line;
+
+	line = strchr(line, ',');
+	if(line == NULL) return(0);
+	*line++ = '\0';
+	if(*line) title_switch = line;
+
+	line = strchr(line, ',');
+	if(line == NULL) return(0);
+	*line++ = '\0';
+	if(*line) exec_switch = line;
+
+	return(0);
+}
+
+__uml_setup("xterm=", xterm_setup,
+"xterm=<terminal emulator>,<title switch>,<exec switch>\n"
+"    Specifies an alternate terminal emulator to use for the debugger,\n"
+"    consoles, and serial lines when they are attached to the xterm channel.\n"
+"    The values are the terminal emulator binary, the switch it uses to set\n"
+"    its title, and the switch it uses to execute a subprocess,\n"
+"    respectively.  The title switch must have the form '<switch> title',\n"
+"    not '<switch>=title'.  Similarly, the exec switch must have the form\n"
+"    '<switch> command arg1 arg2 ...'.\n"
+"    The default values are 'xterm=xterm,-T,-e'.  Values for gnome-terminal\n"
+"    are 'xterm=gnome-terminal,-t,-x'.\n\n"
+);
+
+int xterm_open(int input, int output, int primary, void *d)
+{
+	struct xterm_chan *data = d;
+	unsigned long stack;
+	int pid, fd, new;
+	char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
+	char *argv[] = { terminal_emulator, title_switch, title, exec_switch, 
+			 "/usr/lib/uml/port-helper", "-uml-socket",
+			 file, NULL };
+
+	fd = mkstemp(file);
+	if(fd < 0){
+		printk("xterm_open : mkstemp failed, errno = %d\n", errno);
+		return(-errno);
+	}
+
+	if(unlink(file)){
+		printk("xterm_open : unlink failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	close(fd);
+
+	fd = create_unix_socket(file, sizeof(file));
+	if(fd < 0){
+		printk("xterm_open : create_unix_socket failed, errno = %d\n", 
+		       errno);
+		return(-errno);
+	}
+
+	sprintf(title, data->title, data->device);
+	stack = data->stack;
+	pid = run_helper(NULL, NULL, argv, &stack);
+	if(pid < 0){
+		printk("xterm_open : run_helper failed\n");
+		return(-1);
+	}
+
+	if(data->stack == 0) free_stack(stack, 0);
+
+	new = os_rcv_fd(fd, &data->helper_pid);
+	if(new < 0){
+		printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new);
+		return(new);
+	}
+
+	tcgetattr(new, &data->tt);
+	if(data->raw) raw(new, 0);
+
+	data->pid = pid;
+	return(new);
+}
+
+void xterm_close(int fd, void *d)
+{
+	struct xterm_chan *data = d;
+	
+	if(data->pid != -1) kill(data->pid, SIGKILL);
+	data->pid = -1;
+	if(data->helper_pid != -1) kill(data->helper_pid, SIGKILL);
+	data->helper_pid = -1;
+	close(fd);
+}
+
+void xterm_free(void *d)
+{
+	free(d);
+}
+
+int xterm_console_write(int fd, const char *buf, int n, void *d)
+{
+	struct xterm_chan *data = d;
+
+	return(generic_console_write(fd, buf, n, &data->tt));
+}
+
+struct chan_ops xterm_ops = {
+	init:		xterm_init,
+	open:		xterm_open,
+	close:		xterm_close,
+	read:		generic_read,
+	write:		generic_write,
+	console_write:	xterm_console_write,
+	window_size:	generic_window_size,
+	free:		xterm_free,
+	winch:		1,
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/2_5compat.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __2_5_COMPAT_H__
+#define __2_5_COMPAT_H__
+
+#include "linux/version.h"
+
+#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
+	name :		dev_name, \
+	write :		write_proc, \
+	read :		NULL, \
+	device :	device_proc, \
+	setup :		setup_proc, \
+	flags :		f, \
+	index :		-1, \
+	cflag :		0, \
+	next :		NULL \
+}
+
+#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock)
+
+#define ELV_NOOP elevator_noop
+#define INIT_ELV(queue, elv) elevator_init(queue, elv, ELV_NOOP)
+
+#define INIT_HARDSECT(arr, maj, sizes)
+
+#define SET_PRI(task) do ; while(0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/Makefile b/arch/um/include/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,7 @@
+all : sc.h
+
+sc.h : ../util/mk_sc
+	../util/mk_sc > $@
+
+../util/mk_sc :
+	$(MAKE) -C ../util mk_sc
diff -Nru a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/chan_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,53 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __CHAN_KERN_H__
+#define __CHAN_KERN_H__
+
+#include "linux/tty.h"
+#include "linux/list.h"
+#include "chan_user.h"
+
+struct chan {
+	struct list_head list;
+	unsigned int primary:1;
+	unsigned int input:1;
+	unsigned int output:1;
+	unsigned int opened:1;
+	int fd;
+	enum chan_init_pri pri;
+	struct chan_ops *ops;
+	void *data;
+};
+
+extern void chan_interrupt(struct list_head *chans, struct tq_struct *task,
+			   struct tty_struct *tty, int irq, void *dev);
+extern int parse_chan_pair(char *str, struct list_head *chans, int pri, 
+			   int device, struct chan_opts *opts);
+extern int open_chan(struct list_head *chans);
+extern int write_chan(struct list_head *chans, const char *buf, int len,
+			     int write_irq);
+extern int console_write_chan(struct list_head *chans, const char *buf, 
+			      int len);
+extern void close_chan(struct list_head *chans);
+extern void chan_enable_winch(struct list_head *chans, void *line);
+extern void enable_chan(struct list_head *chans, void *data);
+extern int chan_window_size(struct list_head *chans, 
+			     unsigned short *rows_out, 
+			     unsigned short *cols_out);
+extern int chan_out_fd(struct list_head *chans);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/chan_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,65 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __CHAN_USER_H__
+#define __CHAN_USER_H__
+
+#include "init.h"
+
+struct chan_opts {
+	void (*announce)(char *dev_name, int dev);
+	char *xterm_title;
+	int raw;
+	unsigned long tramp_stack;
+};
+
+enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
+
+struct chan_ops {
+	void *(*init)(char *, int, struct chan_opts *);
+	int (*open)(int, int, int, void *);
+	void (*close)(int, void *);
+	int (*read)(int, char *, void *);
+	int (*write)(int, const char *, int, void *);
+	int (*console_write)(int, const char *, int, void *);
+	int (*window_size)(int, void *, unsigned short *, unsigned short *);
+	void (*free)(void *);
+	int winch;
+};
+
+extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
+	xterm_ops;
+
+extern void generic_close(int fd, void *unused);
+extern int generic_read(int fd, char *c_out, void *unused);
+extern int generic_write(int fd, const char *buf, int n, void *unused);
+extern int generic_console_write(int fd, const char *buf, int n, void *state);
+extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+			       unsigned short *cols_out);
+extern void generic_free(void *data);
+
+extern void register_winch(int fd, void *device_data);
+extern void register_winch_irq(int fd, int tty_fd, int pid, void *line);
+extern void setup_tracer_winch(void);
+
+#define __channel_help(fn, prefix) \
+__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
+"    Attach a console or serial line to a host channel.  See\n" \
+"    http://user-mode-linux.sourceforge.net/input.html for a complete\n" \
+"    description of this switch.\n\n" \
+);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/debug.h b/arch/um/include/debug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/debug.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and
+ * Lars Brinkhoff.
+ * Licensed under the GPL
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+extern int debugger_proxy(int status, pid_t pid);
+extern void child_proxy(pid_t pid, int status);
+extern void init_proxy (pid_t pid, int waiting, int status);
+extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
+extern void fake_child_exit(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/frame.h b/arch/um/include/frame.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/frame.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,51 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_H_
+#define __FRAME_H_
+
+#include "sysdep/frame.h"
+
+struct sc_frame {
+	void *data;
+	int len;
+	int sig_index;
+	int sc_index;
+	int sr_index;
+	int sr_relative;
+	int sp_index;
+	struct arch_frame_data arch;
+};
+
+extern struct sc_frame signal_frame_sc;
+
+struct si_frame {
+	void *data;
+	int len;
+	int sig_index;
+	int sip_index;
+	int si_index;
+	int sr_index;
+	int sr_relative;
+	int sp_index;
+};
+
+extern struct si_frame signal_frame_si;
+
+extern void capture_signal_stack(void);
+extern void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/frame_kern.h b/arch/um/include/frame_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/frame_kern.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_KERN_H_
+#define __FRAME_KERN_H_
+
+#include "frame.h"
+#include "sysdep/frame_kern.h"
+
+extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 
+				 unsigned long handler,
+				 void (*restorer)(void), 
+				 struct pt_regs *regs, 
+				 sigset_t *mask);
+extern int setup_signal_stack_si(unsigned long stack_top, int sig, 
+				 unsigned long handler, 
+				 void (*restorer)(void), 
+				 struct pt_regs *regs, siginfo_t *info, 
+				 sigset_t *mask);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/frame_user.h b/arch/um/include/frame_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/frame_user.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_USER_H_
+#define __FRAME_USER_H_
+
+#include "sysdep/frame_user.h"
+#include "frame.h"
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/helper.h b/arch/um/include/helper.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/helper.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __HELPER_H__
+#define __HELPER_H__
+
+extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
+		      unsigned long *stack_out);
+extern int run_helper_thread(int (*proc)(void *), void *arg, 
+			     unsigned int flags, unsigned long *stack_out,
+			     int stack_order);
+extern int helper_wait(int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/hostaudio.h b/arch/um/include/hostaudio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/hostaudio.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,48 @@
+/* 
+ * Copyright (C) 2002 Steve Schmidtke 
+ * Licensed under the GPL
+ */
+
+#ifndef HOSTAUDIO_H
+#define HOSTAUDIO_H
+
+#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
+#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
+
+struct hostaudio_state {
+  int fd;
+};
+
+struct hostmixer_state {
+  int fd;
+};
+
+/* UML user-side protoypes */
+extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer,
+				   size_t count, loff_t *ppos);
+extern ssize_t hostaudio_write_user(struct hostaudio_state *state, 
+				    const char *buffer, size_t count, 
+				    loff_t *ppos);
+extern int hostaudio_ioctl_user(struct hostaudio_state *state, 
+				unsigned int cmd, unsigned long arg);
+extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, 
+			       char *dsp);
+extern int hostaudio_release_user(struct hostaudio_state *state);
+extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
+				unsigned int cmd, unsigned long arg);
+extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, 
+				      int w, char *mixer);
+extern int hostmixer_release_mixdev_user(struct hostmixer_state *state);
+
+#endif /* HOSTAUDIO_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/init.h b/arch/um/include/init.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/init.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,114 @@
+#ifndef _LINUX_UML_INIT_H
+#define _LINUX_UML_INIT_H
+
+/* These macros are used to mark some functions or
+ * initialized data (doesn't apply to uninitialized data)
+ * as `initialization' functions. The kernel can take this
+ * as hint that the function is used only during the initialization
+ * phase and free up used memory resources after
+ *
+ * Usage:
+ * For functions:
+ *
+ * You should add __init immediately before the function name, like:
+ *
+ * static void __init initme(int x, int y)
+ * {
+ *    extern int z; z = x * y;
+ * }
+ *
+ * If the function has a prototype somewhere, you can also add
+ * __init between closing brace of the prototype and semicolon:
+ *
+ * extern int initialize_foobar_device(int, int, int) __init;
+ *
+ * For initialized data:
+ * You should insert __initdata between the variable name and equal
+ * sign followed by value, e.g.:
+ *
+ * static int init_variable __initdata = 0;
+ * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ *
+ * Don't forget to initialize data not at file scope, i.e. within a function,
+ * as gcc otherwise puts the data into the bss section and not into the init
+ * section.
+ *
+ * Also note, that this data cannot be "const".
+ */
+
+#ifndef _LINUX_INIT_H
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init          __attribute__ ((__section__ (".text.init")))
+#define __exit          __attribute__ ((unused, __section__(".text.exit")))
+#define __initdata      __attribute__ ((__section__ (".data.init")))
+
+#endif
+
+#ifndef MODULE
+struct uml_param {
+        const char *str;
+        int (*setup_func)(char *, int *);
+};
+
+extern initcall_t __uml_initcall_start, __uml_initcall_end;
+extern initcall_t __uml_postsetup_start, __uml_postsetup_end;
+extern const char *__uml_help_start, *__uml_help_end;
+#endif
+
+#define __uml_initcall(fn)					  	\
+	static initcall_t __uml_initcall_##fn __uml_init_call = fn
+
+#define __uml_exitcall(fn)						\
+	static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn
+
+extern struct uml_param __uml_setup_start, __uml_setup_end;
+
+#define __uml_postsetup(fn)						\
+	static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn
+
+#define __non_empty_string(dummyname,string)				\
+	struct __uml_non_empty_string_struct_##dummyname		\
+	{								\
+		char _string[sizeof(string)-2];				\
+	}
+
+#ifndef MODULE
+#define __uml_setup(str, fn, help...)					\
+	__non_empty_string(fn ##_setup, str);				\
+	__uml_help(fn, help);						\
+	static char __uml_setup_str_##fn[] __initdata = str;		\
+	static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn }
+#else
+#define __uml_setup(str, fn, help...)					\
+
+#endif
+
+#define __uml_help(fn, help...)						\
+	__non_empty_string(fn ##__help, help);				\
+	static char __uml_help_str_##fn[] __initdata = help;		\
+	static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn
+
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __uml_init_setup	__attribute__ ((unused,__section__ (".uml.setup.init")))
+#define __uml_setup_help	__attribute__ ((unused,__section__ (".uml.help.init")))
+#define __uml_init_call		__attribute__ ((unused,__section__ (".uml.initcall.init")))
+#define __uml_postsetup_call	__attribute__ ((unused,__section__ (".uml.postsetup.init")))
+#define __uml_exit_call		__attribute__ ((unused,__section__ (".uml.exitcall.exit")))
+
+#endif /* _LINUX_UML_INIT_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/initrd.h b/arch/um/include/initrd.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/initrd.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __INITRD_USER_H__
+#define __INITRD_USER_H__
+
+extern int load_initrd(char *filename, void *buf, int size);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/irq_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,33 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __IRQ_USER_H__
+#define __IRQ_USER_H__
+
+enum { IRQ_READ, IRQ_WRITE };
+
+extern void sigio_handler(int sig, struct uml_pt_regs *regs);
+extern int activate_fd(int irq, int fd, int type, void *dev_id);
+extern void free_irq_by_irq_and_dev(int irq, void *dev_id);
+extern void free_irq_by_fd(int fd);
+extern void reactivate_fd(int fd, int irqnum);
+extern void deactivate_fd(int fd, int irqnum);
+extern void forward_interrupts(int pid);
+extern void init_irq_signals(int on_sigstack);
+extern void forward_ipi(int fd, int pid);
+extern void free_irq_later(int irq, void *dev_id);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/kern.h b/arch/um/include/kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,47 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __KERN_H__
+#define __KERN_H__
+
+/* These are all user-mode things which are convenient to call directly
+ * from kernel code and for which writing a wrapper is too much of a pain.
+ * The regular include files can't be included because this file is included
+ * only into kernel code, and user-space includes conflict with kernel
+ * includes.
+ */
+
+extern int errno;
+
+extern int clone(int (*proc)(void *), void *sp, int flags, void *data);
+extern int sleep(int);
+extern int printf(char *fmt, ...);
+extern char *strerror(int errnum);
+extern char *ptsname(int __fd);
+extern int munmap(void *, int);
+extern void *sbrk(int increment);
+extern void *malloc(int size);
+extern void perror(char *err);
+extern int kill(int pid, int sig);
+extern int getuid(void);
+extern int pause(void);
+extern int write(int, const void *, int);
+extern int exit(int);
+extern int close(int);
+extern int read(unsigned int, char *, int);
+extern int pipe(int *);
+extern int sched_yield(void);
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/kern_util.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,136 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __KERN_UTIL_H__
+#define __KERN_UTIL_H__
+
+#include "sysdep/ptrace.h"
+
+extern int ncpus;
+extern char *linux_prog;
+extern char *gdb_init;
+extern int kmalloc_ok;
+extern int timer_irq_inited;
+extern int jail;
+
+#define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK))
+#define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
+
+extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
+extern unsigned long stack_sp(unsigned long page);
+extern int kernel_thread_proc(void *data);
+extern void syscall_segv(int sig);
+extern int current_pid(void);
+extern void set_init_pid(int pid);
+extern unsigned long alloc_stack(int order, int atomic);
+extern int do_signal(int error);
+extern int is_stack_fault(unsigned long sp);
+extern unsigned long segv(unsigned long address, unsigned long ip, 
+			  int is_write, int is_user, void *sc_ptr);
+extern int set_user_mode(void *task);
+extern void syscall_ready(void);
+extern void set_tracing(void *t, int tracing);
+extern int is_tracing(void *task);
+extern int segv_syscall(void);
+extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
+extern int page_size(void);
+extern int page_mask(void);
+extern int need_finish_fork(void);
+extern int do_proc_op(void *t, int proc_id);
+extern void free_stack(unsigned long stack, int order);
+extern void add_input_request(int op, void (*proc)(int), void *arg);
+extern int sys_execve(char *file, char **argv, char **env);
+extern char *current_cmd(void);
+extern void timer_handler(int sig, struct uml_pt_regs *regs);
+extern int set_signals(int enable);
+extern void force_sigbus(void);
+extern int pid_to_processor_id(int pid);
+extern void block_signals(void);
+extern void unblock_signals(void);
+extern void deliver_signals(void *t);
+extern void lock_syscall(void);
+extern void unlock_syscall(void);
+extern void lock_trap(void);
+extern void unlock_trap(void);
+extern void lock_pid(void);
+extern void unlock_pid(void);
+extern void default_idle(void);
+extern void finish_fork(void);
+extern void paging_init(void);
+extern unsigned long um_virt_to_phys(void *t, unsigned long addr);
+extern void init_flush_vm(void);
+extern void *syscall_sp(void *t);
+extern void syscall_trace(void);
+extern int hz(void);
+extern void idle_timer(void);
+extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
+extern int external_pid(void *t);
+extern int pid_to_processor_id(int pid);
+extern void boot_timer_handler(int sig);
+extern void interrupt_end(void);
+extern void tracing_reboot(void);
+extern void tracing_halt(void);
+extern void tracing_cb(void (*proc)(void *), void *arg);
+extern int debugger_signal(int status, int pid);
+extern void debugger_parent_signal(int status, int pid);
+extern void child_signal(int pid, int status);
+extern int init_ptrace_proxy(int idle_pid, int startup, int stop);
+extern int init_parent_proxy(int pid);
+extern void check_stack_overflow(void *ptr);
+extern void relay_signal(int sig, struct uml_pt_regs *regs);
+extern int singlestepping(void *t);
+extern void clear_singlestep(void *t);
+extern void not_implemented(void);
+extern int user_context(unsigned long sp);
+extern void timer_irq(struct uml_pt_regs *regs);
+extern void unprotect_stack(unsigned long stack);
+extern void do_uml_exitcalls(void);
+extern int attach_debugger(int idle_pid, int pid, int stop);
+extern void *round_up(unsigned long addr);
+extern void *round_down(unsigned long addr);
+extern void bad_segv(unsigned long address, unsigned long ip, int is_write);
+extern int config_gdb(char *str);
+extern int remove_gdb(void);
+extern char *uml_strdup(char *string);
+extern void unprotect_kernel_mem(void);
+extern void protect_kernel_mem(void);
+extern unsigned long get_kmem_end(void);
+extern void set_kmem_end(unsigned long);
+extern void set_task_sizes(int arg);
+extern void uml_cleanup(void);
+extern int pid_to_processor_id(int pid);
+extern void set_current(void *t);
+extern void lock_signalled_task(void *t);
+extern void IPI_handler(int cpu);
+extern int jail_setup(char *line, int *add);
+extern void *get_init_task(void);
+extern int clear_user_proc(void *buf, int size);
+extern int copy_to_user_proc(void *to, void *from, int size);
+extern int copy_from_user_proc(void *to, void *from, int size);
+extern void set_thread_sc(void *sc);
+extern void bus_handler(int sig, struct uml_pt_regs *regs);
+extern long execute_syscall(void *r);
+extern int smp_sigio_handler(void);
+extern void *get_current(void);
+extern struct task_struct *get_task(int pid, int require);
+extern void machine_halt(void);
+extern int is_syscall(unsigned long addr);
+extern void arch_switch(void);
+extern int is_valid_pid(int pid);
+extern void free_irq(unsigned int, void *);
+extern int um_in_interrupt(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/line.h b/arch/um/include/line.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/line.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __LINE_H__
+#define __LINE_H__
+
+#include "linux/list.h"
+#include "linux/tqueue.h"
+#include "linux/tty.h"
+#include "asm/semaphore.h"
+#include "chan_user.h"
+
+struct line_driver {
+	char *name;
+	char *devfs_name;
+	short major;
+	short minor_start;
+	short type;
+	short subtype;
+	int read_irq;
+	char *read_irq_name;
+	int write_irq;
+	char *write_irq_name;
+	char *symlink_from;
+	char *symlink_to;
+};
+
+struct line {
+	char *init_str;
+	int init_pri;
+	struct list_head chan_list;
+	int valid;
+	int count;
+	struct tty_struct *tty;
+	struct semaphore sem;
+	char *buffer;
+	char *head;
+	char *tail;
+	int sigio;
+	struct tq_struct task;
+	struct line_driver *driver;
+	int have_irq;
+};
+
+#define LINE_INIT(str, d) \
+	{ init_str :	str, \
+	  init_pri :	INIT_STATIC, \
+	  chan_list : 	{ }, \
+	  valid :	1, \
+	  count :	0, \
+	  tty :		NULL, \
+	  sem : 	{ }, \
+	  buffer :	NULL, \
+	  head :	NULL, \
+	  tail :	NULL, \
+	  sigio :	0, \
+ 	  driver :	d, \
+          have_irq :	0 }
+
+struct lines {
+	int num;
+	int refcount;
+};
+
+#define LINES_INIT(n) \
+	{  num :		n, \
+	   refcount :		0 }
+
+extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
+extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
+extern void line_close(struct line *lines, struct tty_struct *tty);
+extern int line_open(struct line *lines, struct tty_struct *tty, 
+		     struct chan_opts *opts);
+extern void line_setup(struct line *lines, int num, char *init);
+extern int line_write(struct line *line, struct tty_struct *tty, 
+		      const char *buf, int len);
+extern int line_write_room(struct tty_struct *tty);
+extern char *add_xterm_umid(char *base);
+extern int line_setup_irq(int fd, int input, int output, void *data);
+extern void line_close_chan(struct line *line);
+extern void line_disable(struct line *line, int current_irq);
+extern void line_register_devfs(struct lines *set, 
+				struct line_driver *line_driver, 
+				struct tty_driver *driver, struct line *lines,
+				int nlines);
+extern void lines_init(struct line *lines, int nlines);
+extern void close_lines(struct line *lines, int nlines);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/mconsole.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MCONSOLE_H__
+#define __MCONSOLE_H__
+
+#define MCONSOLE_MAGIC (0xcafebabe)
+#define MCONSOLE_MAX_DATA (512)
+#define MCONSOLE_VERSION 2
+
+struct mconsole_request {
+	unsigned long magic;
+	int version;
+	int len;
+	char data[MCONSOLE_MAX_DATA];
+};
+
+struct mconsole_reply {
+	int err;
+	int more;
+	int len;
+	char data[MCONSOLE_MAX_DATA];
+};
+
+struct mconsole_notify {
+	unsigned long magic;
+	int version;	
+	enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG,
+	       MCONSOLE_USER_NOTIFY } type;
+	int len;
+	char data[MCONSOLE_MAX_DATA];
+};
+
+struct mc_request;
+
+struct mconsole_command
+{
+	char *command;
+	void (*handler)(struct mc_request *req);
+	int as_interrupt;
+};
+
+struct mc_request
+{
+	int len;
+	int as_interrupt;
+
+	int originating_fd;
+	int originlen;
+	unsigned char origin[128];			/* sockaddr_un */
+
+	struct mconsole_request request;
+	struct mconsole_command *cmd;
+};
+
+extern char mconsole_socket_name[];
+
+extern int mconsole_unlink_socket(void);
+extern int mconsole_reply(struct mc_request *req, char *reply, int err,
+			  int more);
+
+extern void mconsole_version(struct mc_request *req);
+extern void mconsole_help(struct mc_request *req);
+extern void mconsole_halt(struct mc_request *req);
+extern void mconsole_reboot(struct mc_request *req);
+extern void mconsole_config(struct mc_request *req);
+extern void mconsole_remove(struct mc_request *req);
+extern void mconsole_sysrq(struct mc_request *req);
+extern void mconsole_cad(struct mc_request *req);
+extern void mconsole_stop(struct mc_request *req);
+extern void mconsole_go(struct mc_request *req);
+
+extern int mconsole_get_request(int fd, struct mc_request *req);
+extern int mconsole_notify(char *sock_name, int type, const void *data, 
+			   int len);
+extern char *mconsole_notify_socket(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/mconsole_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MCONSOLE_KERN_H__
+#define __MCONSOLE_KERN_H__
+
+#include "linux/config.h"
+#include "linux/list.h"
+#include "mconsole.h"
+
+struct mconsole_entry {
+	struct list_head list;
+	struct mc_request request;
+};
+
+struct mc_device {
+	struct list_head list;
+	char *name;
+	int (*config)(char *);
+	int (*remove)(char *);
+};
+
+#ifdef CONFIG_MCONSOLE
+
+extern void mconsole_register_dev(struct mc_device *new);
+
+#else
+
+static inline void mconsole_register_dev(struct mc_device *new)
+{
+}
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/mem.h b/arch/um/include/mem.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/mem.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+struct vm_reserved {
+	struct list_head list;
+	unsigned long start;
+	unsigned long end;
+};
+
+extern void set_usable_vm(unsigned long start, unsigned long end);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/mem_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,88 @@
+/*
+ * arch/um/include/mem_user.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * user side memory interface for support IO memory inside user mode linux
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ *  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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEM_USER_H
+#define _MEM_USER_H
+
+struct mem_region {
+	char *driver;
+	unsigned long start;
+	unsigned long len;
+	void *mem_map;
+	int fd;
+};
+
+extern struct mem_region *regions[];
+extern struct mem_region physmem_region;
+
+#define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
+
+extern unsigned long host_task_size;
+extern unsigned long task_size;
+
+extern int init_mem_user(void);
+extern int create_mem_file(unsigned long len);
+extern void setup_range(int fd, char *driver, unsigned long start,
+			unsigned long total, struct mem_region *region,
+			void *reserved);
+extern void map(unsigned long virt, unsigned long p, unsigned long len, 
+		int r, int w, int x);
+extern int unmap(void *addr, int len);
+extern int protect(unsigned long addr, unsigned long len, int r, int w, 
+		   int x, int must_succeed);
+extern void setup_memory(void *entry);
+extern unsigned long find_iomem(char *driver, unsigned long *len_out);
+extern int init_maps(struct mem_region *region);
+extern int nregions(void);
+extern void setup_one_range(int n, int fd, char *driver, unsigned long start, 
+			    unsigned long len, struct mem_region *region);
+extern int reserve_vm(unsigned long start, unsigned long end, void *e);
+extern unsigned long get_vm(unsigned long len);
+extern void setup_physmem(unsigned long start, unsigned long usable,
+			  unsigned long len);
+extern int setup_region(struct mem_region *region, void *entry);
+extern void add_iomem(char *name, int fd, int size);
+extern struct mem_region *phys_region(unsigned long phys);
+extern unsigned long phys_offset(unsigned long phys);
+extern void unmap_physmem(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/net_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,75 @@
+#ifndef __UM_NET_KERN_H
+#define __UM_NET_KERN_H
+
+#include "linux/netdevice.h"
+#include "linux/skbuff.h"
+#include "linux/socket.h"
+#include "linux/list.h"
+
+#define MAX_UML_NETDEV (16)
+
+struct uml_net {
+	struct net_device *dev;
+	struct net_user_info *user;
+	struct net_kern_info *kern;
+	int private_size;
+	int transport_index;
+	unsigned char mac[ETH_ALEN];
+	int have_mac;
+};
+
+struct uml_net_private {
+	struct list_head list;
+	spinlock_t lock;
+	struct net_device *dev;
+	struct timer_list tl;
+	struct net_device_stats stats;
+	int fd;
+	unsigned char mac[ETH_ALEN];
+	int have_mac;
+	unsigned short (*protocol)(struct sk_buff *);
+	int (*open)(void *);
+	void (*close)(int, void *);
+	void (*remove)(void *);
+	int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
+	int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
+	
+	void (*add_address)(unsigned char *, unsigned char *, void *);
+	void (*delete_address)(unsigned char *, unsigned char *, void *);
+	int (*set_mtu)(int mtu, void *);
+	int user[1];
+};
+
+struct net_kern_info {
+	void (*init)(struct net_device *, int);
+	unsigned short (*protocol)(struct sk_buff *);
+	int (*read)(int, struct sk_buff **skb, struct uml_net_private *);
+	int (*write)(int, struct sk_buff **skb, struct uml_net_private *);
+};
+
+struct transport {
+	struct list_head list;
+	char *name;
+	int (*setup)(char *, struct uml_net *);
+};
+
+extern struct net_device *ether_init(int);
+extern unsigned short ether_protocol(struct sk_buff *);
+extern int setup_etheraddr(char *str, unsigned char *addr);
+extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
+extern int tap_setup_common(char *str, char *type, char **dev_name, 
+			    char *hw_addr, int *hw_setup, char **gate_addr);
+extern void register_transport(struct transport *new);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/net_user.h b/arch/um/include/net_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/net_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,57 @@
+#ifndef __UM_NET_USER_H__
+#define __UM_NET_USER_H__
+
+#define ETH_ADDR_LEN (6)
+#define ETH_HEADER_ETHERTAP (16)
+#define ETH_HEADER_OTHER (14)
+#define ETH_MAX_PACKET (1500)
+
+#define UML_NET_VERSION (4)
+
+struct net_user_info {
+	void (*init)(void *, void *);
+	int (*open)(void *);
+	void (*close)(int, void *);
+	void (*remove)(void *);
+	int (*set_mtu)(int mtu, void *);
+	void (*add_address)(unsigned char *, unsigned char *, void *);
+	void (*delete_address)(unsigned char *, unsigned char *, void *);
+	int max_packet;
+};
+
+extern void ether_user_init(void *data, void *dev);
+extern void dev_ip_addr(void *d, char *buf, char *bin_buf);
+extern void set_ether_mac(void *d, unsigned char *addr);
+extern void iter_addresses(void *d, void (*cb)(unsigned char *, 
+					       unsigned char *, void *), 
+			   void *arg);
+
+extern void *get_output_buffer(int *len_out);
+extern void free_output_buffer(void *buffer);
+
+extern int tap_open_common(void *dev, char *gate_addr);
+extern void tap_check_ips(char *gate_addr, char *eth_addr);
+
+extern void read_output(int fd, char *output_out, int len);
+
+extern int net_read(int fd, void *buf, int len);
+extern int net_recvfrom(int fd, void *buf, int len);
+extern int net_write(int fd, void *buf, int len);
+extern int net_send(int fd, void *buf, int len);
+extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len);
+
+extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg);
+extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/os.h b/arch/um/include/os.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/os.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,121 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __OS_H__
+#define __OS_H__
+
+#include "asm/types.h"
+#include "../os/include/file.h"
+
+#define OS_TYPE_FILE 1 
+#define OS_TYPE_DIR 2 
+#define OS_TYPE_SYMLINK 3 
+#define OS_TYPE_CHARDEV 4
+#define OS_TYPE_BLOCKDEV 5
+#define OS_TYPE_FIFO 6
+#define OS_TYPE_SOCK 7
+
+struct openflags {
+	unsigned int r : 1;
+	unsigned int w : 1;
+	unsigned int s : 1;	/* O_SYNC */
+	unsigned int c : 1;	/* O_CREAT */
+	unsigned int t : 1;	/* O_TRUNC */
+	unsigned int a : 1;	/* O_APPEND */
+	unsigned int e : 1;	/* O_EXCL */
+};
+
+#define OPENFLAGS() ((struct openflags) { r : 0, w : 0, c : 0, s : 0 })
+
+static inline struct openflags of_read(struct openflags flags)
+{
+	flags.r = 1; 
+	return(flags);
+}
+
+static inline struct openflags of_write(struct openflags flags)
+{
+	flags.w = 1; 
+	return(flags); 
+}
+
+static inline struct openflags of_rdwr(struct openflags flags)
+{
+	return(of_read(of_write(flags)));
+}
+
+static inline struct openflags of_set_rw(struct openflags flags, int r, int w)
+{
+	flags.r = r;
+	flags.w = w;
+	return(flags);
+}
+
+static inline struct openflags of_sync(struct openflags flags)
+{ 
+	flags.s = 1; 
+	return(flags); 
+}
+
+static inline struct openflags of_create(struct openflags flags)
+{ 
+	flags.c = 1; 
+	return(flags); 
+}
+ 
+static inline struct openflags of_trunc(struct openflags flags)
+{ 
+	flags.t = 1; 
+	return(flags); 
+}
+ 
+static inline struct openflags of_append(struct openflags flags)
+{ 
+	flags.a = 1; 
+	return(flags); 
+}
+ 
+static inline struct openflags of_excl(struct openflags flags)
+{ 
+	flags.e = 1; 
+	return(flags); 
+}
+ 
+extern int os_seek_file(int fd, __u64 offset);
+extern int os_open_file(char *file, struct openflags flags, int mode);
+extern int os_read_file(int fd, char *buf, int len);
+extern int os_file_size(char *file, long long *size_out);
+extern int os_pipe(int *fd, int stream, int close_on_exec);
+extern int os_set_fd_async(int fd, int owner);
+extern int os_set_fd_block(int fd, int blocking);
+extern int os_accept_connection(int fd);
+extern int os_shutdown_socket(int fd, int r, int w);
+extern void os_close_file(int fd);
+extern int os_rcv_fd(int fd, int *helper_pid_out);
+extern int create_unix_socket(char *file, int len);
+extern int os_connect_socket(char *name);
+extern int os_file_type(char *file);
+extern int os_file_mode(char *file, struct openflags *mode_out);
+extern int os_write_file(int fd, char *buf, int count);
+
+extern unsigned long os_process_pc(int pid);
+extern int os_process_parent(int pid);
+extern void os_stop_process(int pid);
+extern void os_kill_process(int pid);
+extern void os_usr1_process(int pid);
+extern int os_getpid(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/process.h b/arch/um/include/process.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/process.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,25 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PROCESS_H__
+#define __PROCESS_H__
+
+#include <asm/sigcontext.h>
+
+extern void sig_handler(int sig, struct sigcontext sc);
+extern void alarm_handler(int sig, struct sigcontext sc);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/ptrace_user.h b/arch/um/include/ptrace_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/ptrace_user.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,18 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __PTRACE_USER_H__
+#define __PTRACE_USER_H__
+
+#include "sysdep/ptrace_user.h"
+
+extern int ptrace_getregs(long pid, unsigned long *regs_out);
+extern int ptrace_setregs(long pid, unsigned long *regs_in);
+extern int ptrace_getfpregs(long pid, unsigned long *regs_out);
+extern void arch_enter_kernel(void *task, int pid);
+extern void arch_leave_kernel(void *task, int pid);
+extern void ptrace_pokeuser(unsigned long addr, unsigned long data);
+
+#endif
diff -Nru a/arch/um/include/sigcontext.h b/arch/um/include/sigcontext.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sigcontext.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UML_SIGCONTEXT_H__
+#define __UML_SIGCONTEXT_H__
+
+#include "sysdep/sigcontext.h"
+
+extern int sc_size(void *data);
+extern int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data);
+extern int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data);
+extern void sc_to_sc(void *to_ptr, void *from_ptr);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sigio.h b/arch/um/include/sigio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sigio.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGIO_H__
+#define __SIGIO_H__
+
+extern int write_sigio_irq(int fd);
+extern int register_sigio_fd(int fd);
+extern int read_sigio_fd(int fd);
+extern int add_sigio_fd(int fd, int read);
+extern int ignore_sigio_fd(int fd);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/signal_kern.h b/arch/um/include/signal_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/signal_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGNAL_KERN_H__
+#define __SIGNAL_KERN_H__
+
+#include "sysdep/ptrace.h"
+
+extern void signal_deliverer(int sig);
+extern int probe_stack(unsigned long sp, int delta);
+extern int have_signals(void *t);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/signal_user.h b/arch/um/include/signal_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/signal_user.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SIGNAL_USER_H__
+#define __SIGNAL_USER_H__
+
+extern int signal_stack_size;
+
+extern int change_sig(int signal, int on);
+extern void set_sigstack(void *stack, int size);
+extern void set_handler(int sig, void (*handler)(int), int flags, ...);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/syscall_user.h b/arch/um/include/syscall_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/syscall_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSCALL_USER_H__
+#define __SYSCALL_USER_H__
+
+#include <asm/sigcontext.h>
+
+extern void syscall_handler(int sig, struct uml_pt_regs *regs);
+extern void exit_kernel(int pid, void *task);
+extern int do_syscall(void *task, int pid);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/frame.h b/arch/um/include/sysdep-i386/frame.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/frame.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_I386_H
+#define __FRAME_I386_H
+
+struct arch_frame_data_raw {
+	unsigned long sc_end;
+};
+
+struct arch_frame_data {
+	int fpstate_size;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/frame_kern.h b/arch/um/include/sysdep-i386/frame_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/frame_kern.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_KERN_I386_H
+#define __FRAME_KERN_I386_H
+
+/* This is called from sys_sigreturn.  It takes the sp at the point of the
+ * sigreturn system call and returns the address of the sigcontext struct
+ * on the stack.
+ */
+
+static inline void *sp_to_sc(unsigned long sp)
+{
+	return((void *) sp);
+}
+
+static inline void *sp_to_rt_sc(unsigned long sp)
+{
+	unsigned long sc;
+
+	sc = sp - signal_frame_si.sp_index + signal_frame_si.len - 4;
+	return((void *) sc);
+}
+
+static inline void *sp_to_mask(unsigned long sp)
+{
+	unsigned long mask;
+
+	mask = sp - signal_frame_sc.sp_index + signal_frame_sc.len - 8;
+	return((void *) mask);
+}
+
+extern int sc_size(void *data);
+
+static inline void *sp_to_rt_mask(unsigned long sp)
+{
+	unsigned long mask;
+
+	mask = sp - signal_frame_si.sp_index + signal_frame_si.len + 
+		sc_size(&signal_frame_sc.arch) - 4;
+	return((void *) mask);
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/frame_user.h b/arch/um/include/sysdep-i386/frame_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/frame_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,82 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __FRAME_USER_I386_H
+#define __FRAME_USER_I386_H
+
+#include <asm/page.h>
+#include "sysdep/frame.h"
+
+/* This stuff is to calculate the size of the fp state struct at runtime
+ * because it has changed between 2.2 and 2.4 and it would be good for a
+ * UML compiled on one to work on the other.
+ * So, setup_arch_frame_raw fills in the arch struct with the raw data, which
+ * just contains the address of the end of the sigcontext.  This is invoked
+ * from the signal handler.
+ * setup_arch_frame uses that data to figure out what 
+ * arch_frame_data.fpstate_size should be.  It really has no idea, since it's
+ * not allowed to do sizeof(struct fpstate) but it's safe to consider that it's
+ * everything from the end of the sgcontext up to the top of the stack.  So,
+ * it masks off the page number to get the offset within the page and subtracts
+ * that from the page size, and that's how big the fpstate struct will be
+ * considered to be.
+ */
+
+static inline void setup_arch_frame_raw(struct arch_frame_data_raw *data,
+					struct sigcontext *sc)
+{
+	data->sc_end = (unsigned long) sc;
+	data->sc_end += sizeof(*sc);
+}
+
+static inline void setup_arch_frame(struct arch_frame_data_raw *in, 
+				    struct arch_frame_data *out)
+{
+	unsigned long fpstate_start = in->sc_end;
+
+	fpstate_start &= ~PAGE_MASK;
+	out->fpstate_size = PAGE_SIZE - fpstate_start;
+}
+
+/* This figures out where on the stack the SA_RESTORER function address
+ * is stored.  For i386, it's the signal handler return address, so it's
+ * located next to the frame pointer.
+ * This is inlined, so __builtin_frame_address(0) is correct.  Otherwise,
+ * it would have to be __builtin_frame_address(1).
+ */
+
+static inline unsigned long frame_restorer(void)
+{
+	unsigned long *fp;
+
+	fp = __builtin_frame_address(0);
+	return((unsigned long) (fp + 1));
+}
+
+/* Similarly, this returns the value of sp when the handler was first
+ * entered.  This is used to calculate the proper sp when delivering
+ * signals.
+ */
+
+static inline unsigned long frame_sp(void)
+{
+	unsigned long *fp;
+
+	fp = __builtin_frame_address(0);
+	return((unsigned long) (fp + 1));
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/ptrace.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,115 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_PTRACE_H
+#define __SYSDEP_I386_PTRACE_H
+
+#include "sysdep/sc.h"
+
+struct uml_pt_regs {
+	unsigned long args[6];
+	long syscall;
+	int is_user;
+	void *sc;
+};
+
+#define EMPTY_UML_PT_REGS { \
+	syscall : 	-1, \
+	args : 		{ [0 ... 5] = 0 }, \
+	is_user :	0, \
+	sc : 		NULL }
+
+#define UPT_IP(regs) SC_IP((regs)->sc)
+#define UPT_SP(regs) SC_SP((regs)->sc)
+#define UPT_EFLAGS(regs) SC_EFLAGS((regs)->sc)
+#define UPT_EAX(regs) SC_EAX((regs)->sc)
+#define UPT_EBX(regs) SC_EBX((regs)->sc)
+#define UPT_ECX(regs) SC_ECX((regs)->sc)
+#define UPT_EDX(regs) SC_EDX((regs)->sc)
+#define UPT_ESI(regs) SC_ESI((regs)->sc)
+#define UPT_EDI(regs) SC_EDI((regs)->sc)
+#define UPT_EBP(regs) SC_EBP((regs)->sc)
+#define UPT_ORIG_EAX(regs) ((regs)->syscall)
+#define UPT_CS(regs) SC_CS((regs)->sc)
+#define UPT_SS(regs) SC_SS((regs)->sc)
+#define UPT_DS(regs) SC_DS((regs)->sc)
+#define UPT_ES(regs) SC_ES((regs)->sc)
+#define UPT_FS(regs) SC_FS((regs)->sc)
+#define UPT_GS(regs) SC_GS((regs)->sc)
+#define UPT_SC(regs) ((regs)->sc)
+
+#define UPT_REG(regs, reg) \
+	({	unsigned long val; \
+		switch(reg){ \
+		case EIP: val = UPT_IP(regs); break; \
+		case UESP: val = UPT_SP(regs); break; \
+		case EAX: val = UPT_EAX(regs); break; \
+		case EBX: val = UPT_EBX(regs); break; \
+		case ECX: val = UPT_ECX(regs); break; \
+		case EDX: val = UPT_EDX(regs); break; \
+		case ESI: val = UPT_ESI(regs); break; \
+		case EDI: val = UPT_EDI(regs); break; \
+		case EBP: val = UPT_EBP(regs); break; \
+		case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \
+		case CS: val = UPT_CS(regs); break; \
+		case SS: val = UPT_SS(regs); break; \
+		case DS: val = UPT_DS(regs); break; \
+		case ES: val = UPT_ES(regs); break; \
+		case FS: val = UPT_FS(regs); break; \
+		case GS: val = UPT_GS(regs); break; \
+		case EFL: val = UPT_EFLAGS(regs); break; \
+		default :  \
+			panic("Bad register in UPT_REG : %d\n", reg);  \
+			val = -1; \
+		} \
+	        val; \
+	})
+	
+
+#define UPT_SET(regs, reg, val) \
+	do { \
+		switch(reg){ \
+		case EIP: UPT_IP(regs) = val; break; \
+		case UESP: UPT_SP(regs) = val; break; \
+		case EAX: UPT_EAX(regs) = val; break; \
+		case EBX: UPT_EBX(regs) = val; break; \
+		case ECX: UPT_ECX(regs) = val; break; \
+		case EDX: UPT_EDX(regs) = val; break; \
+		case ESI: UPT_ESI(regs) = val; break; \
+		case EDI: UPT_EDI(regs) = val; break; \
+		case EBP: UPT_EBP(regs) = val; break; \
+		case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \
+		case CS: UPT_CS(regs) = val; break; \
+		case SS: UPT_SS(regs) = val; break; \
+		case DS: UPT_DS(regs) = val; break; \
+		case ES: UPT_ES(regs) = val; break; \
+		case FS: UPT_FS(regs) = val; break; \
+		case GS: UPT_GS(regs) = val; break; \
+		case EFL: UPT_EFLAGS(regs) = val; break; \
+		default :  \
+			panic("Bad register in UPT_SET : %d\n", reg);  \
+			break; \
+		} \
+	} while (0)
+
+#define UPT_SET_SYSCALL_RETURN(regs, res) \
+	SC_SET_SYSCALL_RETURN((regs)->sc, (res))
+#define UPT_RESTART_SYSCALL(regs) SC_RESTART_SYSCALL((regs)->sc)
+#define UPT_ORIG_SYSCALL(regs) UPT_EAX(regs)
+#define UPT_SYSCALL_NR(regs) ((regs)->syscall)
+#define UPT_SYSCALL_RET(regs) UPT_EAX(regs)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/ptrace_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,62 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_I386_PTRACE_USER_H__
+#define __SYSDEP_I386_PTRACE_USER_H__
+
+#include <asm/ptrace.h>
+
+#define PT_OFFSET(r) ((r) * sizeof(long))
+
+#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX])
+#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX)
+
+#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX)
+#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX)
+#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
+#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
+#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+
+#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
+
+#define PT_IP_OFFSET PT_OFFSET(EIP)
+#define PT_IP(regs) ((regs)[EIP])
+#define PT_SP(regs) ((regs)[UESP])
+
+#ifndef FRAME_SIZE
+#define FRAME_SIZE (17)
+#endif
+#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
+
+#define FP_FRAME_SIZE (27)
+#define FPX_FRAME_SIZE (128)
+
+#ifdef PTRACE_GETREGS
+#define UM_HAVE_GETREGS
+#endif
+
+#ifdef PTRACE_SETREGS
+#define UM_HAVE_SETREGS
+#endif
+
+#ifdef PTRACE_GETFPREGS
+#define UM_HAVE_GETFPREGS
+#endif
+
+#ifdef PTRACE_SETFPREGS
+#define UM_HAVE_SETFPREGS
+#endif
+
+#ifdef PTRACE_GETFPXREGS
+#define UM_HAVE_GETFPXREGS
+#endif
+
+#ifdef PTRACE_SETFPXREGS
+#define UM_HAVE_SETFPXREGS
+#endif
+
+extern void update_debugregs(int seq);
+
+#endif
diff -Nru a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/sigcontext.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,52 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_SIGCONTEXT_I386_H
+#define __SYS_SIGCONTEXT_I386_H
+
+#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
+
+#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
+#define SC_SET_SYSCALL_RETURN(sc, result) do SC_EAX(sc) = (result) ; while(0)
+
+#define SC_FAULT_ADDR(sc) SC_CR2(sc)
+#define SC_FAULT_WRITE(sc) (SC_ERR(sc) & 2)
+
+/* ptrace expects that, at the start of a system call, %eax contains
+ * -ENOSYS, so this makes it so.
+ */
+#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
+
+/* These are General Protection and Page Fault */
+#define SEGV_IS_FIXABLE(sc) ((SC_TRAPNO(sc) == 13) || (SC_TRAPNO(sc) == 14))
+
+/* XXX struct sigcontext needs declaring by now */
+
+static inline void sc_to_regs(struct uml_pt_regs *regs, struct sigcontext *sc,
+			      unsigned long syscall)
+{
+	regs->syscall = syscall;
+	regs->args[0] = SC_EBX(sc);
+	regs->args[1] = SC_ECX(sc);
+	regs->args[2] = SC_EDX(sc);
+	regs->args[3] = SC_ESI(sc);
+	regs->args[4] = SC_EDI(sc);
+	regs->args[5] = SC_EBP(sc);
+}
+
+extern unsigned long *sc_sigmask(void *sc_ptr);
+extern int sc_get_fpregs(unsigned long buf, void *sc_ptr);
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-i386/syscalls.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,59 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/unistd.h"
+
+typedef long syscall_handler_t(struct pt_regs);
+
+#define EXECUTE_SYSCALL(syscall, regs) (*sys_call_table[syscall])(*regs);
+
+extern syscall_handler_t sys_modify_ldt;
+extern syscall_handler_t old_mmap_i386;
+extern syscall_handler_t old_select;
+extern syscall_handler_t sys_ni_syscall;
+
+#define ARCH_SYSCALLS \
+	[ __NR_mmap ] = old_mmap_i386, \
+	[ __NR_select ] = old_select, \
+	[ __NR_vm86old ] = sys_ni_syscall, \
+        [ __NR_modify_ldt ] = sys_modify_ldt, \
+	[ __NR_lchown32 ] = sys_lchown, \
+	[ __NR_getuid32 ] = sys_getuid, \
+	[ __NR_getgid32 ] = sys_getgid, \
+	[ __NR_geteuid32 ] = sys_geteuid, \
+	[ __NR_getegid32 ] = sys_getegid, \
+	[ __NR_setreuid32 ] = sys_setreuid, \
+	[ __NR_setregid32 ] = sys_setregid, \
+	[ __NR_getgroups32 ] = sys_getgroups, \
+	[ __NR_setgroups32 ] = sys_setgroups, \
+	[ __NR_fchown32 ] = sys_fchown, \
+	[ __NR_setresuid32 ] = sys_setresuid, \
+	[ __NR_getresuid32 ] = sys_getresuid, \
+	[ __NR_setresgid32 ] = sys_setresgid, \
+	[ __NR_getresgid32 ] = sys_getresgid, \
+	[ __NR_chown32 ] = sys_chown, \
+	[ __NR_setuid32 ] = sys_setuid, \
+	[ __NR_setgid32 ] = sys_setgid, \
+	[ __NR_setfsuid32 ] = sys_setfsuid, \
+	[ __NR_setfsgid32 ] = sys_setfsgid, \
+	[ __NR_pivot_root ] = sys_pivot_root, \
+	[ __NR_mincore ] = sys_mincore, \
+	[ __NR_madvise ] = sys_madvise, \
+        [ 222 ] = sys_ni_syscall, 
+        
+/* 222 doesn't yet have a name in include/asm-i386/unistd.h */
+
+#define LAST_ARCH_SYSCALL 222
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ia64/ptrace.h b/arch/um/include/sysdep-ia64/ptrace.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ia64/ptrace.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_PTRACE_H
+#define __SYSDEP_IA64_PTRACE_H
+
+struct sys_pt_regs {
+  int foo;
+};
+
+#define EMPTY_REGS { 0 }
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ia64/sigcontext.h b/arch/um/include/sysdep-ia64/sigcontext.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ia64/sigcontext.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SIGCONTEXT_H
+#define __SYSDEP_IA64_SIGCONTEXT_H
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ia64/syscalls.h b/arch/um/include/sysdep-ia64/syscalls.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ia64/syscalls.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_IA64_SYSCALLS_H
+#define __SYSDEP_IA64_SYSCALLS_H
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ppc/ptrace.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,104 @@
+/* 
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_PTRACE_PPC_H
+#define __SYS_PTRACE_PPC_H
+
+#include "linux/config.h"
+#include "linux/types.h"
+
+/* the following taken from <asm-ppc/ptrace.h> */
+
+#ifdef CONFIG_PPC64
+#define PPC_REG unsigned long /*long*/
+#else
+#define PPC_REG unsigned long
+#endif
+struct sys_pt_regs_s {
+	PPC_REG gpr[32];
+	PPC_REG nip;
+	PPC_REG msr;
+	PPC_REG orig_gpr3;	/* Used for restarting system calls */
+	PPC_REG ctr;
+	PPC_REG link;
+	PPC_REG xer;
+	PPC_REG ccr;
+	PPC_REG mq;		/* 601 only (not used at present) */
+				/* Used on APUS to hold IPL value. */
+	PPC_REG trap;		/* Reason for being here */
+	PPC_REG dar;		/* Fault registers */
+	PPC_REG dsisr;
+	PPC_REG result; 	/* Result of a system call */
+};
+
+#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG))
+
+struct sys_pt_regs {
+    PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)];
+};
+
+#define UM_MAX_REG (PT_FPR0)
+#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG))
+
+#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } }
+
+#define UM_REG(r, n) ((r)->regs[n])
+
+#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3)
+#define UM_SP(r) UM_REG(r, PT_R1)
+#define UM_IP(r) UM_REG(r, PT_NIP)
+#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR)
+#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0)
+#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3)
+#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4)
+#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5)
+#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6)
+#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7)
+#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8)
+
+#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG))
+#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG))
+#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG))
+#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG))
+#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG))
+#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG))
+
+#define UM_SET_SYSCALL_RETURN(_regs, result)	        \
+do {                                                    \
+        if (result < 0) {				\
+		(_regs)->regs[PT_CCR] |= 0x10000000;	\
+		UM_SYSCALL_RET((_regs)) = -result;	\
+        } else {					\
+		UM_SYSCALL_RET((_regs)) = result;	\
+        }                                               \
+} while(0)
+
+extern void shove_aux_table(unsigned long sp);
+#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp);
+
+/* These aren't actually defined.  The undefs are just to make sure
+ * everyone's clear on the concept.
+ */
+#undef UML_HAVE_GETREGS
+#undef UML_HAVE_GETFPREGS
+#undef UML_HAVE_SETREGS
+#undef UML_HAVE_SETFPREGS
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ppc/sigcontext.h b/arch/um/include/sysdep-ppc/sigcontext.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ppc/sigcontext.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,62 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_SIGCONTEXT_PPC_H
+#define __SYS_SIGCONTEXT_PPC_H
+
+#define DSISR_WRITE 0x02000000
+
+#define SC_FAULT_ADDR(sc) ({ \
+		struct sigcontext_struct *_sc = (sc); \
+		long retval = -1; \
+		switch (_sc->regs->trap) { \
+		case 0x300: \
+			/* data exception */ \
+			retval = _sc->regs->dar; \
+			break; \
+		case 0x400: \
+			/* instruction exception */ \
+			retval = _sc->regs->nip; \
+			break; \
+		default: \
+			panic("SC_FAULT_ADDR: unhandled trap type\n"); \
+		} \
+		retval; \
+	})
+
+#define SC_FAULT_WRITE(sc) ({ \
+		struct sigcontext_struct *_sc = (sc); \
+		long retval = -1; \
+		switch (_sc->regs->trap) { \
+		case 0x300: \
+			/* data exception */ \
+			retval = !!(_sc->regs->dsisr & DSISR_WRITE); \
+			break; \
+		case 0x400: \
+			/* instruction exception: not a write */ \
+			retval = 0; \
+			break; \
+		default: \
+			panic("SC_FAULT_ADDR: unhandled trap type\n"); \
+		} \
+		retval; \
+	})
+
+#define SC_IP(sc) ((sc)->regs->nip)
+#define SC_SP(sc) ((sc)->regs->gpr[1])
+#define SEGV_IS_FIXABLE(sc) (1)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysdep-ppc/syscalls.h b/arch/um/include/sysdep-ppc/syscalls.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysdep-ppc/syscalls.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,50 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2,
+			       unsigned long arg3, unsigned long arg4,
+			       unsigned long arg5, unsigned long arg6);
+
+#define EXECUTE_SYSCALL(syscall, regs) \
+        (*sys_call_table[syscall])(UM_SYSCALL_ARG1(&regs), \
+			           UM_SYSCALL_ARG2(&regs), \
+				   UM_SYSCALL_ARG3(&regs), \
+				   UM_SYSCALL_ARG4(&regs), \
+				   UM_SYSCALL_ARG5(&regs), \
+				   UM_SYSCALL_ARG6(&regs))
+
+extern syscall_handler_t sys_mincore;
+extern syscall_handler_t sys_madvise;
+
+/* old_mmap needs the correct prototype since syscall_kern.c includes
+ * this file.
+ */
+int old_mmap(unsigned long addr, unsigned long len,
+	     unsigned long prot, unsigned long flags,
+	     unsigned long fd, unsigned long offset);
+
+#define ARCH_SYSCALLS \
+	[ __NR_modify_ldt ] = sys_ni_syscall, \
+	[ __NR_pciconfig_read ] = sys_ni_syscall, \
+	[ __NR_pciconfig_write ] = sys_ni_syscall, \
+	[ __NR_pciconfig_iobase ] = sys_ni_syscall, \
+	[ __NR_pivot_root ] = sys_ni_syscall, \
+	[ __NR_multiplexer ] = sys_ni_syscall, \
+	[ __NR_mmap ] = old_mmap, \
+	[ __NR_madvise ] = sys_madvise, \
+	[ __NR_mincore ] = sys_mincore, 
+
+#define LAST_ARCH_SYSCALL __NR_mincore
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/sysrq.h b/arch/um/include/sysrq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/sysrq.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SYSRQ_H
+#define __UM_SYSRQ_H
+
+extern void show_trace(unsigned long *stack);
+
+#endif
diff -Nru a/arch/um/include/tlb.h b/arch/um/include/tlb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/tlb.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TLB_H__
+#define __TLB_H__
+
+extern void mprotect_kernel_vm(int w);
+extern void force_flush_all(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/ubd_user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,78 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_UBD_USER_H
+#define __UM_UBD_USER_H
+
+#include "os.h"
+
+enum ubd_req { UBD_READ, UBD_WRITE };
+
+struct io_thread_req {
+	enum ubd_req op;
+	int fds[2];
+	unsigned long offsets[2];
+	unsigned long long offset;
+	unsigned long length;
+	char *buffer;
+	int sectorsize;
+	unsigned long sector_mask;
+	unsigned long cow_offset;
+	unsigned long bitmap_words[2];
+	int error;
+};
+
+extern int open_ubd_file(char *file, struct openflags *openflags, 
+			 char **backing_file_out, int *bitmap_offset_out, 
+			 unsigned long *bitmap_len_out, int *data_offset_out,
+			 int *create_cow_out);
+extern int create_cow_file(char *cow_file, char *backing_file, 
+			   struct openflags flags, int sectorsize, 
+			   int *bitmap_offset_out, 
+			   unsigned long *bitmap_len_out,
+			   int *data_offset_out);
+extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
+extern int read_ubd_fs(int fd, void *buffer, int len);
+extern int write_ubd_fs(int fd, char *buffer, int len);
+extern int start_io_thread(unsigned long sp, int *fds_out);
+extern void do_io(struct io_thread_req *req);
+extern int ubd_is_dir(char *file);
+
+static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+{
+	__u64 n;
+	int bits, off;
+
+	bits = sizeof(data[0]) * 8;
+	n = bit / bits;
+	off = bit % bits;
+	return((data[n] & (1 << off)) != 0);
+}
+
+static inline void ubd_set_bit(__u64 bit, unsigned char *data)
+{
+	__u64 n;
+	int bits, off;
+
+	bits = sizeof(data[0]) * 8;
+	n = bit / bits;
+	off = bit % bits;
+	data[n] |= (1 << off);
+}
+
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/umid.h b/arch/um/include/umid.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/umid.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+extern int umid_file_name(char *name, char *buf, int len);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/umn.h b/arch/um/include/umn.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/umn.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UMN_H
+#define __UMN_H
+
+extern int open_umn_tty(int *slave_out, int *slipno_out);
+extern void close_umn_tty(int master, int slave);
+extern int umn_send_packet(int fd, void *data, int len);
+extern int set_umn_addr(int fd, char *addr, char *ptp_addr);
+extern void slip_unesc(unsigned char s);
+extern void umn_read(int fd);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/user.h b/arch/um/include/user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/user.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,29 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __USER_H__
+#define __USER_H__
+
+extern void panic(const char *fmt, ...);
+extern int printk(const char *fmt, ...);
+extern void schedule(void);
+extern void *um_kmalloc(int size);
+extern void *um_kmalloc_atomic(int size);
+extern void kfree(void *ptr);
+extern int in_aton(char *str);
+extern int open_gdb_chan(void);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/user_util.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,127 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __USER_UTIL_H__
+#define __USER_UTIL_H__
+
+#include "sysdep/ptrace.h"
+
+extern int grantpt(int __fd);
+extern int unlockpt(int __fd);
+extern char *ptsname(int __fd);
+
+enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+
+struct cpu_task {
+	int pid;
+	void *task;
+};
+
+extern struct cpu_task cpu_tasks[];
+
+extern unsigned long low_physmem;
+extern unsigned long high_physmem;
+extern unsigned long uml_physmem;
+extern unsigned long uml_reserved;
+extern unsigned long end_vm;
+extern unsigned long start_vm;
+
+extern int tracing_pid;
+extern int honeypot;
+
+extern char host_info[];
+
+extern char saved_command_line[];
+extern char command_line[];
+
+extern int gdb_pid;
+
+extern char *tempdir;
+
+extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
+extern unsigned long _unprotected_end;
+extern unsigned long brk_start;
+
+extern int pty_output_sigio;
+extern int pty_close_sigio;
+
+extern void *open_maps(void);
+extern void close_maps(void *fd);
+extern unsigned long get_brk(void);
+extern void stop(void);
+extern int proc_start_thread(unsigned long ip, unsigned long sp);
+extern void stack_protections(unsigned long address);
+extern void task_protections(unsigned long address);
+extern void abandon_proc_space(int (*proc)(void *), unsigned long sp);
+extern int signals(int (*init_proc)(void *), void *sp);
+extern int __personality(int);
+extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
+extern void *add_signal_handler(int sig, void (*handler)(int));
+extern void signal_init(void);
+extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
+			    int clone_flags, int (*tramp)(void *));
+extern void trace_myself(void);
+extern void timer(void);
+extern void get_profile_timer(void);
+extern void disable_profile_timer(void);
+extern void set_timers(int set_signal);
+extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
+extern int input_loop(void);
+extern void continue_execing_proc(int pid);
+extern int linux_main(int argc, char **argv);
+extern void remap_data(void *segment_start, void *segment_end, int w);
+extern void set_cmdline(char *cmd);
+extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
+extern void setup_input(void);
+extern int get_pty(void);
+extern void save_signal_state(int *sig_ptr);
+extern void *um_kmalloc(int size);
+extern int raw(int fd, int complain);
+extern int switcheroo(int fd, int prot, void *from, void *to, int size);
+extern void idle_sleep(int secs);
+extern void setup_machinename(char *machine_out);
+extern void setup_hostinfo(void);
+extern void add_arg(char *cmd_line, char *arg);
+extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
+extern void attach_process(int pid);
+extern void calc_sigframe_size(void);
+extern int fork_tramp(void *sig_stack);
+extern void do_exec(int old_pid, int new_pid);
+extern void tracer_panic(char *msg, ...);
+extern void close_fd(int);
+extern int make_tempfile(const char *template, char **tempname, int do_unlink);
+extern char *get_umid(int only_if_set);
+extern void do_longjmp(void *p);
+extern void term_handler(int sig);
+extern void suspend_new_thread(int fd);
+extern int detach(int pid, int sig);
+extern int attach(int pid);
+extern void kill_child_dead(int pid);
+extern int cont(int pid);
+extern void check_ptrace(void);
+extern void check_sigio(void);
+extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
+extern int user_read(int fd, char *buf, int len);
+extern int user_write(int fd, char *buf, int len);
+extern void write_sigio_workaround(void);
+extern void arch_check_bugs(void);
+extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
+extern void user_time_init(void);
+extern unsigned long pid_pc(int pid);
+extern int arch_fixup(unsigned long address, void *sc_ptr);
+extern void forward_pending_sigio(int target);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,86 @@
+O_TARGET = um.o
+
+obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \
+	helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
+	process.o process_kern.o ptrace.o reboot.o resource.o setup.o \
+	sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
+	syscall_kern.o syscall_user.o sysrq.o sys_call_table.o time.o \
+	time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
+	umid.o user_util.o
+
+ifeq ($(CONFIG_BLK_DEV_INITRD), y)
+  obj-y += initrd_kern.o initrd_user.o
+endif
+
+# user_syms.o not included here because Rules.make has its own ideas about
+# building anything in export-objs
+
+USER_OBJS = $(filter %_user.o,$(obj-y)) config.o process.o time.o umid.o \
+	user_util.o user_syms.o helper.o
+
+export-objs := ksyms.o process_kern.o signal_kern.o
+
+UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
+UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
+
+ifeq ($(CONFIG_MODULES), y)
+  DMODULES = -D__CONFIG_MODULES__
+endif
+
+ifeq ($(CONFIG_MODVERSIONS), y)
+  DMODVERSIONS = -D__CONFIG_MODVERSIONS__
+endif
+
+ifeq ($(CONFIG_GPROF), y)
+    obj-y += gprof_syms.o
+    export-objs += gprof_syms.o
+endif
+
+ifeq ($(CONFIG_GCOV), y)
+    obj-y += gmon_syms.o
+    export-objs += gmon_syms.o
+endif
+
+ifeq ($(CONFIG_TTY_LOG), y)
+    obj-y += tty_log.o
+    USER_OBJS += tty_log.o
+endif
+
+
+CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES) $(DMODVERSIONS) \
+	-I/usr/include -I../include
+
+CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS))
+
+include $(TOPDIR)/Rules.make
+
+$(O_TARGET) : unmap_fin.o
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+unmap.o: unmap.c
+	$(CC) $(UNMAP_CFLAGS) -c -o $@ $<
+
+frame.o: frame.c
+	$(CC) $(CFLAGS_$@) -c -o $@ $<
+
+unmap_fin.o : unmap.o
+	ld -r -o $@ $< -lc -L/usr/lib
+
+QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
+
+config.c : config.c.in $(TOPDIR)/.config
+	$(PERL) -e $(QUOTE) < config.c.in > $@
+
+clean:
+	rm -f config.c
+
+modules:
+
+fastdep:
+
+dep:
+
+archmrproper: clean
+
diff -Nru a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/config.c.in	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "init.h"
+
+static __initdata char *config = "
+CONFIG
+";
+
+static int __init print_config(char *line, int *add)
+{
+	printf("%s", config);
+	exit(0);
+}
+
+__uml_setup("--showconfig", print_config,
+"--showconfig\n"
+"    Prints the config file that this UML binary was generated from.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/exec_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,124 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/slab.h"
+#include "linux/smp_lock.h"
+#include "asm/ptrace.h"
+#include "asm/pgtable.h"
+#include "asm/tlbflush.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "kern.h"
+#include "irq_user.h"
+#include "tlb.h"
+#include "2_5compat.h"
+#include "os.h"
+
+/* See comment above fork_tramp for why sigstop is defined and used like
+ * this
+ */
+
+static int sigstop = SIGSTOP;
+
+static int exec_tramp(void *sig_stack)
+{
+	int sig = sigstop;
+
+	block_signals();
+	init_new_thread(sig_stack, NULL);
+	kill(os_getpid(), sig);
+	return(0);
+}
+
+void flush_thread(void)
+{
+	unsigned long stack;
+	int new_pid;
+
+	stack = alloc_stack(0, 0);
+	if(stack == 0){
+		printk(KERN_ERR 
+		       "flush_thread : failed to allocate temporary stack\n");
+		do_exit(SIGKILL);
+	}
+		
+	new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
+				   stack, 0, exec_tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR 
+		       "flush_thread : new thread failed, errno = %d\n",
+		       -new_pid);
+		do_exit(SIGKILL);
+	}
+
+	if(current->thread_info->cpu == 0)
+		forward_interrupts(new_pid);
+	current->thread.request.op = OP_EXEC;
+	current->thread.request.u.exec.pid = new_pid;
+	unprotect_stack((unsigned long) current->thread_info);
+	os_usr1_process(os_getpid());
+
+	free_page(stack);
+	protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+	task_protections((unsigned long) current->thread_info);
+	force_flush_all();
+	unblock_signals();
+}
+
+void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
+{
+	set_fs(USER_DS);
+	flush_tlb_mm(current->mm);
+	PT_REGS_IP(regs) = eip;
+	PT_REGS_SP(regs) = esp;
+	PT_FIX_EXEC_STACK(esp);
+}
+
+static int execve1(char *file, char **argv, char **env)
+{
+        int error;
+
+        error = do_execve(file, argv, env, &current->thread.regs);
+        if (error == 0){
+                current->ptrace &= ~PT_DTRACE;
+                set_cmdline(current_cmd());
+        }
+        return(error);
+}
+
+int um_execve(char *file, char **argv, char **env)
+{
+	if(execve1(file, argv, env) == 0) do_longjmp(current->thread.jmp);
+	return(-1);
+}
+
+int sys_execve(char *file, char **argv, char **env)
+{
+	int error;
+	char *filename;
+
+	lock_kernel();
+	filename = getname((char *) file);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename)) goto out;
+	error = execve1(filename, argv, env);
+	putname(filename);
+ out:
+	unlock_kernel();
+	return(error);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/exec_user.c b/arch/um/kernel/exec_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/exec_user.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,49 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ptrace_user.h"
+
+void do_exec(int old_pid, int new_pid)
+{
+	unsigned long regs[FRAME_SIZE];
+
+	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) ||
+	   (waitpid(new_pid, 0, WUNTRACED) < 0))
+		tracer_panic("do_exec failed to attach proc - errno = %d",
+			     errno);
+
+	if(ptrace_getregs(old_pid, regs) < 0)
+		tracer_panic("do_exec failed to get registers - errno = %d",
+			     errno);
+
+	kill(old_pid, SIGKILL);
+
+	if(ptrace_setregs(new_pid, regs) < 0)
+		tracer_panic("do_exec failed to start new proc - errno = %d",
+			     errno);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/exitcode.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,70 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/ctype.h"
+#include "linux/proc_fs.h"
+#include "asm/uaccess.h"
+
+int uml_exitcode = 0;
+
+static int read_proc_exitcode(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", uml_exitcode);
+	len -= off;
+	if(len <= off+count) *eof = 1;
+	*start = page + off;
+	if(len > count) len = count;
+	if(len < 0) len = 0;
+	return(len);
+}
+
+static int write_proc_exitcode(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	char *end, buf[sizeof("nnnnn\0")];
+	int tmp;
+
+	if(copy_from_user(buf, buffer, count))
+		return(-EFAULT);
+	tmp = simple_strtol(buf, &end, 0);
+	if((*end != '\0') && !isspace(*end))
+		return(-EINVAL);
+	uml_exitcode = tmp;
+	return(count);
+}
+
+int make_proc_exitcode(void)
+{
+	struct proc_dir_entry *ent;
+
+	ent = create_proc_entry("exitcode", 0600, &proc_root);
+	if(ent == NULL){
+		printk("make_proc_exitcode : Failed to register "
+		       "/proc/exitcode\n");
+		return(0);
+	}
+
+	ent->read_proc = read_proc_exitcode;
+	ent->write_proc = write_proc_exitcode;
+	
+	return(0);
+}
+
+__initcall(make_proc_exitcode);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/frame.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,293 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <wait.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "frame_user.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+#include "os.h"
+
+static int capture_stack(int (*child)(void *arg), void *arg, void *sp,
+			 unsigned long top, void **data_out)
+{
+	unsigned long regs[FRAME_SIZE];
+	int pid, status, n, len;
+
+	/* Start the child as a thread */
+	pid = clone(child, sp, CLONE_VM | SIGCHLD, arg);
+	if(pid < 0){
+		printf("capture_stack : clone failed - errno = %d\n", errno);
+		exit(1);
+	}
+
+	/* Wait for it to stop itself and continue it with a SIGUSR1 to force 
+	 * it into the signal handler.
+	 */
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
+		fprintf(stderr, "capture_stack : Expected SIGSTOP, "
+			"got status = 0x%x\n", status);
+		exit(1);
+	}
+	if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){
+		printf("capture_stack : PTRACE_CONT failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	/* Wait for it to stop itself again and grab its registers again.  
+	 * At this point, the handler has stuffed the addresses of
+	 * sig, sc, and SA_RESTORER in raw.
+	 */
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){
+		fprintf(stderr, "capture_stack : Expected SIGSTOP, "
+			"got status = 0x%x\n", status);
+		exit(1);
+	}
+	if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){
+		printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	/* It has outlived its usefulness, so continue it so it can exit */
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){
+		printf("capture_stack : mmap failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(waitpid(pid, &status, 0) < 0){
+		printf("capture_stack : waitpid failed - errno = %d\n", errno);
+		exit(1);
+	}
+	if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+		printf("capture_stack : Expected exit status 0, "
+		       "got status = 0x%x\n", status);
+		exit(1);
+	}
+
+	/* The frame that we want is the top of the signal stack */
+
+	len = top - PT_SP(regs);
+	*data_out = malloc(len);
+	if(*data_out == NULL){
+		printf("capture_stack : malloc failed - errno = %d\n", errno);
+		exit(1);
+	}
+	memcpy(*data_out, (void *) PT_SP(regs), len);
+
+	return(len);
+}
+
+static void child_common(void *sp, int size, sighandler_t handler, int flags)
+{
+	stack_t ss;
+	struct sigaction sa;
+
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+		printf("PTRACE_TRACEME failed, errno = %d\n", errno);
+	}
+	ss.ss_sp = sp;
+	ss.ss_flags = 0;
+	ss.ss_size = size;
+	if(sigaltstack(&ss, NULL) < 0){
+		printf("sigaltstack failed - errno = %d\n", errno);
+		_exit(1);
+	}
+
+	sa.sa_handler = handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_ONSTACK | flags;
+	if(sigaction(SIGUSR1, &sa, NULL) < 0){
+		printf("sigaction failed - errno = %d\n", errno);
+		_exit(1);
+	}
+
+	os_stop_process(os_getpid());
+}
+
+struct sc_frame signal_frame_sc;
+
+struct sc_frame_raw {
+	void *stack;
+	int size;
+	unsigned long sig;
+	unsigned long sc;
+	unsigned long sr;
+	unsigned long sp;
+	struct arch_frame_data_raw arch;
+};
+
+static struct sc_frame_raw *raw_sc = NULL;
+
+static void sc_handler(int sig, struct sigcontext sc)
+{
+	raw_sc->sig = (unsigned long) &sig;
+	raw_sc->sc = (unsigned long) &sc;
+	raw_sc->sr = frame_restorer();
+	raw_sc->sp = frame_sp();
+	setup_arch_frame_raw(&raw_sc->arch, &sc);
+	os_stop_process(os_getpid());
+	_exit(0);
+}
+
+static int sc_child(void *arg)
+{
+	raw_sc = arg;
+	child_common(raw_sc->stack, raw_sc->size, (sighandler_t) sc_handler, 
+		     0);
+	return(-1);
+}
+
+struct si_frame signal_frame_si;
+
+struct si_frame_raw {
+	void *stack;
+	int size;
+	unsigned long sig;
+	unsigned long sip;
+	unsigned long si;
+	unsigned long sr;
+	unsigned long sp;
+};
+
+static struct si_frame_raw *raw_si = NULL;
+
+static void si_handler(int sig, siginfo_t *si)
+{
+	raw_si->sig = (unsigned long) &sig;
+	raw_si->sip = (unsigned long) &si;
+	raw_si->si = (unsigned long) si;
+	raw_si->sr = frame_restorer();
+	raw_si->sp = frame_sp();
+	os_stop_process(os_getpid());
+	_exit(0);
+}
+
+static int si_child(void *arg)
+{
+	raw_si = arg;
+	child_common(raw_si->stack, raw_si->size, (sighandler_t) si_handler,
+		     SA_SIGINFO);
+	return(-1);
+}
+
+void capture_signal_stack(void)
+{
+	struct sc_frame_raw raw_sc;
+	struct si_frame_raw raw_si;
+	void *stack, *sigstack;
+	unsigned long top, sig_top, base;
+
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){
+		printf("capture_signal_stack : mmap failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+
+	top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+	sig_top = (unsigned long) sigstack + PAGE_SIZE;
+
+	raw_sc.stack = sigstack;
+	raw_sc.size = PAGE_SIZE;
+	signal_frame_sc.len = capture_stack(sc_child, &raw_sc, (void *) top,
+					    sig_top, &signal_frame_sc.data);
+
+	/* These are the offsets within signal_frame_sc.data (counting from
+	 * the bottom) of sig, sc, SA_RESTORER, and the initial sp.
+	 */
+
+	base = sig_top - signal_frame_sc.len;
+	signal_frame_sc.sig_index = raw_sc.sig - base;
+	signal_frame_sc.sc_index = raw_sc.sc - base;
+	signal_frame_sc.sr_index = raw_sc.sr - base;
+	if((*((unsigned long *) raw_sc.sr) & PAGE_MASK) == 
+	   (unsigned long) sigstack){
+		unsigned long *sr = (unsigned long *) raw_sc.sr;
+		unsigned long frame = (unsigned long) signal_frame_sc.data;
+
+		signal_frame_sc.sr_relative = 1;
+		*sr -= raw_sc.sr;
+		*((unsigned long *) (frame + signal_frame_sc.sr_index)) = *sr;
+	}
+	else signal_frame_sc.sr_relative = 0;
+	signal_frame_sc.sp_index = raw_sc.sp - base;
+	setup_arch_frame(&raw_sc.arch, &signal_frame_sc.arch);
+
+	/* Repeat for the siginfo variant */
+
+	raw_si.stack = sigstack;
+	raw_si.size = PAGE_SIZE;
+	signal_frame_si.len = capture_stack(si_child, &raw_si, (void *) top,
+					    sig_top, &signal_frame_si.data);
+	base = sig_top - signal_frame_si.len;
+	signal_frame_si.sig_index = raw_si.sig - base;
+	signal_frame_si.sip_index = raw_si.sip - base;
+	signal_frame_si.si_index = raw_si.si - base;
+	signal_frame_si.sr_index = raw_si.sr - base;
+	if((*((unsigned long *) raw_si.sr) & PAGE_MASK) == 
+	   (unsigned long) sigstack){
+		unsigned long *sr = (unsigned long *) raw_si.sr;
+		unsigned long frame = (unsigned long) signal_frame_si.data;
+
+		signal_frame_sc.sr_relative = 1;
+		*sr -= raw_si.sr;
+		*((unsigned long *) (frame + signal_frame_si.sr_index)) = *sr;
+	}
+	else signal_frame_si.sr_relative = 0;
+	signal_frame_si.sp_index = raw_si.sp - base;
+
+	if((munmap(stack, PAGE_SIZE) < 0) || 
+	   (munmap(sigstack, PAGE_SIZE) < 0)){
+		printf("capture_signal_stack : munmap failed - errno = %d\n", 
+		       errno);
+		exit(1);
+	}
+}
+
+void set_sc_ip_sp(void *sc_ptr, unsigned long ip, unsigned long sp)
+{
+	struct sigcontext *sc = sc_ptr;
+
+	SC_IP(sc) = ip;
+	SC_SP(sc) = sp;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/frame_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,97 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/signal.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+#include "sysdep/ptrace.h"
+
+static int copy_restorer(void (*restorer)(void), unsigned long start, 
+			 unsigned long sr_index, int sr_relative)
+{
+	if(restorer != 0){
+		if(copy_to_user((void *) (start + sr_index), &restorer, 
+				sizeof(restorer)))
+			return(1);
+	}
+	else if(sr_relative){
+		unsigned long *sr = (unsigned long *) (start + sr_index);
+		*sr += (unsigned long) sr;
+	}
+	return(0);
+}
+
+int setup_signal_stack_si(unsigned long stack_top, int sig, 
+			  unsigned long handler, void (*restorer)(void), 
+			  struct pt_regs *regs, siginfo_t *info, 
+			  sigset_t *mask)
+{
+	unsigned long start, sc, sigs;
+	void *sip;
+	int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+
+	start = stack_top - signal_frame_si.len - 
+		sc_size(&signal_frame_sc.arch) - sig_size;
+	sip = (void *) (start + signal_frame_si.si_index);
+	sc = start + signal_frame_si.len;
+	sigs = sc + sc_size(&signal_frame_sc.arch);
+	if(copy_sc_to_user((void *) sc, regs->regs.sc, 
+			   &signal_frame_sc.arch) ||
+	   copy_to_user((void *) start, signal_frame_si.data,
+			signal_frame_si.len) ||
+	   copy_to_user((void *) (start + signal_frame_si.sig_index), &sig, 
+			sizeof(sig)) ||
+	   copy_siginfo_to_user(sip, info) ||
+	   copy_to_user((void *) (start + signal_frame_si.sip_index), &sip,
+			sizeof(sip)) ||
+	   copy_to_user((void *) sigs, mask, sig_size) ||
+	   copy_restorer(restorer, start, signal_frame_si.sr_index,
+			 signal_frame_si.sr_relative))
+		return(1);
+	
+	PT_REGS_IP(regs) = handler;
+	PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+	return(0);
+}
+
+int setup_signal_stack_sc(unsigned long stack_top, int sig, 
+			  unsigned long handler, void (*restorer)(void), 
+			  struct pt_regs *regs, sigset_t *mask)
+{
+	int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+	unsigned long sigs, start = stack_top - signal_frame_sc.len - sig_size;
+	void *user_sc = (void *) (start + signal_frame_sc.sc_index);
+
+	sigs = start + signal_frame_sc.len;
+	if(copy_to_user((void *) start, signal_frame_sc.data, 
+			signal_frame_sc.len) ||
+	   copy_to_user((void *) (start + signal_frame_sc.sig_index), &sig,
+			sizeof(sig)) ||
+	   copy_sc_to_user(user_sc, regs->regs.sc, &signal_frame_sc.arch) ||
+	   copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) ||
+	   copy_to_user((void *) sigs, &mask->sig[1], sig_size) ||
+	   copy_restorer(restorer, start, signal_frame_sc.sr_index,
+			 signal_frame_sc.sr_relative))
+		return(1);
+
+	PT_REGS_IP(regs) = handler;
+	PT_REGS_SP(regs) = start + signal_frame_sc.sp_index;
+
+	set_sc_ip_sp(regs->regs.sc, handler, start + signal_frame_sc.sp_index);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/gmon_syms.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+
+extern void __bb_init_func(void *);
+EXPORT_SYMBOL(__bb_init_func);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/gprof_syms.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+
+extern void mcount(void);
+EXPORT_SYMBOL(mcount);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/helper.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,146 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/signal.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "kern_util.h"
+#include "os.h"
+
+struct helper_data {
+	void (*pre_exec)(void*);
+	void *pre_data;
+	char **argv;
+	int fd;
+};
+
+int helper_pause = 0;
+
+static void helper_hup(int sig)
+{
+}
+
+static int helper_child(void *arg)
+{
+	struct helper_data *data = arg;
+	char **argv = data->argv;
+
+	if(helper_pause){
+		signal(SIGHUP, helper_hup);
+		pause();
+	}
+	if(data->pre_exec != NULL)
+		(*data->pre_exec)(data->pre_data);
+	execvp(argv[0], argv);
+	printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
+	write(data->fd, &errno, sizeof(errno));
+	_exit(1);
+}
+
+int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
+	       unsigned long *stack_out)
+{
+	struct helper_data data;
+	unsigned long stack, sp;
+	int pid, fds[2], err, n;
+
+	if((stack_out != NULL) && (*stack_out != 0))
+		stack = *stack_out;
+	else stack = alloc_stack(0, um_in_interrupt());
+	if(stack == 0) return(-ENOMEM);
+
+	err = os_pipe(fds, 1, 0);
+	if(err){
+		printk("run_helper : pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+	if(fcntl(fds[1], F_SETFD, 1) != 0){
+		printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n",
+		       errno);
+		return(-errno);
+	}
+
+	sp = stack + page_size() - sizeof(void *);
+	data.pre_exec = pre_exec;
+	data.pre_data = pre_data;
+	data.argv = argv;
+	data.fd = fds[1];
+	pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
+	if(pid < 0){
+		printk("run_helper : clone failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	close(fds[1]);
+	n = read(fds[0], &err, sizeof(err));
+	if(n < 0){
+		printk("run_helper : read on pipe failed, errno = %d\n", 
+		       errno);
+		return(-errno);
+	}
+	else if(n != 0)	pid = -err;
+
+	if(stack_out == NULL) free_stack(stack, 0);
+        else *stack_out = stack;
+	return(pid);
+}
+
+int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, 
+		      unsigned long *stack_out, int stack_order)
+{
+	unsigned long stack, sp;
+	int pid, status;
+
+	stack = alloc_stack(stack_order, um_in_interrupt());
+	if(stack == 0) return(-ENOMEM);
+
+	sp = stack + (page_size() << stack_order) - sizeof(void *);
+	pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
+	if(pid < 0){
+		printk("run_helper_thread : clone failed, errno = %d\n", 
+		       errno);
+		return(-errno);
+	}
+	if(stack_out == NULL){
+		pid = waitpid(pid, &status, 0);
+		if(pid < 0)
+			printk("run_helper_thread - wait failed, errno = %d\n",
+			       pid);
+		if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+			printk("run_helper_thread - thread returned status "
+			       "0x%x\n", status);
+		free_stack(stack, stack_order);
+	}
+        else *stack_out = stack;
+	return(pid);
+}
+
+int helper_wait(int pid, int block)
+{
+	int ret;
+
+	ret = waitpid(pid, NULL, WNOHANG);
+	if(ret < 0){
+		printk("helper_wait : waitpid failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	return(ret);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/init_task.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,70 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/mm.h"
+#include "linux/sched.h"
+#include "linux/init_task.h"
+#include "linux/version.h"
+#include "asm/uaccess.h"
+#include "asm/pgtable.h"
+#include "user_util.h"
+#include "mem_user.h"
+
+static struct fs_struct init_fs = INIT_FS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+
+struct task_struct init_task = INIT_TASK(init_task);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+
+union thread_union init_thread_union 
+__attribute__((__section__(".data.init_task"))) = 
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct *alloc_task_struct(void){
+	struct task_struct *task;
+
+	task = (struct task_struct *) __get_free_pages(GFP_KERNEL, 2);
+	if(task == NULL) return(NULL);
+	return(task);
+}
+
+void unprotect_stack(unsigned long stack)
+{
+	protect(stack, 4 * PAGE_SIZE, 1, 1, 0, 1);
+}
+
+void free_task_struct(struct task_struct *task)
+{
+	/* free_pages decrements the page counter and only actually frees
+	 * the pages if they are now not accessed by anything.
+	 */
+	free_pages((unsigned long) task, 2);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/initrd_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/blk.h"
+#include "asm/types.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+
+static char *initrd __initdata = NULL;
+
+static int __init read_initrd(void)
+{
+	void *area;
+	long long size;
+	int err;
+
+	if(initrd == NULL) return 0;
+	err = os_file_size(initrd, &size);
+	if(err) return 0;
+	area = alloc_bootmem(size);
+	if(area == NULL) return 0;
+	if(load_initrd(initrd, area, size) == -1) return 0;
+	initrd_start = (unsigned long) area;
+	initrd_end = initrd_start + size;
+	return 0;
+}
+
+__uml_postsetup(read_initrd);
+
+static int __init uml_initrd_setup(char *line, int *add)
+{
+	initrd = line;
+	return 0;
+}
+
+__uml_setup("initrd=", uml_initrd_setup, 
+"initrd=<initrd image>\n"
+"    This is used to boot UML from an initrd image.  The argument is the\n"
+"    name of the file containing the image.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/initrd_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "initrd.h"
+#include "os.h"
+
+int load_initrd(char *filename, void *buf, int size)
+{
+	int fd, n;
+
+	if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){
+		printk("Opening '%s' failed - errno = %d\n", filename, errno);
+		return(-1);
+	}
+	if((n = read(fd, buf, size)) != size){
+		printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
+		       size, filename, n, errno);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/irq.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,817 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
+ *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/irq.h"
+#include "linux/kernel_stat.h"
+#include "linux/interrupt.h"
+#include "linux/random.h"
+#include "linux/slab.h"
+#include "linux/file.h"
+#include "linux/proc_fs.h"
+#include "linux/init.h"
+#include "linux/seq_file.h"
+#include "asm/irq.h"
+#include "asm/hw_irq.h"
+#include "asm/hardirq.h"
+#include "asm/atomic.h"
+#include "asm/signal.h"
+#include "asm/system.h"
+#include "asm/errno.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+
+static void register_irq_proc (unsigned int irq);
+
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+        { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
+ */
+#if CONFIG_X86
+	printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
+#ifdef CONFIG_X86_LOCAL_APIC
+	/*
+	 * Currently unexpected vectors happen only on SMP and APIC.
+	 * We _must_ ack these because every local APIC has only N
+	 * irq slots per priority level, and a 'hanging, unacked' IRQ
+	 * holds up an irq slot - in excessive cases (when multiple
+	 * unexpected vectors occur) that might lock up the APIC
+	 * completely.
+	 */
+	ack_APIC_irq();
+#endif
+#endif
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+volatile unsigned long irq_err_count;
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int get_irq_list(char *buf)
+{
+	int i, j;
+	struct irqaction * action;
+	char *p = buf;
+
+	p += sprintf(p, "           ");
+	for (j=0; j<num_online_cpus(); j++)
+		p += sprintf(p, "CPU%d       ",j);
+	*p++ = '\n';
+
+	for (i = 0 ; i < NR_IRQS ; i++) {
+		action = irq_desc[i].action;
+		if (!action) 
+			continue;
+		p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j = 0; j < num_online_cpus(); j++)
+			p += sprintf(p, "%10u ",
+				kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+		p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+		p += sprintf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			p += sprintf(p, ", %s", action->name);
+		*p++ = '\n';
+	}
+	p += sprintf(p, "\n");
+#ifdef notdef
+#if CONFIG_SMP
+	p += sprintf(p, "LOC: ");
+	for (j = 0; j < num_online_cpus(); j++)
+		p += sprintf(p, "%10u ",
+			apic_timer_irqs[cpu_logical_map(j)]);
+	p += sprintf(p, "\n");
+#endif
+#endif
+	p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+	return p - buf;
+}
+
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	return(0);
+}
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, 
+		     struct irqaction * action)
+{
+	int status = 1;	/* Force the "do bottom halves" bit */
+
+	if (!(action->flags & SA_INTERRUPT))
+		local_irq_enable();
+
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+
+	local_irq_disable();
+
+	return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
+ 
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void inline disable_irq_nosync(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		desc->status |= IRQ_DISABLED;
+		desc->handler->disable(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+#if CONFIG_SMP
+inline void synchronize_irq(unsigned int irq)
+{
+	/* is there anything to synchronize with? */
+	if (!irq_desc[irq].action)
+		return;
+ 
+	while (irq_desc[irq].status & IRQ_INPROGRESS)
+		cpu_relax();
+}
+#endif
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. That is for two disables you need two enables. This
+ *	function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
+ 
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	synchronize_irq(irq);
+}
+
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line
+ *	providing no disable_irq calls are now in effect.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void enable_irq(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
+	case 1: {
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
+		}
+		desc->handler->enable(irq);
+		/* fall-through */
+	}
+	default:
+		desc->depth--;
+		break;
+	case 0:
+		printk(KERN_ERR "enable_irq() unbalanced from %p\n",
+		       __builtin_return_address(0));
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
+{	
+	/* 
+	 * 0 return value means that this irq is already being
+	 * handled by some other CPU. (or is disabled)
+	 */
+	int cpu = smp_processor_id();
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
+	unsigned int status;
+
+	irq_enter();
+	kstat.irqs[cpu][irq]++;
+	spin_lock(&desc->lock);
+	desc->handler->ack(irq);
+	/*
+	   REPLAY is when Linux resends an IRQ that was dropped earlier
+	   WAITING is used by probe to mark irqs that are being tested
+	   */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+		action = desc->action;
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		status |= IRQ_INPROGRESS; /* we are handling it */
+	}
+	desc->status = status;
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	   Since we set PENDING, if another processor is handling
+	   a different instance of this same irq, the other processor
+	   will take care of it.
+	 */
+	if (!action)
+		goto out;
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in do_IRQ
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		spin_unlock(&desc->lock);
+		handle_IRQ_event(irq, (struct pt_regs *) regs, action);
+		spin_lock(&desc->lock);
+		
+		if (!(desc->status & IRQ_PENDING))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+	desc->status &= ~IRQ_INPROGRESS;
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	desc->handler->end(irq);
+	spin_unlock(&desc->lock);
+
+	irq_exit();
+
+	return 1;
+}
+
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board 
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+ 
+int request_irq(unsigned int irq,
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{
+	int retval;
+	struct irqaction * action;
+
+#if 1
+	/*
+	 * Sanity-check: shared interrupts should REALLY pass in
+	 * a real dev-ID, otherwise we'll have trouble later trying
+	 * to figure out which interrupt is which (messes up the
+	 * interrupt freeing logic etc).
+	 */
+	if (irqflags & SA_SHIRQ) {
+		if (!dev_id)
+			printk(KERN_ERR "Bad boy: %s (at 0x%x) called us "
+			       "without a dev_id!\n", devname, (&irq)[-1]);
+	}
+#endif
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+
+	action = (struct irqaction *)
+			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+	return retval;
+}
+
+int um_request_irq(unsigned int irq, int fd, int type,
+		   void (*handler)(int, void *, struct pt_regs *),
+		   unsigned long irqflags, const char * devname,
+		   void *dev_id)
+{
+	int retval;
+
+	retval = request_irq(irq, handler, irqflags, devname, dev_id);
+	if(retval) return(retval);
+	return(activate_fd(irq, fd, type, dev_id));
+}
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	unsigned long flags;
+	struct irqaction *old, **p;
+	irq_desc_t *desc = irq_desc + irq;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&desc->lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		desc->depth = 0;
+		desc->status &= ~IRQ_DISABLED;
+		desc->handler->startup(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	register_irq_proc(irq);
+	return 0;
+}
+
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function. The function
+ *	does not return until any executing interrupts for this IRQ
+ *	have completed.
+ *
+ *	This function may be called from interrupt context. 
+ *
+ *	Bugs: Attempting to free an irq in a handler for the same irq hangs
+ *	      the machine.
+ */
+ 
+void free_irq(unsigned int irq, void *dev_id)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS)
+		return;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
+			}
+			free_irq_by_irq_and_dev(irq, dev_id);
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+			/* Wait to make sure it's not being used on another CPU */
+			synchronize_irq(irq);
+			kfree(action);
+			return;
+		}
+		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return;
+	}
+}
+
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
+{
+	unsigned char hexnum [HEX_DIGITS];
+	unsigned long value;
+	int i;
+
+	if (!count)
+		return -EINVAL;
+	if (count > HEX_DIGITS)
+		count = HEX_DIGITS;
+	if (copy_from_user(hexnum, buffer, count))
+		return -EFAULT;
+
+	/*
+	 * Parse the first 8 characters as a hex string, any non-hex char
+	 * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+	 */
+	value = 0;
+
+	for (i = 0; i < count; i++) {
+		unsigned int c = hexnum[i];
+
+		switch (c) {
+			case '0' ... '9': c -= '0'; break;
+			case 'a' ... 'f': c -= 'a'-10; break;
+			case 'A' ... 'F': c -= 'A'-10; break;
+		default:
+			goto out;
+		}
+		value = (value << 4) | c;
+	}
+out:
+	*ret = value;
+	return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	int irq = (long) data, full_count = count, err;
+	unsigned long new_value;
+
+	if (!irq_desc[irq].handler->set_affinity)
+		return -EIO;
+
+	err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+	/*
+	 * Do not allow disabling IRQs completely - it's a too easy
+	 * way to make the system unusable accidentally :-) At least
+	 * one online CPU still has to be targeted.
+	 */
+	if (!(new_value & cpu_online_map))
+		return -EINVAL;
+#endif
+
+	irq_affinity[irq] = new_value;
+	irq_desc[irq].handler->set_affinity(irq, new_value);
+
+	return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	unsigned long *mask = (unsigned long *) data;
+	if (count < HEX_DIGITS+1)
+		return -EINVAL;
+	return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+					unsigned long count, void *data)
+{
+	unsigned long *mask = (unsigned long *) data, full_count = count, err;
+	unsigned long new_value;
+
+	err = parse_hex_value(buffer, count, &new_value);
+	if (err)
+		return err;
+
+	*mask = new_value;
+	return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+	struct proc_dir_entry *entry;
+	char name [MAX_NAMELEN];
+
+	if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
+	    irq_dir[irq])
+		return;
+
+	memset(name, 0, MAX_NAMELEN);
+	sprintf(name, "%d", irq);
+
+	/* create /proc/irq/1234 */
+	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+	/* create /proc/irq/1234/smp_affinity */
+	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+	entry->nlink = 1;
+	entry->data = (void *)(long)irq;
+	entry->read_proc = irq_affinity_read_proc;
+	entry->write_proc = irq_affinity_write_proc;
+
+	smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void __init init_irq_proc (void)
+{
+	struct proc_dir_entry *entry;
+	int i;
+
+	/* create /proc/irq */
+	root_irq_dir = proc_mkdir("irq", 0);
+
+	/* create /proc/irq/prof_cpu_mask */
+	entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir);
+
+	entry->nlink = 1;
+	entry->data = (void *)&prof_cpu_mask;
+	entry->read_proc = prof_cpu_mask_read_proc;
+	entry->write_proc = prof_cpu_mask_write_proc;
+
+	/*
+	 * Create entries for all existing IRQs.
+	 */
+	for (i = 0; i < NR_IRQS; i++)
+		register_irq_proc(i);
+}
+
+unsigned long probe_irq_on(void)
+{
+	return(0);
+}
+
+int probe_irq_off(unsigned long val)
+{
+	return(0);
+}
+
+static unsigned int startup_SIGIO_irq(unsigned int irq)
+{
+	return(0);
+}
+
+static void shutdown_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void enable_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void disable_SIGIO_irq(unsigned int irq)
+{
+}
+
+static void mask_and_ack_SIGIO(unsigned int irq)
+{
+}
+
+static void end_SIGIO_irq(unsigned int irq)
+{
+}
+
+static unsigned int startup_SIGVTALRM_irq(unsigned int irq)
+{
+	return(0);
+}
+
+static void shutdown_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void enable_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void disable_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static void mask_and_ack_SIGVTALRM(unsigned int irq)
+{
+}
+
+static void end_SIGVTALRM_irq(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type SIGIO_irq_type = {
+	"SIGIO",
+	startup_SIGIO_irq,
+	shutdown_SIGIO_irq,
+	enable_SIGIO_irq,
+	disable_SIGIO_irq,
+	mask_and_ack_SIGIO,
+	end_SIGIO_irq,
+	NULL
+};
+
+static struct hw_interrupt_type SIGVTALRM_irq_type = {
+	"SIGVTALRM",
+	startup_SIGVTALRM_irq,
+	shutdown_SIGVTALRM_irq,
+	enable_SIGVTALRM_irq,
+	disable_SIGVTALRM_irq,
+	mask_and_ack_SIGVTALRM,
+	end_SIGVTALRM_irq,
+	NULL
+};
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
+	irq_desc[TIMER_IRQ].action = 0;
+	irq_desc[TIMER_IRQ].depth = 1;
+	irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type;
+	enable_irq(TIMER_IRQ);
+	for(i=1;i<NR_IRQS;i++){
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+		irq_desc[i].handler = &SIGIO_irq_type;
+		enable_irq(i);
+	}
+	init_irq_signals(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/irq_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,357 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_user.h"
+#include "sigio.h"
+#include "irq_user.h"
+#include "os.h"
+
+struct irq_fd {
+	struct irq_fd *next;
+	void *id;
+	int fd;
+	int type;
+	int irq;
+	int pid;
+	int events;
+	int current_events;
+	int freed;
+};
+
+static struct irq_fd *active_fds = NULL;
+static struct irq_fd **last_irq_ptr = &active_fds;
+
+static struct pollfd *pollfds = NULL;
+static int pollfds_num = 0;
+static int pollfds_size = 0;
+
+extern int io_count, intr_count;
+
+void sigio_handler(int sig, struct uml_pt_regs *regs)
+{
+	struct irq_fd *irq_fd, *next;
+	int i, n;
+
+	if(smp_sigio_handler()) return;
+	while(1){
+		if((n = poll(pollfds, pollfds_num, 0)) < 0){
+			if(errno == EINTR) continue;
+			printk("sigio_handler : poll returned %d, "
+			       "errno = %d\n", n, errno);
+			break;
+		}
+		if(n == 0) break;
+
+		irq_fd = active_fds;
+		for(i = 0; i < pollfds_num; i++){
+			if(pollfds[i].revents != 0){
+				irq_fd->current_events = pollfds[i].revents;
+				pollfds[i].events = 0;
+			}
+			irq_fd = irq_fd->next;
+		}
+
+		for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
+			next = irq_fd->next;
+			if(irq_fd->current_events != 0){
+				irq_fd->current_events = 0;
+				do_IRQ(irq_fd->irq, regs);
+
+				/* This is here because the next irq may be
+				 * freed in the handler.  If a console goes
+				 * away, both the read and write irqs will be
+				 * freed.  After do_IRQ, ->next will point to
+				 * a good IRQ.
+				 * Irqs can't be freed inside their handlers,
+				 * so the next best thing is to have them
+				 * marked as needing freeing, so that they
+				 * can be freed here.
+				 */
+				next = irq_fd->next;
+				if(irq_fd->freed)
+					free_irq(irq_fd->irq, irq_fd->id);
+			}
+		}
+	}
+}
+
+int activate_ipi(int fd, int pid)
+{
+	return(os_set_fd_async(fd, pid));
+}
+
+static void maybe_sigio_broken(int fd, int type)
+{
+	if(isatty(fd)){
+		if((type == IRQ_WRITE) && !pty_output_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 0);
+		}
+		else if((type == IRQ_READ) && !pty_close_sigio){
+			write_sigio_workaround();
+			add_sigio_fd(fd, 1);			
+		}
+	}
+}
+
+int activate_fd(int irq, int fd, int type, void *dev_id)
+{
+	struct irq_fd *new_fd;
+	int pid, retval, events, err;
+
+	for(new_fd = active_fds;new_fd;new_fd = new_fd->next){
+		if((new_fd->fd == fd) && (new_fd->type == type)){
+			printk("Registering fd %d twice\n", fd);
+			printk("Irqs : %d, %d\n", new_fd->irq, irq);
+			printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id);
+			return(-EIO);
+		}
+	}
+	pid = cpu_tasks[0].pid;
+	if((retval = os_set_fd_async(fd, pid)) != 0)
+		return(retval);
+	new_fd = um_kmalloc(sizeof(*new_fd));
+	err = -ENOMEM;
+	if(new_fd == NULL) return(err);
+	pollfds_num++;
+	if(pollfds_num > pollfds_size){
+		struct pollfd *tmp_pfd;
+
+		tmp_pfd = um_kmalloc(pollfds_num * sizeof(pollfds[0]));
+		if(tmp_pfd == NULL){
+			pollfds_num--;
+			goto out_irq;
+		}
+		if(pollfds != NULL){
+			memcpy(tmp_pfd, pollfds,
+			       sizeof(pollfds[0]) * pollfds_size);
+			kfree(pollfds);
+		}
+		pollfds = tmp_pfd;
+		pollfds_size = pollfds_num;
+	}
+
+	if(type == IRQ_READ) events = POLLIN | POLLPRI;
+	else events = POLLOUT;
+	*new_fd = ((struct irq_fd) { next : 		NULL,
+				     id :		dev_id,
+				     fd :		fd,
+				     type :		type,
+				     irq :		irq,
+				     pid : 		pid,
+				     events :		events,
+				     current_events: 	0,
+				     freed :		0  } );
+
+	*last_irq_ptr = new_fd;
+	last_irq_ptr = &new_fd->next;
+
+	if(type == IRQ_WRITE) events = 0;
+
+	pollfds[pollfds_num - 1] = ((struct pollfd) { fd :	fd,
+						      events :	events,
+						      revents :	0 });
+
+	maybe_sigio_broken(fd, type);
+
+	return(0);
+
+ out_irq:
+	kfree(new_fd);
+	return(err);
+}
+
+static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
+{
+	struct irq_fd **prev;
+	int i = 0;
+
+	prev = &active_fds;
+	while(*prev != NULL){
+		if((*test)(*prev, arg)){
+			struct irq_fd *old_fd = *prev;
+			if(pollfds[i].fd != (*prev)->fd){
+				printk("free_irq_by_cb - mismatch between "
+				       "active_fds and pollfds, fd %d vs %d\n",
+				       (*prev)->fd, pollfds[i].fd);
+				return;
+			}
+			memcpy(&pollfds[i], &pollfds[i + 1],
+			       (pollfds_num - i - 1) * sizeof(pollfds[0]));
+			pollfds_num--;
+			if(last_irq_ptr == &old_fd->next) 
+				last_irq_ptr = prev;
+			*prev = (*prev)->next;
+			if(old_fd->type == IRQ_WRITE) 
+				ignore_sigio_fd(old_fd->fd);
+			kfree(old_fd);
+			continue;
+		}
+		prev = &(*prev)->next;
+		i++;
+	}
+}
+
+struct irq_and_dev {
+	int irq;
+	void *dev;
+};
+
+static int same_irq_and_dev(struct irq_fd *irq, void *d)
+{
+	struct irq_and_dev *data = d;
+
+	return((irq->irq == data->irq) && (irq->id == data->dev));
+}
+
+void free_irq_by_irq_and_dev(int irq, void *dev)
+{
+	struct irq_and_dev data = ((struct irq_and_dev) { irq : irq,
+							  dev : dev });
+
+	free_irq_by_cb(same_irq_and_dev, &data);
+}
+
+static int same_fd(struct irq_fd *irq, void *fd)
+{
+	return(irq->fd == *((int *) fd));
+}
+
+void free_irq_by_fd(int fd)
+{
+	free_irq_by_cb(same_fd, &fd);
+}
+
+static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
+{
+	struct irq_fd *irq;
+	int i = 0;
+	
+	for(irq=active_fds; irq != NULL; irq = irq->next){
+		if((irq->fd == fd) && (irq->irq == irqnum)) break;
+		i++;
+	}
+	if(irq == NULL){
+		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
+		return(NULL);
+	}
+	if(pollfds[i].fd != fd){
+		printk("find_irq_by_fd - mismatch between active_fds and "
+		       "pollfds, fd %d vs %d, need %d\n", irq->fd, 
+		       pollfds[i].fd, fd);
+		return(NULL);
+	}
+	*index_out = i;
+	return(irq);
+}
+
+void free_irq_later(int irq, void *dev_id)
+{
+	struct irq_fd *irq_fd;
+
+	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+		if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
+			break;
+	}
+	if(irq_fd == NULL){
+		printk("free_irq_later found no irq, irq = %d, "
+		       "dev_id = 0x%p\n", irq, dev_id);
+		return;
+	}
+	irq_fd->freed = 1;
+}
+
+void reactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	int i;
+
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL) return;
+	pollfds[i].events = irq->events;
+	maybe_sigio_broken(fd, irq->type);
+}
+
+void deactivate_fd(int fd, int irqnum)
+{
+	struct irq_fd *irq;
+	int i;
+
+	irq = find_irq_by_fd(fd, irqnum, &i);
+	if(irq == NULL) return;
+	pollfds[i].events = 0;
+}
+
+void forward_ipi(int fd, int pid)
+{
+	if(fcntl(fd, F_SETOWN, pid) < 0){
+		int save_errno = errno;
+		if(fcntl(fd, F_GETOWN, 0) != pid){
+			printk("forward_ipi: F_SETOWN failed, fd = %d, "
+			       "me = %d, target = %d, errno = %d\n", fd, 
+			       os_getpid(), pid, save_errno);
+		}
+	}
+}
+
+void forward_interrupts(int pid)
+{
+	struct irq_fd *irq;
+
+	for(irq=active_fds;irq != NULL;irq = irq->next){
+		if(fcntl(irq->fd, F_SETOWN, pid) < 0){
+			int save_errno = errno;
+			if(fcntl(irq->fd, F_GETOWN, 0) != pid){
+				/* XXX Just remove the irq rather than
+				 * print out an infinite stream of these
+				 */
+				printk("Failed to forward %d to pid %d, "
+				       "errno = %d\n", irq->fd, pid, 
+				       save_errno);
+			}
+		}
+		irq->pid = pid;
+	}
+}
+
+void init_irq_signals(int on_sigstack)
+{
+	__sighandler_t h;
+	int flags;
+
+	flags = on_sigstack ? SA_ONSTACK : 0;
+	if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
+	else h = boot_timer_handler;
+
+	set_handler(SIGVTALRM, h, flags | SA_NODEFER | SA_RESTART, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	signal(SIGWINCH, SIG_IGN);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/ksyms.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,59 @@
+#include "linux/module.h"
+#include "linux/string.h"
+#include "asm/current.h"
+#include "asm/delay.h"
+#include "asm/processor.h"
+#include "asm/unistd.h"
+#include "asm/pgalloc.h"
+#include "asm/page.h"
+#include "asm/tlbflush.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "helper.h"
+
+EXPORT_SYMBOL(stop);
+EXPORT_SYMBOL(uml_physmem);
+EXPORT_SYMBOL(set_signals);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(__const_udelay);
+EXPORT_SYMBOL(sys_waitpid);
+EXPORT_SYMBOL(task_size);
+EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_strncpy_from_user);
+EXPORT_SYMBOL(__do_strnlen_user); 
+EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(__do_clear_user);
+EXPORT_SYMBOL(honeypot);
+EXPORT_SYMBOL(host_task_size);
+EXPORT_SYMBOL(arch_validate);
+
+EXPORT_SYMBOL(region_pa);
+EXPORT_SYMBOL(region_va);
+EXPORT_SYMBOL(phys_mem_map);
+EXPORT_SYMBOL(page_mem_map);
+EXPORT_SYMBOL(get_signals);
+EXPORT_SYMBOL(page_to_phys);
+EXPORT_SYMBOL(phys_to_page);
+
+EXPORT_SYMBOL(os_open_file);
+EXPORT_SYMBOL(os_read_file);
+EXPORT_SYMBOL(os_write_file);
+EXPORT_SYMBOL(os_seek_file);
+EXPORT_SYMBOL(os_pipe);
+EXPORT_SYMBOL(helper_wait);
+EXPORT_SYMBOL(os_shutdown_socket);
+EXPORT_SYMBOL(os_connect_socket);
+EXPORT_SYMBOL(run_helper);
+EXPORT_SYMBOL(tracing_pid);
+EXPORT_SYMBOL(start_thread);
+EXPORT_SYMBOL(dump_thread);
+
+/* This is here because UML expands open to sys_open, not to a system
+ * call instruction.
+ */
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_wait4);
+
diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/mem.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,617 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/types.h"
+#include "linux/mm.h"
+#include "linux/fs.h"
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/swap.h"
+#include "linux/slab.h"
+#include "linux/vmalloc.h"
+#include "linux/highmem.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/bitops.h"
+#include "asm/uaccess.h"
+#include "asm/tlb.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "mem.h"
+#include "kern.h"
+#include "init.h"
+
+unsigned long high_physmem;
+
+unsigned long low_physmem;
+
+unsigned long vm_start;
+
+unsigned long vm_end;
+
+pgd_t swapper_pg_dir[1024];
+
+unsigned long *empty_zero_page = NULL;
+
+unsigned long *empty_bad_page = NULL;
+
+const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
+
+extern char __init_begin, __init_end;
+extern long physmem_size;
+
+mmu_gather_t mmu_gathers[NR_CPUS];
+
+int kmalloc_ok = 0;
+
+#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0))
+struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
+#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
+
+static unsigned long brk_end;
+
+static void map_cb(void *unused)
+{
+	map(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+}
+
+void unmap_physmem(void)
+{
+	unmap((void *) brk_end, uml_reserved - brk_end);
+}
+
+extern char __binary_start;
+
+void mem_init(void)
+{
+	unsigned long start;
+
+	max_mapnr = num_physpages = max_low_pfn;
+
+        /* clear the zero-page */
+        memset((void *) empty_zero_page, 0, PAGE_SIZE);
+
+	/* Map in the area just after the brk now that kmalloc is about
+	 * to be turned on.
+	 */
+	brk_end = (unsigned long) ROUND_UP(sbrk(0));
+	map_cb(NULL);
+	tracing_cb(map_cb, NULL);
+	free_bootmem(__pa(brk_end), uml_reserved - brk_end);
+	uml_reserved = brk_end;
+
+	/* Fill in any hole at the start of the binary */
+	start = (unsigned long) &__binary_start;
+	if(uml_physmem != start){
+		map(uml_physmem, __pa(uml_physmem), start - uml_physmem,
+		    1, 1, 0);
+	}
+
+	/* this will put all low memory onto the freelists */
+	totalram_pages += free_all_bootmem();
+	printk(KERN_INFO "Memory: %luk available\n", 
+	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
+	kmalloc_ok = 1;
+}
+
+void paging_init(void)
+{
+	struct mem_region *region;
+	unsigned long zones_size[MAX_NR_ZONES], start, end;
+	int i, index;
+
+	empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+	empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+	for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) 
+		zones_size[i] = 0;
+	zones_size[0] = (high_physmem >> PAGE_SHIFT) - 
+		(uml_physmem >> PAGE_SHIFT);
+	free_area_init(zones_size);
+	start = phys_region_index(__pa(uml_physmem));
+	end = phys_region_index(__pa(high_physmem - 1));
+	for(i = start; i <= end; i++){
+		region = regions[i];
+		index = (region->start - uml_physmem) / PAGE_SIZE;
+		region->mem_map = &mem_map[index];
+		if(i > start) free_bootmem(__pa(region->start), region->len);
+	}
+}
+
+pte_t __bad_page(void)
+{
+	clear_page(empty_bad_page);
+        return pte_mkdirty(mk_pte((struct page *) empty_bad_page, 
+				  PAGE_SHARED));
+}
+
+/* This can't do anything because nothing in the kernel image can be freed
+ * since it's not in kernel physical memory.
+ */
+
+void free_initmem(void)
+{
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+	if (start < end)
+		printk ("Freeing initrd memory: %ldk freed\n", 
+			(end - start) >> 10);
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(start));
+		set_page_count(virt_to_page(start), 1);
+		free_page(start);
+		totalram_pages++;
+	}
+}
+	
+#endif
+
+void show_mem(void)
+{
+        int pfn, total = 0, reserved = 0;
+        int shared = 0, cached = 0;
+        int highmem = 0;
+	struct page *page;
+
+        printk("Mem-info:\n");
+        show_free_areas();
+        printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+        pfn = max_mapnr;
+        while(pfn-- > 0) {
+		page = pfn_to_page(pfn);
+                total++;
+                if(PageHighMem(page))
+                        highmem++;
+                if(PageReserved(page))
+                        reserved++;
+                else if(PageSwapCache(page))
+                        cached++;
+                else if(page_count(page))
+                        shared += page_count(page) - 1;
+        }
+        printk("%d pages of RAM\n", total);
+        printk("%d pages of HIGHMEM\n", highmem);
+        printk("%d reserved pages\n", reserved);
+        printk("%d pages shared\n", shared);
+        printk("%d pages swap cached\n", cached);
+}
+
+unsigned long kmem_top = 0;
+
+unsigned long get_kmem_end(void)
+{
+	if(kmem_top == 0) kmem_top = host_task_size - ABOVE_KMEM;
+	return(kmem_top);
+}
+
+void set_kmem_end(unsigned long new)
+{
+	kmem_top = new;
+}
+
+static int __init uml_mem_setup(char *line, int *add)
+{
+	char *retptr;
+	physmem_size = memparse(line,&retptr);
+	return 0;
+}
+__uml_setup("mem=", uml_mem_setup,
+"mem=<Amount of desired ram>\n"
+"    This controls how much \"physical\" memory the kernel allocates\n"
+"    for the system. The size is specified as a number followed by\n"
+"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+"    This is not related to the amount of memory in the physical\n"
+"    machine. It can be more, and the excess, if it's ever used, will\n"
+"    just be swapped out.\n        Example: mem=64M\n\n"
+);
+
+struct page *arch_validate(struct page *page, int mask, int order)
+{
+	unsigned long addr, zero = 0;
+	int i;
+
+ again:
+	if(page == NULL) return(page);
+	addr = (unsigned long) page_address(page);
+	for(i = 0; i < (1 << order); i++){
+		current->thread.fault_addr = (void *) addr;
+		if(__do_copy_to_user((void *) addr, &zero, 
+				     sizeof(zero),
+				     &current->thread.fault_addr,
+				     &current->thread.fault_catcher)){
+			if(!(mask & __GFP_WAIT)) return(NULL);
+			else break;
+		}
+		addr += PAGE_SIZE;
+	}
+	if(i == (1 << order)) return(page);
+	page = _alloc_pages(mask, order);
+	goto again;
+}
+
+static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);
+
+static struct vm_reserved head = {
+	list :		LIST_HEAD_INIT(head.list),
+	start :		0,
+	end :		0xffffffff
+};
+
+static struct vm_reserved tail = {
+	list :		LIST_HEAD_INIT(tail.list),
+	start :		0,
+	end :		0xffffffff
+};
+
+void set_usable_vm(unsigned long start, unsigned long end)
+{
+	list_add(&head.list, &vm_reserved);
+	list_add(&tail.list, &head.list);
+	head.end = start;
+	tail.start = end;
+}
+
+int reserve_vm(unsigned long start, unsigned long end, void *e)
+	       
+{
+	struct vm_reserved *entry = e, *reserved, *prev;
+	struct list_head *ele;
+
+	list_for_each(ele, &vm_reserved){
+		reserved = list_entry(ele, struct vm_reserved, list);
+		if(reserved->start >= end) goto found;
+	}
+	panic("Reserved vm out of range");
+ found:
+	prev = list_entry(ele->prev, struct vm_reserved, list);
+	if(prev->end > start)
+		panic("Can't reserve vm");
+	if(entry == NULL)
+		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if(entry == NULL){
+		printk("reserve_vm : Failed to allocate entry\n");
+		return(-ENOMEM);
+	}
+	*entry = ((struct vm_reserved) 
+		{ list :	LIST_HEAD_INIT(entry->list),
+		  start :	start,
+		  end :		end });
+	list_add(&entry->list, &prev->list);
+	return(0);
+}
+
+unsigned long get_vm(unsigned long len)
+{
+	struct vm_reserved *this, *next;
+	struct list_head *ele;
+	unsigned long start;
+	int err;
+	
+	list_for_each(ele, &vm_reserved){
+		this = list_entry(ele, struct vm_reserved, list);
+		next = list_entry(ele->next, struct vm_reserved, list);
+		if((this->start < next->start) && 
+		   (this->end + len + PAGE_SIZE <= next->start))
+			goto found;
+	}
+	return(0);
+ found:
+	start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE;
+	err = reserve_vm(start, start + len, NULL);
+	if(err) return(0);
+	return(start);
+}
+
+int nregions(void)
+{
+	return(NREGIONS);
+}
+
+int init_maps(struct mem_region *region)
+{
+	struct page *p, *map;
+	int i, n;
+
+	if(region == &physmem_region){
+		region->mem_map = mem_map;
+		return(0);
+	}
+	else if(region->mem_map != NULL) return(0);
+
+	n = region->len >> PAGE_SHIFT;
+	map = kmalloc(n * sizeof(struct page), GFP_KERNEL);
+	if(map == NULL) map = vmalloc(n * sizeof(struct page));
+	if(map == NULL)
+		return(-ENOMEM);
+	for(i = 0; i < n; i++){
+		p = &map[i];
+		set_page_count(p, 0);
+		SetPageReserved(p);
+		INIT_LIST_HEAD(&p->list);
+	}
+	region->mem_map = map;
+	return(0);
+}
+
+void setup_range(int fd, char *driver, unsigned long start, 
+		 unsigned long len, struct mem_region *region, void *reserved)
+{
+	int i, incr;
+
+	i = 0;
+	do {
+		for(; i < NREGIONS; i++){
+			if(regions[i] == NULL) break;		
+		}
+		if(i == NREGIONS){
+			printk("setup_range : no free regions\n");
+			return;
+		}
+		setup_one_range(i, fd, driver, start, len, region);
+		region = regions[i];
+		if(setup_region(region, reserved)){
+			kfree(region);
+			regions[i] = NULL;
+			return;
+		}
+		incr = min(len, (unsigned long) REGION_SIZE);
+		start += incr;
+		len -= incr;
+	} while(len > 0);
+}
+
+struct iomem {
+	char *name;
+	int fd;
+	unsigned long size;
+};
+
+struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = 
+					 { name : 	NULL,
+					   fd : 	-1,
+					   size :	0 } };
+
+int num_iomem_regions = 0;
+
+void add_iomem(char *name, int fd, int size)
+{
+	if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
+		return;
+	size = (size + PAGE_SIZE - 1) & PAGE_MASK;
+	iomem_regions[num_iomem_regions++] = 
+		((struct iomem) { name :	name,
+				  fd :		fd,
+				  size :	size } );
+}
+
+int setup_iomem(void)
+{
+	struct iomem *iomem;
+	int i;
+
+	for(i = 0; i < num_iomem_regions; i++){
+		iomem = &iomem_regions[i];
+		setup_range(iomem->fd, iomem->name, -1, iomem->size, NULL, 
+			    NULL);
+	}
+	return(0);
+}
+
+__initcall(setup_iomem);
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+
+static struct mem_region physmem_region;
+static struct vm_reserved physmem_reserved;
+
+void setup_physmem(unsigned long start, unsigned long reserve_end,
+		   unsigned long len)
+{
+	struct mem_region *region = &physmem_region;
+	struct vm_reserved *reserved = &physmem_reserved;
+	unsigned long cur;
+	int do_free = 1, bootmap_size;
+
+	do {
+		cur = min(len, (unsigned long) REGION_SIZE);
+		if(region == NULL) 
+			region = alloc_bootmem_low_pages(sizeof(*region));
+		if(reserved == NULL) 
+			reserved = alloc_bootmem_low_pages(sizeof(*reserved));
+		if((region == NULL) || (reserved == NULL))
+			panic("Couldn't allocate physmem region or vm "
+			      "reservation\n");
+		setup_range(-1, NULL, start, cur, region, reserved);
+
+		if(do_free){
+			unsigned long reserve = reserve_end - start;
+			int pfn = PFN_UP(__pa(reserve_end));
+			int delta = (len - reserve) >> PAGE_SHIFT;
+
+			bootmap_size = init_bootmem(pfn, pfn + delta);
+			free_bootmem(__pa(reserve_end) + bootmap_size,
+				     cur - bootmap_size - reserve);
+			do_free = 0;
+		}
+		start += cur;
+		len -= cur;
+		region = NULL;
+		reserved = NULL;
+	} while(len > 0);
+}
+
+struct mem_region *phys_region(unsigned long phys)
+{
+	unsigned int n = phys_region_index(phys);
+
+	if(regions[n] == NULL) 
+		panic("Physical address in uninitialized region");
+	return(regions[n]);
+}
+
+unsigned long phys_offset(unsigned long phys)
+{
+	return(phys_addr(phys));
+}
+
+struct page *phys_mem_map(unsigned long phys)
+{
+	return((struct page *) phys_region(phys)->mem_map);
+}
+
+struct page *pte_mem_map(pte_t pte)
+{
+	return(phys_mem_map(pte_val(pte)));
+}
+
+struct mem_region *page_region(struct page *page, int *index_out)
+{
+	int i;
+	struct mem_region *region;
+	struct page *map;
+
+	for(i = 0; i < NREGIONS; i++){
+		region = regions[i];
+		if(region == NULL) continue;
+		map = region->mem_map;
+		if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){
+			if(index_out != NULL) *index_out = i;
+			return(region);
+		}
+	}
+	panic("No region found for page");
+	return(NULL);
+}
+
+struct page *page_mem_map(struct page *page)
+{
+	return((struct page *) page_region(page, NULL)->mem_map);
+}
+
+extern unsigned long region_pa(void *virt)
+{
+	struct mem_region *region;
+	unsigned long addr = (unsigned long) virt;
+	int i;
+
+	for(i = 0; i < NREGIONS; i++){
+		region = regions[i];
+		if(region == NULL) continue;
+		if((region->start <= addr) && 
+		   (addr <= region->start + region->len))
+			return(mk_phys(addr - region->start, i));
+	}
+	panic("region_pa : no region for virtual address");
+	return(0);
+}
+
+extern void *region_va(unsigned long phys)
+{
+	return((void *) (phys_region(phys)->start + phys_addr(phys)));
+}
+
+unsigned long page_to_phys(struct page *page)
+{
+	int n;
+	struct mem_region *region = page_region(page, &n);
+	struct page *map = region->mem_map;
+	return(mk_phys((page - map) << PAGE_SHIFT, n));
+}
+
+struct page *phys_to_page(unsigned long phys)
+{
+	struct page *mem_map;
+
+	mem_map = phys_mem_map(phys);
+	return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));
+}
+
+int setup_mem_maps(void)
+{
+	struct mem_region *region;
+	int i;
+
+	for(i = 0; i < NREGIONS; i++){
+		region = regions[i];
+		if((region != NULL) && (region->fd > 0)) init_maps(region);
+	}
+	return(0);
+}
+
+__initcall(setup_mem_maps);
+
+/*
+ * Allocate and free page tables.
+ */
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+
+	if (pgd) {
+		memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+		memcpy(pgd + USER_PTRS_PER_PGD, 
+		       swapper_pg_dir + USER_PTRS_PER_PGD, 
+		       (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+	}
+	return pgd;
+}
+
+void pgd_free(pgd_t *pgd)
+{
+	free_page((unsigned long) pgd);
+}
+
+pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+	int count = 0;
+	pte_t *pte;
+
+   	do {
+		pte = (pte_t *) __get_free_page(GFP_KERNEL);
+		if (pte)
+			clear_page(pte);
+		else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pte && (count++ < 10));
+	return pte;
+}
+
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	int count = 0;
+	struct page *pte;
+   
+   	do {
+		pte = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
+		if (pte)
+			clear_highpage(pte);
+		else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pte && (count++ < 10));
+	return pte;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/mem_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,274 @@
+/*
+ * arch/um/kernel/mem_user.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * user side memory routines for supporting IO memory inside user mode linux
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
+ *
+ *  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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "kern_util.h"
+#include "user.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "init.h"
+#include "os.h"
+
+struct mem_region physmem_region;
+
+struct mem_region *mem_list = &physmem_region;
+
+#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
+
+int create_mem_file(unsigned long len)
+{
+	int fd;
+	char zero;
+
+	fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
+	if (fchmod(fd, 0777) < 0){
+		perror("fchmod");
+		exit(1);
+	}
+	if(os_seek_file(fd, len) < 0){
+		perror("lseek");
+		exit(1);
+	}
+	zero = 0;
+	if(write(fd, &zero, 1) != 1){
+		perror("write");
+		exit(1);
+	}
+	if(fcntl(fd, F_SETFD, 1) != 0)
+		perror("Setting FD_CLOEXEC failed");
+	return(fd);
+}
+
+void setup_one_range(int n, int fd, char *driver, unsigned long start, 
+		     unsigned long len, struct mem_region *region)
+{
+	if(fd == -1)
+		fd = create_mem_file(len);
+	if(region == NULL){
+		region = malloc(sizeof(*region));
+		if(region == NULL){
+			perror("Allocating mem_region");
+			exit(1);
+		}
+	}
+	*region = ((struct mem_region) { driver :	driver, 
+					 start :	start, 
+					 len :		len, 
+					 fd :		fd } );
+	regions[n] = region;
+}
+
+int setup_region(struct mem_region *region, void *entry)
+{
+	void *loc, *start;
+	char *driver;
+	int err, offset;
+
+	if(region->start != -1){
+		err = reserve_vm(region->start, 
+				 region->start + region->len, entry);
+		if(err){
+			printk("setup_region : failed to reserve "
+			       "0x%x - 0x%x for driver '%s'\n",
+			       region->start, 
+			       region->start + region->len,
+			       region->driver);
+			return(-1);
+		}
+	}
+	else region->start = get_vm(region->len);
+	if(region->start == 0){
+		if(region->driver == NULL) driver = "physmem";
+		else driver = region->driver;
+		printk("setup_region : failed to find vm for "
+		       "driver '%s' (length %d)\n", driver, region->len);
+		return(-1);
+	}
+	if(region->start == uml_physmem){
+		start = (void *) uml_reserved;
+		offset = uml_reserved - uml_physmem;
+	}
+	else {
+		start = (void *) region->start;
+		offset = 0;
+	}
+
+	loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, 
+		   MAP_SHARED | MAP_FIXED, region->fd, offset);
+	if(loc != start){
+		perror("Mapping memory");
+		exit(1);
+	}
+	return(0);
+}
+
+static int __init parse_iomem(char *str, int *add)
+{
+	struct stat buf;
+	char *file, *driver;
+	int fd;
+
+	driver = str;
+	file = strchr(str,',');
+	if(file == NULL){
+		printk("parse_iomem : failed to parse iomem\n");
+		return(1);
+	}
+	*file = '\0';
+	file++;
+	fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
+	if(fd < 0){
+		printk("parse_iomem - Couldn't open io file, errno = %d\n", 
+		       errno);
+		return(1);
+	}
+	if(fstat(fd, &buf) < 0) {
+		printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
+		return(1);
+	}
+	add_iomem(driver, fd, buf.st_size);
+	return(0);
+}
+
+__uml_setup("iomem=", parse_iomem,
+"iomem=<name>,<file>\n"
+"    Configure <file> as an IO memory region named <name>.\n\n"
+);
+
+#ifdef notdef
+int logging = 0;
+int logging_fd = -1;
+
+int logging_line = 0;
+char logging_buf[256];
+
+void log(char *fmt, ...)
+{
+	va_list ap;
+	struct timeval tv;
+	struct openflags flags;
+
+	if(logging == 0) return;
+	if(logging_fd < 0){
+		flags = of_create(of_trunc(of_rdrw(OPENFLAGS())));
+		logging_fd = os_open_file("log", flags, 0644);
+	}
+	gettimeofday(&tv, NULL);
+	sprintf(logging_buf, "%d\t %u.%u  ", logging_line++, tv.tv_sec, 
+		tv.tv_usec);
+	va_start(ap, fmt);
+	vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
+	va_end(ap);
+	write(logging_fd, logging_buf, strlen(logging_buf));
+}
+#endif
+
+void map(unsigned long virt, unsigned long phys, unsigned long len, 
+	 int r, int w, int x)
+{
+	struct mem_region *region;
+	void *loc;
+	int prot;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+	region = phys_region(phys);
+
+	loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
+		   region->fd, phys_offset(phys));
+	if(loc != (void *) virt){
+		panic("Error mapping a page - errno = %d", errno);
+	}
+}
+
+int unmap(void *addr, int len)
+{
+	int err;
+
+	err = munmap(addr, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int protect(unsigned long addr, unsigned long len, int r, int w, int x,
+	    int must_succeed)
+{
+	int prot;
+
+	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+		(x ? PROT_EXEC : 0);
+	if(mprotect((void *) addr, len, prot) == -1){
+		if(must_succeed)
+			panic("protect failed, errno = %d", errno);
+		else return(-errno);
+	}
+	return(0);
+}
+
+unsigned long find_iomem(char *driver, unsigned long *len_out)
+{
+	struct mem_region *region;
+	int i, n;
+
+	n = nregions();
+	for(i = 0; i < n; i++){
+		region = regions[i];
+		if(region == NULL) continue;
+		if((region->driver != NULL) &&
+		   !strcmp(region->driver, driver)){
+			*len_out = region->len;
+			return(region->start);
+		}
+	}
+	*len_out = 0;
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/mprot.h b/arch/um/kernel/mprot.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/mprot.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __MPROT_H__
+#define __MPROT_H__
+
+extern void no_access(unsigned long addr, unsigned int len);
+
+#endif
diff -Nru a/arch/um/kernel/process.c b/arch/um/kernel/process.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/process.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,255 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sched.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#ifdef PROFILING
+#include <sys/gmon.h>
+#endif
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "irq_user.h"
+#include "syscall_user.h"
+#include "ptrace_user.h"
+#include "init.h"
+#include "os.h"
+
+void init_new_thread(void *sig_stack, void (*usr1_handler)(int))
+{
+	int flags = 0;
+
+	if(sig_stack != NULL){
+		set_sigstack(sig_stack, 2 * page_size());
+		flags = SA_ONSTACK;
+	}
+	set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
+		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
+		    SA_NOMASK | flags, -1);
+	if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
+	signal(SIGCHLD, SIG_IGN);
+	signal(SIGHUP, SIG_IGN);
+	set_timers(1);  /* XXX A bit of a race here */
+	init_irq_signals(sig_stack != NULL);
+}
+
+struct tramp {
+	int (*tramp)(void *);
+	void *tramp_data;
+	unsigned long temp_stack;
+	int flags;
+	int pid;
+};
+
+/* See above for why sigkill is here */
+
+int sigkill = SIGKILL;
+
+int outer_tramp(void *arg)
+{
+	struct tramp *t;
+	int sig = sigkill;
+
+	t = arg;
+	t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+		       t->flags, t->tramp_data);
+	if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
+	kill(os_getpid(), sig);
+	_exit(0);
+}
+
+int start_fork_tramp(void *thread_arg, unsigned long temp_stack, 
+		     int clone_flags, int (*tramp)(void *))
+{
+	struct tramp arg;
+	unsigned long sp;
+	int new_pid, status, err;
+
+	/* The trampoline will run on the temporary stack */
+	sp = stack_sp(temp_stack);
+
+	clone_flags |= CLONE_FILES | SIGCHLD;
+
+	arg.tramp = tramp;
+	arg.tramp_data = thread_arg;
+	arg.temp_stack = temp_stack;
+	arg.flags = clone_flags;
+
+	/* Start the process and wait for it to kill itself */
+	new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
+	if(new_pid < 0) return(-errno);
+	while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ;
+	if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", 
+			  errno);
+	if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+		panic("outer trampoline didn't exit with SIGKILL");
+
+	return(arg.pid);
+}
+
+void trace_myself(void)
+{
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+		panic("ptrace failed in trace_myself");
+}
+
+void attach_process(int pid)
+{
+	if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
+		tracer_panic("OP_FORK failed to attach pid");
+	wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		tracer_panic("OP_FORK failed to continue process");
+}
+
+void tracer_panic(char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vprintf(format, ap);
+	printf("\n");
+	while(1) sleep(10);
+}
+
+void suspend_new_thread(int fd)
+{
+	char c;
+
+	os_stop_process(os_getpid());
+
+	if(read(fd, &c, sizeof(c)) != sizeof(c))
+		panic("read failed in suspend_new_thread");
+}
+
+static int ptrace_child(void *arg)
+{
+	int pid = os_getpid();
+
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+		perror("ptrace");
+		_exit(1);
+	}
+	os_stop_process(pid);
+	_exit(os_getpid() == pid);
+}
+
+void __init check_ptrace(void)
+{
+	void *stack;
+	unsigned long sp;
+	int status, pid, n, syscall;
+
+	printk("Checking that ptrace can change system call numbers...");
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if(stack == MAP_FAILED)
+		panic("check_ptrace : mmap failed, errno = %d", errno);
+	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+	pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
+	if(pid < 0)
+		panic("check_ptrace : clone failed, errno = %d", errno);
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0)
+		panic("check_ptrace : wait failed, errno = %d", errno);
+	if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
+		panic("check_ptrace : expected SIGSTOP, got status = %d",
+		      status);
+	while(1){
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			panic("check_ptrace : ptrace failed, errno = %d", 
+			      errno);
+		n = waitpid(pid, &status, WUNTRACED);
+		if(n < 0)
+			panic("check_ptrace : wait failed, errno = %d", errno);
+		if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
+			panic("check_ptrace : expected SIGTRAP, "
+			      "got status = %d", status);
+		
+		syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET,
+				 0);
+		if(syscall == __NR_getpid){
+			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
+				   __NR_getppid);
+			if(n < 0)
+				panic("check_ptrace : failed to modify system "
+				      "call, errno = %d", errno);
+			break;
+		}
+	}
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		panic("check_ptrace : ptrace failed, errno = %d", errno);
+	n = waitpid(pid, &status, 0);
+	if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+		panic("check_ptrace : child exited with status 0x%x", status);
+
+	if(munmap(stack, PAGE_SIZE) < 0)
+		panic("check_ptrace : munmap failed, errno = %d", errno);
+	printk("OK\n");
+}
+
+int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
+{
+	jmp_buf buf;
+
+	*jmp_ptr = &buf;
+	if(setjmp(buf)) return(1);
+	(*fn)(arg);
+	return(0);
+}
+
+void forward_pending_sigio(int target)
+{
+	sigset_t sigs;
+
+	if(sigpending(&sigs)) 
+		panic("forward_pending_sigio : sigpending failed");
+	if(sigismember(&sigs, SIGIO))
+		kill(target, SIGIO);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/process_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,771 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/interrupt.h"
+#include "linux/mm.h"
+#include "linux/slab.h"
+#include "linux/utsname.h"
+#include "linux/fs.h"
+#include "linux/utime.h"
+#include "linux/smp_lock.h"
+#include "linux/module.h"
+#include "linux/init.h"
+#include "linux/capability.h"
+#include "asm/unistd.h"
+#include "asm/mman.h"
+#include "asm/segment.h"
+#include "asm/stat.h"
+#include "asm/pgtable.h"
+#include "asm/processor.h"
+#include "asm/tlbflush.h"
+#include "asm/spinlock.h"
+#include "asm/uaccess.h"
+#include "asm/user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "init.h"
+#include "irq_user.h"
+#include "mem_user.h"
+#include "tlb.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+#include "2_5compat.h"
+#include "os.h"
+
+struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
+
+struct task_struct *get_task(int pid, int require)
+{
+        struct task_struct *task, *ret;
+
+        ret = NULL;
+        read_lock(&tasklist_lock);
+        for_each_task(task){
+                if(task->pid == pid){
+                        ret = task;
+                        break;
+                }
+        }
+        read_unlock(&tasklist_lock);
+        if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
+        return(ret);
+}
+
+int is_valid_pid(int pid)
+{
+	struct task_struct *task;
+
+        read_lock(&tasklist_lock);
+        for_each_task(task){
+                if(task->thread.extern_pid == pid){
+			read_unlock(&tasklist_lock);
+			return(1);
+                }
+        }
+	read_unlock(&tasklist_lock);
+	return(0);
+}
+
+int external_pid(void *t)
+{
+	struct task_struct *task = t ? t : current;
+
+	return(task->thread.extern_pid);
+}
+
+int pid_to_processor_id(int pid)
+{
+	int i;
+
+	for(i = 0; i < num_online_cpus(); i++){
+		if(cpu_tasks[i].pid == pid) return(i);
+	}
+	return(-1);
+}
+
+void free_stack(unsigned long stack, int order)
+{
+	free_pages(stack, order);
+}
+
+void set_init_pid(int pid)
+{
+	int err;
+
+	init_task.thread.extern_pid = pid;
+	err = os_pipe(init_task.thread.switch_pipe, 1, 1);
+	if(err)	panic("Can't create switch pipe for init_task, errno = %d", 
+		      err);
+}
+
+int set_user_mode(void *t)
+{
+	struct task_struct *task;
+
+	task = t ? t : current;
+	if(task->thread.tracing) return(1);
+	task->thread.request.op = OP_TRACE_ON;
+	os_usr1_process(os_getpid());
+	return(0);
+}
+
+void set_tracing(void *task, int tracing)
+{
+	((struct task_struct *) task)->thread.tracing = tracing;
+}
+
+int is_tracing(void *t)
+{
+	return (((struct task_struct *) t)->thread.tracing);
+}
+
+unsigned long alloc_stack(int order, int atomic)
+{
+	unsigned long page;
+	int flags = GFP_KERNEL;
+
+	if(atomic) flags |= GFP_ATOMIC;
+	if((page = __get_free_pages(flags, order)) == 0)
+		return(0);
+	stack_protections(page);
+	return(page);
+}
+
+extern void schedule_tail(struct task_struct *prev);
+
+static void new_thread_handler(int sig)
+{
+	int (*fn)(void *);
+	void *arg;
+
+	fn = current->thread.request.u.thread.proc;
+	arg = current->thread.request.u.thread.arg;
+	current->thread.regs.regs.sc = (void *) (&sig + 1);
+	suspend_new_thread(current->thread.switch_pipe[0]);
+
+	free_page(current->thread.temp_stack);
+	set_cmdline("(kernel thread)");
+	force_flush_all();
+
+	current->thread.prev_sched = NULL;
+	change_sig(SIGUSR1, 1);
+	unblock_signals();
+	if(!run_kernel_thread(fn, arg, &current->thread.jmp))
+		do_exit(0);
+}
+
+static int new_thread_proc(void *stack)
+{
+	block_signals();
+	init_new_thread(stack, new_thread_handler);
+	os_usr1_process(os_getpid());
+	return(0);
+}
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	struct task_struct *p;
+
+	current->thread.request.u.thread.proc = fn;
+	current->thread.request.u.thread.arg = arg;
+	p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL);
+	if(IS_ERR(p)) panic("do_fork failed in kernel_thread");
+	return(p->pid);
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+	       struct task_struct *tsk, unsigned cpu)
+{
+	if (prev != next) 
+		clear_bit(cpu, &prev->cpu_vm_mask);
+	set_bit(cpu, &next->cpu_vm_mask);
+}
+
+void set_current(void *t)
+{
+	struct task_struct *task = t;
+
+	cpu_tasks[task->thread_info->cpu] = ((struct cpu_task) 
+		{ task->thread.extern_pid, task });
+}
+
+void *switch_to(void *prev, void *next, void *last)
+{
+	struct task_struct *from, *to;
+	unsigned long flags;
+	int vtalrm, alrm, prof, err, cpu;
+	char c;
+	static int reading;
+
+	from = prev;
+	to = next;
+
+	to->thread.prev_sched = from;
+
+	cpu = from->thread_info->cpu;
+	if(cpu == 0) 
+		forward_interrupts(to->thread.extern_pid);
+#ifdef CONFIG_SMP
+	forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.extern_pid);
+#endif
+	local_irq_save(flags);
+
+	vtalrm = change_sig(SIGVTALRM, 0);
+	alrm = change_sig(SIGALRM, 0);
+	prof = change_sig(SIGPROF, 0);
+
+	forward_pending_sigio(to->thread.extern_pid);
+
+	c = 0;
+	set_current(to);
+
+	reading = 0;
+	err = user_write(to->thread.switch_pipe[1], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("write of switch_pipe failed, errno = %d", -err);
+
+	reading = 1;
+	if(from->state == TASK_ZOMBIE) os_kill_process(os_getpid());
+
+	err = user_read(from->thread.switch_pipe[0], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read of switch_pipe failed, errno = %d", -err);
+
+	/* This works around a nasty race with 'jail'.  If we are switching
+	 * between two threads of a threaded app and the incoming process 
+	 * runs before the outgoing process reaches the read, and it makes
+	 * it all the way out to userspace, then it will have write-protected 
+	 * the outgoing process stack.  Then, when the outgoing process 
+	 * returns from the write, it will segfault because it can no longer
+	 * write its own stack.  So, in order to avoid that, the incoming 
+	 * thread sits in a loop yielding until 'reading' is set.  This 
+	 * isn't entirely safe, since there may be a reschedule from a timer
+	 * happening between setting 'reading' and sleeping in read.  But,
+	 * it should get a whole quantum in which to reach the read and sleep,
+	 * which should be enough.
+	 */
+
+	if(jail){
+		while(!reading) sched_yield();
+	}
+
+	change_sig(SIGVTALRM, vtalrm);
+	change_sig(SIGALRM, alrm);
+	change_sig(SIGPROF, prof);
+
+	arch_switch();
+
+	flush_tlb_all();
+	local_irq_restore(flags);
+
+	return(current->thread.prev_sched);
+}
+
+void interrupt_end(void)
+{
+	if(need_resched()) schedule();
+	if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal(0);
+}
+
+void release_thread(struct task_struct *task)
+{
+	os_kill_process(task->thread.extern_pid);
+}
+
+void exit_thread(void)
+{
+	close(current->thread.switch_pipe[0]);
+	close(current->thread.switch_pipe[1]);
+	unprotect_stack((unsigned long) current->thread_info);
+}
+
+/* Signal masking - signals are blocked at the start of fork_tramp.  They
+ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
+ * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off,
+ * so it is blocked before it's called.  They are re-enabled on sigreturn
+ * despite the fact that they were blocked when the SIGUSR1 was issued because
+ * copy_thread copies the parent's signcontext, including the signal mask
+ * onto the signal frame.
+ */
+
+extern int hit_me;
+
+void finish_fork_handler(int sig)
+{
+	current->thread.regs.regs.sc = (void *) (&sig + 1);
+	suspend_new_thread(current->thread.switch_pipe[0]);
+	
+	force_flush_all();
+	if(current->mm != current->parent->mm)
+		protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+	task_protections((unsigned long) current->thread_info);
+
+	current->thread.prev_sched = NULL;
+
+	free_page(current->thread.temp_stack);
+	block_signals();
+	change_sig(SIGUSR1, 0);
+	set_user_mode(current);
+}
+
+void *get_current(void)
+{
+	return(current);
+}
+
+/* This sigusr1 business works around a bug in gcc's -pg support.  
+ * Normally a procedure's mcount call comes after esp has been copied to 
+ * ebp and the new frame is constructed.  With procedures with no locals,
+ * the mcount comes before, as the first thing that the procedure does.
+ * When that procedure is main for a thread, ebp comes in as NULL.  So,
+ * when mcount dereferences it, it segfaults.  So, UML works around this
+ * by adding a non-optimizable local to the various trampolines, fork_tramp
+ * and outer_tramp below, and exec_tramp.
+ */
+
+static int sigusr1 = SIGUSR1;
+
+int fork_tramp(void *stack)
+{
+	int sig = sigusr1;
+
+	block_signals();
+	init_new_thread(stack, finish_fork_handler);
+
+	kill(os_getpid(), sig);
+	return(0);
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+		unsigned long stack_top, struct task_struct * p, 
+		struct pt_regs *regs)
+{
+	int new_pid, err;
+	unsigned long stack;
+	int (*tramp)(void *);
+
+	p->thread = (struct thread_struct) INIT_THREAD;
+	p->thread.kernel_stack = 
+		(unsigned long) p->thread_info + 2 * PAGE_SIZE;
+
+	if(current->thread.forking)
+		tramp = fork_tramp;
+	else {
+		tramp = new_thread_proc;
+		p->thread.request.u.thread = current->thread.request.u.thread;
+	}
+
+	err = os_pipe(p->thread.switch_pipe, 1, 1);
+	if(err){
+		printk("copy_thread : pipe failed, errno = %d\n", -err);
+		return(err);
+	}
+
+	stack = alloc_stack(0, 0);
+	if(stack == 0){
+		printk(KERN_ERR "copy_thread : failed to allocate "
+		       "temporary stack\n");
+		return(-ENOMEM);
+	}
+
+	clone_flags &= CLONE_VM;
+	p->thread.temp_stack = stack;
+	new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack,
+				   clone_flags, tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
+		       -new_pid);
+		return(new_pid);
+	}
+
+	if(current->thread.forking){
+		sc_to_sc(p->thread.regs.regs.sc, current->thread.regs.regs.sc);
+		PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
+		if(sp != 0) PT_REGS_SP(&p->thread.regs) = sp;
+	}
+	p->thread.extern_pid = new_pid;
+
+	current->thread.request.op = OP_FORK;
+	current->thread.request.u.fork.pid = new_pid;
+	os_usr1_process(os_getpid());
+	return(0);
+}
+
+void tracing_reboot(void)
+{
+	current->thread.request.op = OP_REBOOT;
+	os_usr1_process(os_getpid());
+}
+
+void tracing_halt(void)
+{
+	current->thread.request.op = OP_HALT;
+	os_usr1_process(os_getpid());
+}
+
+void tracing_cb(void (*proc)(void *), void *arg)
+{
+	if(os_getpid() == tracing_pid){
+		(*proc)(arg);
+	}
+	else {
+		current->thread.request.op = OP_CB;
+		current->thread.request.u.cb.proc = proc;
+		current->thread.request.u.cb.arg = arg;
+		os_usr1_process(os_getpid());
+	}
+}
+
+int do_proc_op(void *t, int proc_id)
+{
+	struct task_struct *task;
+	struct thread_struct *thread;
+	int op, pid;
+
+	task = t;
+	thread = &task->thread;
+	op = thread->request.op;
+	switch(op){
+	case OP_NONE:
+	case OP_TRACE_ON:
+		break;
+	case OP_EXEC:
+		pid = thread->request.u.exec.pid;
+		do_exec(thread->extern_pid, pid);
+		thread->extern_pid = pid;
+		cpu_tasks[task->thread_info->cpu].pid = pid;
+		break;
+	case OP_FORK:
+		attach_process(thread->request.u.fork.pid);
+		break;
+	case OP_CB:
+		(*thread->request.u.cb.proc)(thread->request.u.cb.arg);
+		break;
+	case OP_REBOOT:
+	case OP_HALT:
+		break;
+	default:
+		tracer_panic("Bad op in do_proc_op");
+		break;
+	}
+	thread->request.op = OP_NONE;
+	return(op);
+}
+
+unsigned long stack_sp(unsigned long page)
+{
+	return(page + PAGE_SIZE - sizeof(void *));
+}
+
+int current_pid(void)
+{
+	return(current->pid);
+}
+
+void default_idle(void)
+{
+ 	if(current->thread_info->cpu == 0) idle_timer();
+
+	atomic_inc(&init_mm.mm_count);
+	current->mm = &init_mm;
+	current->active_mm = &init_mm;
+
+	while(1){
+		/* endless idle loop with no priority at all */
+		SET_PRI(current);
+
+		/*
+		 * although we are an idle CPU, we do not want to
+		 * get into the scheduler unnecessarily.
+		 */
+		irq_stat[smp_processor_id()].idle_timestamp = jiffies;
+		if(need_resched())
+			schedule();
+		
+		idle_sleep(10);
+	}
+}
+
+void cpu_idle(void)
+{
+	default_idle();
+}
+
+int page_size(void)
+{
+	return(PAGE_SIZE);
+}
+
+int page_mask(void)
+{
+	return(PAGE_MASK);
+}
+
+unsigned long um_virt_to_phys(void *t, unsigned long addr)
+{
+	struct task_struct *task;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	task = t;
+	if(task->mm == NULL) return(0xffffffff);
+	pgd = pgd_offset(task->mm, addr);
+	pmd = pmd_offset(pgd, addr);
+	if(!pmd_present(*pmd)) return(0xffffffff);
+	pte = pte_offset_kernel(pmd, addr);
+	if(!pte_present(*pte)) return(0xffffffff);
+	return((pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK));
+}
+
+char *current_cmd(void)
+{
+#ifdef CONFIG_SMP
+	return("(Unknown)");
+#else
+	unsigned long addr = um_virt_to_phys(current, current->mm->arg_start);
+	return addr == 0xffffffff? "(Unknown)": __va(addr);
+#endif
+}
+
+void force_sigbus(void)
+{
+	printk(KERN_ERR "Killing pid %d because of a lack of memory\n", 
+	       current->pid);
+	lock_kernel();
+	sigaddset(&current->pending.signal, SIGBUS);
+	recalc_sigpending();
+	current->flags |= PF_SIGNALED;
+	do_exit(SIGBUS | 0x80);
+}
+
+void dump_thread(struct pt_regs *regs, struct user *u)
+{
+}
+
+void enable_hlt(void)
+{
+	panic("enable_hlt");
+}
+
+void disable_hlt(void)
+{
+	panic("disable_hlt");
+}
+
+extern int signal_frame_size;
+
+void *um_kmalloc(int size)
+{
+	return(kmalloc(size, GFP_KERNEL));
+}
+
+void *um_kmalloc_atomic(int size)
+{
+	return(kmalloc(size, GFP_ATOMIC));
+}
+
+unsigned long get_fault_addr(void)
+{
+	return((unsigned long) current->thread.fault_addr);
+}
+
+EXPORT_SYMBOL(get_fault_addr);
+
+void clear_singlestep(void *t)
+{
+	struct task_struct *task = (struct task_struct *) t;
+
+	task->ptrace &= ~PT_DTRACE;
+}
+
+int singlestepping(void *t)
+{
+	struct task_struct *task = (struct task_struct *) t;
+
+	if(task->thread.singlestep_syscall)
+		return(0);
+	return(task->ptrace & PT_DTRACE);
+}
+
+void not_implemented(void)
+{
+	printk(KERN_DEBUG "Something isn't implemented in here\n");
+}
+
+EXPORT_SYMBOL(not_implemented);
+
+int user_context(unsigned long sp)
+{
+	return((sp & (PAGE_MASK << 1)) != current->thread.kernel_stack);
+}
+
+extern void remove_umid_dir(void);
+__uml_exitcall(remove_umid_dir);
+
+extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
+
+void do_uml_exitcalls(void)
+{
+	exitcall_t *call;
+
+	call = &__uml_exitcall_end;
+	while (--call >= &__uml_exitcall_begin)
+		(*call)();
+}
+
+void *round_up(unsigned long addr)
+{
+	return(ROUND_UP(addr));
+}
+
+void *round_down(unsigned long addr)
+{
+	return(ROUND_DOWN(addr));
+}
+
+char *uml_strdup(char *string)
+{
+	char *new;
+
+	new = kmalloc(strlen(string) + 1, GFP_KERNEL);
+	if(new == NULL) return(NULL);
+	strcpy(new, string);
+	return(new);
+}
+
+int jail = 0;
+
+int __init jail_setup(char *line, int *add)
+{
+	int ok = 1;
+
+	if(jail) return(0);
+#ifdef CONFIG_SMP
+	printf("'jail' may not used used in a kernel with CONFIG_SMP "
+	       "enabled\n");
+	ok = 0;
+#endif
+#ifdef CONFIG_HOSTFS
+	printf("'jail' may not used used in a kernel with CONFIG_HOSTFS "
+	       "enabled\n");
+	ok = 0;
+#endif
+#ifdef CONFIG_MODULES
+	printf("'jail' may not used used in a kernel with CONFIG_MODULES "
+	       "enabled\n");
+	ok = 0;
+#endif	
+	if(!ok) exit(1);
+
+	/* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem.
+	 * Removing it from the bounding set eliminates the ability of anything
+	 * to acquire it, and thus read or write kernel memory.
+	 */
+	cap_lower(cap_bset, CAP_SYS_RAWIO);
+	jail = 1;
+	return(0);
+}
+
+__uml_setup("jail", jail_setup,
+"jail\n"
+"    Enables the protection of kernel memory from processes.\n\n"
+);
+
+static void mprotect_kernel_mem(int w)
+{
+	unsigned long start, end;
+
+	if(!jail || (current == &init_task)) return;
+
+	start = (unsigned long) current->thread_info + PAGE_SIZE;
+	end = (unsigned long) current->thread_info + PAGE_SIZE * 4;
+	protect(uml_reserved, start - uml_reserved, 1, w, 1, 1);
+	protect(end, high_physmem - end, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&_stext);
+	end = (unsigned long) ROUND_UP(&_etext);
+	protect(start, end - start, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&_unprotected_end);
+	end = (unsigned long) ROUND_UP(&_edata);
+	protect(start, end - start, 1, w, 1, 1);
+
+	start = (unsigned long) ROUND_DOWN(&__bss_start);
+	end = (unsigned long) ROUND_UP(brk_start);
+	protect(start, end - start, 1, w, 1, 1);
+
+	mprotect_kernel_vm(w);
+}
+
+int jail_timer_off = 0;
+
+void unprotect_kernel_mem(void)
+{
+	mprotect_kernel_mem(1);
+	jail_timer_off = 0;
+}
+
+void protect_kernel_mem(void)
+{
+	jail_timer_off = 1;
+	mprotect_kernel_mem(0);
+}
+
+void *get_init_task(void)
+{
+	return(&init_thread_union.thread_info.task);
+}
+
+int copy_to_user_proc(void *to, void *from, int size)
+{
+	return(copy_to_user(to, from, size));
+}
+
+int copy_from_user_proc(void *to, void *from, int size)
+{
+	return(copy_from_user(to, from, size));
+}
+
+int clear_user_proc(void *buf, int size)
+{
+	return(clear_user(buf, size));
+}
+
+void set_thread_sc(void *sc)
+{
+	current->thread.regs.regs.sc = sc;
+}
+
+int smp_sigio_handler(void)
+{
+#ifdef CONFIG_SMP
+	IPI_handler(hard_smp_processor_id());
+	if (hard_smp_processor_id() != 0) return(1);
+#endif
+	return(0);
+}
+
+int um_in_interrupt(void)
+{
+	return(in_interrupt());
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/ptrace.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,281 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/errno.h"
+#include "linux/smp_lock.h"
+#include "linux/security.h"
+#include "linux/ptrace.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{ 
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int i, ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+
+		ret = security_ops->ptrace(current->parent, current);
+		if(ret)
+ 			goto out;
+
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+
+	switch (request) {
+		/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		ret = -EIO;
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
+
+		ret = -EIO;
+		if ((addr & 3) || addr < 0) 
+			break;
+
+		tmp = 0;  /* Default return condition */
+		if(addr < FRAME_SIZE_OFFSET){
+			tmp = getreg(child, addr);
+		}
+		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+			(addr <= offsetof(struct user, u_debugreg[7]))){
+			addr -= offsetof(struct user, u_debugreg[0]);
+			addr = addr >> 2;
+			tmp = child->thread.arch.debugregs[addr];
+		}
+		ret = put_user(tmp, (unsigned long *) data);
+		break;
+	}
+
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = -EIO;
+		if (access_process_vm(child, addr, &data, sizeof(data), 
+				      1) != sizeof(data))
+			break;
+		ret = 0;
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0)
+			break;
+
+		if (addr < FRAME_SIZE_OFFSET) {
+			ret = putreg(child, addr, data);
+			break;
+		}
+		else if((addr >= offsetof(struct user, u_debugreg[0])) &&
+			(addr <= offsetof(struct user, u_debugreg[7]))){
+			  addr -= offsetof(struct user, u_debugreg[0]);
+			  addr = addr >> 2;
+			  if((addr == 4) || (addr == 5)) break;
+			  child->thread.arch.debugregs[addr] = data;
+			  ret = 0;
+		}
+
+		break;
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL) {
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		else {
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		}
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		ret = 0;
+		if (child->state == TASK_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->ptrace |= PT_DTRACE;
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH:
+		/* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+ 		break;
+
+#ifdef PTRACE_GETREGS
+	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+	  	if (!access_ok(VERIFY_WRITE, (unsigned *)data, 
+			       FRAME_SIZE_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
+			__put_user(getreg(child, i),(unsigned long *) data);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+#endif
+#ifdef PTRACE_SETREGS
+	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+		unsigned long tmp = 0;
+	  	if (!access_ok(VERIFY_READ, (unsigned *)data, 
+			       FRAME_SIZE_OFFSET)) {
+			ret = -EIO;
+			break;
+		}
+		for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) {
+			__get_user(tmp, (unsigned long *) data);
+			putreg(child, i, tmp);
+			data += sizeof(long);
+		}
+		ret = 0;
+		break;
+	}
+#endif
+#ifdef PTRACE_GETFPREGS
+	case PTRACE_GETFPREGS: /* Get the child FPU state. */
+		ret = get_fpregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_SETFPREGS
+	case PTRACE_SETFPREGS: /* Set the child FPU state. */
+	        ret = set_fpregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_GETFPXREGS
+	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
+		ret = get_fpxregs(data, child);
+		break;
+#endif
+#ifdef PTRACE_SETFPXREGS
+	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
+		ret = set_fpxregs(data, child);
+		break;
+#endif
+	default:
+		ret = -EIO;
+		break;
+	}
+ out_tsk:
+	put_task_struct(child);
+ out:
+	unlock_kernel();
+	return ret;
+}
+
+void syscall_trace(void)
+{
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+ 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ 					? 0x80 : 0);
+	current->state = TASK_STOPPED;
+	notify_parent(current, SIGCHLD);
+	schedule();
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/reboot.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,62 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "os.h"
+
+static void kill_off_processes(void)
+{
+	struct task_struct *p;
+	int me;
+
+	me = os_getpid();
+	for_each_task(p){
+		if(p->thread.extern_pid != me) 
+			os_kill_process(p->thread.extern_pid);
+	}
+	if(init_task.thread.extern_pid != me) 
+		os_kill_process(init_task.thread.extern_pid);
+}
+
+void uml_cleanup(void)
+{
+	kill_off_processes();
+	do_uml_exitcalls();
+}
+
+void machine_restart(char * __unused)
+{
+	do_uml_exitcalls();
+	kill_off_processes();
+	tracing_reboot();
+	os_kill_process(os_getpid());
+}
+
+void machine_power_off(void)
+{
+	do_uml_exitcalls();
+	kill_off_processes();
+	tracing_halt();
+	os_kill_process(os_getpid());
+}
+
+void machine_halt(void)
+{
+	machine_power_off();
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/resource.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,23 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/pci.h"
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+			     unsigned long start, unsigned long size)
+{
+	return start;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/setup.c b/arch/um/kernel/setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/setup.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/processor.h"
+
+struct cpuinfo_um boot_cpu_data = { loops_per_jiffy :	0,
+				    ipi_pipe : 		{ -1, -1 } };
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/sigio_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/list.h"
+#include "linux/slab.h"
+#include "asm/irq.h"
+#include "init.h"
+#include "sigio.h"
+#include "irq_user.h"
+
+static int sigio_irq_fd = -1;
+
+void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+{
+	read_sigio_fd(sigio_irq_fd);
+	reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
+}
+
+int write_sigio_irq(int fd)
+{
+	if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
+			  SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", 
+			  NULL)){
+		printk("write_sigio_irq : um_request_irq failed\n");
+		return(-1);
+	}
+	sigio_irq_fd = fd;
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/sigio_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,413 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <pty.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include "init.h"
+#include "user.h"
+#include "kern_util.h"
+#include "sigio.h"
+#include "helper.h"
+#include "os.h"
+
+int pty_output_sigio = 0;
+int pty_close_sigio = 0;
+
+static int got_sigio = 0;
+
+void __init handler(int sig)
+{
+	got_sigio = 1;
+}
+
+struct openpty_arg {
+	int master;
+	int slave;
+	int err;
+};
+
+static int openpty_cb(void *arg)
+{
+	struct openpty_arg *info = arg;
+
+	info->err = 0;
+	if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+		info->err = errno;
+	return(0);
+}
+
+void __init check_one_sigio(void (*proc)(int, int))
+{
+	struct sigaction old, new;
+	struct termios tt;
+	struct openpty_arg pty = { master : -1, slave : -1 };
+	int master, slave, flags, err;
+
+	err = run_helper_thread(openpty_cb, &pty, CLONE_FILES, NULL, 2);
+	if(err < 0){
+		printk("run_helper_thread failed, errno = %d\n", -err);
+		return;
+	}
+	if(pty.err){
+		printk("openpty failed, errno = %d\n", pty.err);
+		return;
+	}
+
+	master = pty.master;
+	slave = pty.slave;
+
+	if((master == -1) || (slave == -1)){
+		printk("openpty failed to allocate a pty\n");
+		return;
+	}
+
+	if(tcgetattr(master, &tt) < 0)
+		panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
+	cfmakeraw(&tt);
+	if(tcsetattr(master, TCSADRAIN, &tt) < 0)
+		panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
+
+	if((flags = fcntl(master, F_GETFL)) < 0)
+		panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
+
+	if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+	   (fcntl(master, F_SETOWN, os_getpid()) < 0))
+		panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
+		      "errno = %d\n", errno);
+
+	if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+		panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", 
+		      errno);
+
+	if(sigaction(SIGIO, NULL, &old) < 0)
+		panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+	new = old;
+	new.sa_handler = handler;
+	if(sigaction(SIGIO, &new, NULL) < 0)
+		panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+
+	got_sigio = 0;
+	(*proc)(master, slave);
+		
+	close(master);
+	close(slave);
+
+	if(sigaction(SIGIO, &old, NULL) < 0)
+		panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+	int n;
+	char buf[512];
+
+	printk("Checking that host ptys support output SIGIO...");
+
+	while(write(master, buf, sizeof(buf)) > 0) ;
+	if(errno != EAGAIN)
+		panic("check_sigio : write failed, errno = %d\n", errno);
+
+	while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+	if(got_sigio){
+		printk("Yes\n");
+		pty_output_sigio = 1;
+	}
+	else if(errno == EAGAIN) printk("No, enabling workaround\n");
+	else panic("check_sigio : read failed, errno = %d\n", errno);
+}
+
+static void tty_close(int master, int slave)
+{
+	printk("Checking that host ptys support SIGIO on close...");
+
+	close(slave);
+	if(got_sigio){
+		printk("Yes\n");
+		pty_close_sigio = 1;
+	}
+	else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+	if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){
+		printk("No pseudo-terminals available - skipping pty SIGIO "
+		       "check\n");
+		return;
+	}
+	check_one_sigio(tty_output);
+	check_one_sigio(tty_close);
+}
+
+static int write_sigio_pid = -1;
+static int write_sigio_fds[2] = { -1, -1 };
+static int sigio_private[2] = { -1, -1 };
+
+struct pollfds {
+	struct pollfd *poll;
+	int size;
+	int used;
+};
+
+struct pollfds current_poll = {
+	poll : 		NULL,
+	size :		0,
+	used :		0
+};
+
+struct pollfds next_poll = {
+	poll : 		NULL,
+	size :		0,
+	used :		0
+};
+
+static int write_sigio_thread(void *unused)
+{
+	struct pollfds *fds, tmp;
+	struct pollfd *p;
+	int i, n, respond_fd;
+	char c;
+
+	fds = &current_poll;
+	while(1){
+		n = poll(fds->poll, fds->used, -1);
+		if(n < 0){
+			if(errno == EINTR) continue;
+			printk("write_sigio_thread : poll returned %d, "
+			       "errno = %d\n", n, errno);
+		}
+		for(i = 0; i < fds->used; i++){
+			p = &fds->poll[i];
+			if(p->revents == 0) continue;
+			if(p->fd == sigio_private[1]){
+				n = read(sigio_private[1], &c, sizeof(c));
+				if(n != sizeof(c))
+					printk("write_sigio_thread : "
+					       "read failed, errno = %d\n",
+					       errno);
+				tmp = current_poll;
+				current_poll = next_poll;
+				next_poll = tmp;
+				respond_fd = sigio_private[1];
+			}
+			else {
+				respond_fd = write_sigio_fds[1];
+				fds->used--;
+				memmove(&fds->poll[i], &fds->poll[i + 1],
+					(fds->used - i) * sizeof(*fds->poll));
+			}
+
+			n = write(respond_fd, &c, sizeof(c));
+			if(n != sizeof(c))
+				printk("write_sigio_thread : write failed, "
+				       "errno = %d\n", errno);
+		}
+	}
+}
+
+/* XXX SMP locking needed here too */
+
+static int need_poll(int n)
+{
+	if(n <= next_poll.size){
+		next_poll.used = n;
+		return(0);
+	}
+	if(next_poll.poll != NULL) kfree(next_poll.poll);
+	next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
+	if(next_poll.poll == NULL){
+		printk("need_poll : failed to allocate new pollfds\n");
+		next_poll.size = 0;
+		next_poll.used = 0;
+		return(-1);
+	}
+	next_poll.size = n;
+	next_poll.used = n;
+	return(0);
+}
+
+static void update_thread(void)
+{
+	unsigned long flags;
+	int n;
+	char c;
+
+	flags = set_signals(0);
+	n = write(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : write failed, errno = %d\n", errno);
+		goto fail;
+	}
+
+	n = read(sigio_private[0], &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("update_thread : read failed, errno = %d\n", errno);
+		goto fail;
+	}
+
+	set_signals(flags);
+	return;
+ fail:
+	if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
+	write_sigio_pid = -1;
+	close(sigio_private[0]);
+	close(sigio_private[1]);	
+	close(write_sigio_fds[0]);
+	close(write_sigio_fds[1]);
+	set_signals(flags);
+}
+
+int add_sigio_fd(int fd, int read)
+{
+	int err, i, n, events;
+
+	for(i = 0; i < current_poll.used; i++)
+		if(current_poll.poll[i].fd == fd) return(0);
+
+	n = current_poll.used + 1;
+	err = need_poll(n);
+	if(err) return(err);
+
+	for(i = 0; i < current_poll.used; i++)
+		next_poll.poll[i] = current_poll.poll[i];
+
+	if(read) events = POLLIN;
+	else events = POLLOUT;
+
+	next_poll.poll[n - 1] = ((struct pollfd) { fd : 	fd,
+						   events :	events,
+						   revents :	0 });
+	update_thread();
+	return(0);
+}
+
+int ignore_sigio_fd(int fd)
+{
+	struct pollfd *p;
+	int err, i, n = 0;
+
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) break;
+	}
+	if(i == current_poll.used) return(0);
+	
+	err = need_poll(current_poll.used - 1);
+	if(err) return(err);
+
+	for(i = 0; i < current_poll.used; i++){
+		p = &current_poll.poll[i];
+		if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
+	}
+	if(n == i){
+		printk("ignore_sigio_fd : fd %d not found\n", fd);
+		return(-1);
+	}
+
+	update_thread();
+	return(0);
+}
+
+static int setup_initial_poll(int fd)
+{
+	struct pollfd *p;
+
+	p = um_kmalloc(sizeof(struct pollfd));
+	if(p == NULL){
+		printk("setup_initial_poll : failed to allocate poll\n");
+		return(-1);
+	}
+	*p = ((struct pollfd) { fd : 	fd,
+				events :	POLLIN,
+				revents :	0 });
+	current_poll = ((struct pollfds) { poll :	p,
+					   used :	1,
+					   size :	1 });
+	return(0);
+}
+
+void write_sigio_workaround(void)
+{
+	unsigned long stack;
+	int err;
+
+	if(write_sigio_pid != -1) return;
+
+	/* XXX This needs SMP locking */
+	err = os_pipe(write_sigio_fds, 1, 1);
+	if(err){
+		printk("write_sigio_workaround - os_pipe 1 failed, "
+		       "errno = %d\n", -err);
+		return;
+	}
+	err = os_pipe(sigio_private, 1, 1);
+	if(err){
+		printk("write_sigio_workaround - os_pipe 2 failed, "
+		       "errno = %d\n", -err);
+		goto out_close1;
+	}
+	if(setup_initial_poll(sigio_private[1]))
+		goto out_close2;
+
+	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 
+					    CLONE_FILES, &stack, 0);
+
+	if(write_sigio_pid < 0) goto out_close2;
+
+	if(write_sigio_irq(write_sigio_fds[0])) 
+		goto out_kill;
+
+	return;
+
+ out_kill:
+	kill(write_sigio_pid, SIGKILL);
+	write_sigio_pid = -1;
+ out_close2:
+	close(sigio_private[0]);
+	close(sigio_private[1]);	
+ out_close1:
+	close(write_sigio_fds[0]);
+	close(write_sigio_fds[1]);
+}
+
+int read_sigio_fd(int fd)
+{
+	int n;
+	char c;
+
+	n = read(fd, &c, sizeof(c));
+	if(n != sizeof(c)){
+		printk("read_sigio_fd - read failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	return(n);
+}
+
+static void sigio_cleanup(void)
+{
+	if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
+}
+
+__uml_exitcall(sigio_cleanup);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/signal_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,274 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/stddef.h"
+#include "linux/sys.h"
+#include "linux/sched.h"
+#include "linux/wait.h"
+#include "linux/kernel.h"
+#include "linux/smp_lock.h"
+#include "linux/module.h"
+#include "linux/slab.h"
+#include "linux/tty.h"
+#include "linux/binfmts.h"
+#include "asm/signal.h"
+#include "asm/uaccess.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "signal_kern.h"
+#include "signal_user.h"
+#include "kern.h"
+#include "frame_kern.h"
+#include "sigcontext.h"
+
+EXPORT_SYMBOL(block_signals);
+EXPORT_SYMBOL(unblock_signals);
+
+int probe_stack(unsigned long sp, int delta)
+{
+	int n;
+
+	if((get_user(n, (int *) sp) != 0) ||
+	   (put_user(n, (int *) sp) != 0) ||
+	   (get_user(n, (int *) (sp - delta)) != 0) ||
+	   (put_user(n, (int *) (sp - delta)) != 0))
+		return(-EFAULT);
+	return(0);
+}
+
+static void force_segv(int sig)
+{
+	if(sig == SIGSEGV){
+		struct k_sigaction *ka;
+
+		ka = &current->sig->action[SIGSEGV - 1];
+		ka->sa.sa_handler = SIG_DFL;
+	}
+	force_sig(SIGSEGV, current);
+}
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+/*
+ * OK, we're invoking a handler
+ */	
+static int handle_signal(struct pt_regs *regs, unsigned long signr, 
+			 struct k_sigaction *ka, siginfo_t *info, 
+			 sigset_t *oldset, int error)
+{
+        __sighandler_t handler;
+	void (*restorer)(void);
+	unsigned long sp;
+	sigset_t save;
+	int err, ret;
+
+	ret = 0;
+	switch(error){
+	case -ERESTARTNOHAND:
+		ret = -EINTR;
+		break;
+
+	case -ERESTARTSYS:
+		if (!(ka->sa.sa_flags & SA_RESTART)) {
+			ret = -EINTR;
+			break;
+		}
+		/* fallthrough */
+	case -ERESTARTNOINTR:
+		PT_REGS_RESTART_SYSCALL(regs);
+		PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+
+		/* This is because of the UM_SET_SYSCALL_RETURN and the fact
+		 * that on i386 the system call number and return value are
+		 * in the same register.  When the system call restarts, %eax
+		 * had better have the system call number in it.  Since the
+		 * return value doesn't matter (except that it shouldn't be
+		 * -ERESTART*), we'll stick the system call number there.
+		 */
+		ret = PT_REGS_SYSCALL_NR(regs);
+		break;
+	}
+
+	handler = ka->sa.sa_handler;
+	save = *oldset;
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sigmask_lock);
+		sigorsets(&current->blocked, &current->blocked, 
+			  &ka->sa.sa_mask);
+		sigaddset(&current->blocked, signr);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sigmask_lock);
+	}
+
+	sp = PT_REGS_SP(regs);
+
+	if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+	
+	if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret);
+
+	if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
+	else restorer = NULL;
+
+	if(ka->sa.sa_flags & SA_SIGINFO)
+		err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
+					    restorer, regs, info, &save);
+	else
+		err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
+					    restorer, regs, &save);
+	if(err) goto segv;
+
+	return(0);
+ segv:
+	force_segv(signr);
+	return(1);
+}
+
+static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
+{
+	siginfo_t info;
+	struct k_sigaction *ka;
+	int err, sig;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	sig = get_signal_to_deliver(&info, regs);
+	if(sig == 0)
+		return(0);
+
+	/* Whee!  Actually deliver the signal.  */
+	ka = &current->sig->action[sig -1 ];
+	err = handle_signal(regs, sig, ka, &info, oldset, error);
+	if(!err) return(1);
+
+	/* Did we come from a system call? */
+	if(PT_REGS_SYSCALL_NR(regs) >= 0){
+		/* Restart the system call - no handlers present */
+		if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
+		   PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
+		   PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){
+			PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+			PT_REGS_RESTART_SYSCALL(regs);
+		}
+	}
+
+	/* This closes a way to execute a system call on the host.  If
+	 * you set a breakpoint on a system call instruction and singlestep
+	 * from it, the tracing thread used to PTRACE_SINGLESTEP the process
+	 * rather than PTRACE_SYSCALL it, allowing the system call to execute
+	 * on the host.  The tracing thread will check this flag and 
+	 * PTRACE_SYSCALL if necessary.
+	 */
+	if((current->ptrace & PT_DTRACE) && 
+	   is_syscall(PT_REGS_IP(&current->thread.regs)))
+		current->thread.singlestep_syscall = 1;
+	return(0);
+}
+
+int do_signal(int error)
+{
+	return(kern_do_signal(&current->thread.regs, NULL, error));
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sigmask_lock);
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if(kern_do_signal(&current->thread.regs, &saveset, -EINTR))
+			return(-EINTR);
+	}
+}
+
+int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+{
+	sigset_t saveset, newset;
+
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sigmask_lock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sigmask_lock);
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (kern_do_signal(&current->thread.regs, &saveset, -EINTR))
+			return(-EINTR);
+	}
+}
+
+int sys_sigreturn(struct pt_regs regs)
+{
+	void *sc = sp_to_sc(PT_REGS_SP(&regs));
+	void *mask = sp_to_mask(PT_REGS_SP(&regs));
+	int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+
+	spin_lock_irq(&current->sigmask_lock);
+	copy_from_user(&current->blocked.sig[0], sc_sigmask(sc), 
+		       sizeof(current->blocked.sig[0]));
+	copy_from_user(&current->blocked.sig[1], mask, sig_size);
+	sigdelsetmask(&current->blocked, ~_BLOCKABLE);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sigmask_lock);
+	copy_sc_from_user(current->thread.regs.regs.sc, sc,
+			  &signal_frame_sc.arch);
+	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+}
+
+int sys_rt_sigreturn(struct pt_regs regs)
+{
+	void *sc = sp_to_rt_sc(PT_REGS_SP(&regs));
+	void *mask = sp_to_rt_mask(PT_REGS_SP(&regs));
+	int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+
+	spin_lock_irq(&current->sigmask_lock);
+	copy_from_user(&current->blocked, mask, sig_size);
+	sigdelsetmask(&current->blocked, ~_BLOCKABLE);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sigmask_lock);
+	copy_sc_from_user(current->thread.regs.regs.sc, sc,
+			  &signal_frame_sc.arch);
+	return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/signal_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,146 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/mman.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "signal_user.h"
+#include "signal_kern.h"
+#include "sysdep/sigcontext.h"
+#include "sigcontext.h"
+
+extern int kern_timer_on;
+
+void set_sigstack(void *sig_stack, int size)
+{
+	stack_t stack;
+
+	stack.ss_sp = (__ptr_t) sig_stack;
+	stack.ss_flags = 0;
+	stack.ss_size = size - sizeof(void *);
+	if(sigaltstack(&stack, NULL) != 0)
+		panic("sigaltstack failed");
+}
+
+void set_handler(int sig, void (*handler)(int), int flags, ...)
+{
+	struct sigaction action;
+	va_list ap;
+	int mask;
+
+	va_start(ap, flags);
+	action.sa_handler = handler;
+	sigemptyset(&action.sa_mask);
+	while((mask = va_arg(ap, int)) != -1){
+		sigaddset(&action.sa_mask, mask);
+	}
+	action.sa_flags = flags;
+	action.sa_restorer = NULL;
+	if(sigaction(sig, &action, NULL) < 0)
+		panic("sigaction failed");
+}
+
+int change_sig(int signal, int on)
+{
+	sigset_t sigset, old;
+
+	sigemptyset(&sigset);
+	sigaddset(&sigset, signal);
+	sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
+	return(sigismember(&old, signal));
+}
+
+static void change_signals(int type)
+{
+	sigset_t mask;
+
+	sigemptyset(&mask);
+	if(type == SIG_BLOCK) kern_timer_on = 0;
+	else {
+		kern_timer_on = 1;
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+	sigaddset(&mask, SIGIO);
+	sigaddset(&mask, SIGPROF);
+	if(sigprocmask(type, &mask, NULL) < 0)
+		panic("Failed to change signal mask - errno = %d", errno);
+}
+
+void block_signals(void)
+{
+	change_signals(SIG_BLOCK);
+}
+
+void unblock_signals(void)
+{
+	change_signals(SIG_UNBLOCK);
+}
+
+#define SIGIO_BIT 0
+#define SIGVTALRM_BIT 1
+
+static int disable_mask(sigset_t *mask)
+{
+	int sigs;
+
+	sigs = sigismember(mask, SIGIO) ? 1 << SIGIO_BIT : 0;
+	sigs |= sigismember(mask, SIGVTALRM) ? 1 << SIGVTALRM_BIT : 0;
+	sigs |= sigismember(mask, SIGALRM) ? 1 << SIGVTALRM_BIT : 0;
+	if(!kern_timer_on) sigs |= 1 << SIGVTALRM_BIT;
+	return(sigs);
+}
+
+int get_signals(void)
+{
+	sigset_t mask;
+	
+	if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
+		panic("Failed to get signal mask");
+	return(disable_mask(&mask));
+}
+
+int set_signals(int disable)
+{
+	sigset_t mask;
+	int ret;
+
+	sigemptyset(&mask);
+	if(!(disable & (1 << SIGIO_BIT))) sigaddset(&mask, SIGIO);
+	if(!(disable & (1 << SIGVTALRM_BIT))){
+		kern_timer_on = 1;
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
+	if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
+		panic("Failed to enable signals");
+	ret = disable_mask(&mask);
+	sigemptyset(&mask);
+	if(disable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO);
+	if(disable & (1 << SIGVTALRM_BIT))
+		kern_timer_on = 0;
+	if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
+		panic("Failed to block signals");
+	return(ret);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/smp.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,297 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+
+/* CPU online map */
+unsigned long cpu_online_map = 1;
+
+#ifdef CONFIG_SMP
+
+#include "linux/sched.h"
+#include "linux/threads.h"
+#include "linux/interrupt.h"
+#include "asm/smp.h"
+#include "asm/processor.h"
+#include "asm/spinlock.h"
+#include "asm/softirq.h"
+#include "asm/hardirq.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "os.h"
+
+/* The 'big kernel lock' */
+spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_um cpu_data[NR_CPUS];
+
+spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
+
+atomic_t global_bh_count;
+
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile long global_irq_lock;
+
+/* Set when the idlers are all forked */
+int smp_threads_ready = 0;
+int num_reschedules_sent = 0;
+
+void smp_send_reschedule(int cpu)
+{
+	write(cpu_data[cpu].ipi_pipe[1], "R", 1);
+	num_reschedules_sent++;
+}
+
+static void show(char * str)
+{
+	int cpu = smp_processor_id();
+
+	printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
+}
+	
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+	int count = MAXCOUNT;
+	do {
+		if (!--count) {
+			show("wait_on_bh");
+			count = ~0;
+		}
+		/* nothing .. wait for the other bh's to go away */
+	} while (atomic_read(&global_bh_count) != 0);
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler. 
+ */
+void synchronize_bh(void)
+{
+	if (atomic_read(&global_bh_count) && !in_interrupt())
+		wait_on_bh();
+}
+
+void smp_send_stop(void)
+{
+	printk(KERN_INFO "Stopping all CPUs\n");
+}
+
+
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+static volatile unsigned long smp_callin_map = 0;
+
+void smp_commence(void)
+{
+	printk("All CPUs are go!\n");
+
+	wmb();
+	atomic_set(&smp_commenced, 1);
+}
+
+static int idle_proc(void *unused)
+{
+	int cpu, err;
+
+	set_current(current);
+	del_from_runqueue(current);
+	unhash_process(current);
+
+	cpu = current->processor;
+	err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
+	if(err)
+		panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, 
+		      -err);
+
+	activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid);
+ 
+	wmb();
+	if (test_and_set_bit(current->processor, &smp_callin_map)) {
+		printk("huh, CPU#%d already present??\n", current->processor);
+		BUG();
+	}
+
+	while (!atomic_read(&smp_commenced))
+		cpu_relax();
+
+	init_idle();
+	default_idle();
+	return(0);
+}
+
+int inited_cpus = 1;
+
+static int idle_thread(int (*fn)(void *), int cpu)
+{
+	struct task_struct *p;
+	int pid;
+	unsigned char c;
+
+        current->thread.request.u.thread.proc = fn;
+        current->thread.request.u.thread.arg = NULL;
+	p = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0);
+	if(IS_ERR(p)) panic("do_fork failed in idle_thread");
+
+	cpu_tasks[cpu].pid = p->thread.extern_pid;
+	cpu_tasks[cpu].task = p;
+	inited_cpus++;
+	init_tasks[cpu] = p;
+	p->processor = cpu;
+	p->cpus_allowed = 1 << cpu;
+	p->cpus_runnable = p->cpus_allowed;
+	write(p->thread.switch_pipe[1], &c, sizeof(c));
+	return(p->thread.extern_pid);
+}
+
+void smp_boot_cpus(void)
+{
+	int err;
+
+	set_bit(0, &cpu_online_map);
+	set_bit(0, &smp_callin_map);
+
+	err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
+	if(err)	panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
+
+	activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid);
+
+	if(ncpus < 1){
+		printk(KERN_INFO "ncpus set to 1\n");
+		ncpus = 1;
+	}
+	else if(ncpus > NR_CPUS){
+		printk(KERN_INFO 
+		       "ncpus can't be greater than NR_CPUS, set to %d\n",
+		       NR_CPUS);
+		ncpus = NR_CPUS;
+	}
+
+	if(ncpus > 1){
+		int i, pid;
+
+		printk(KERN_INFO "Starting up other processors:\n");
+		for(i=1;i<ncpus;i++){
+			int waittime;
+
+			/* Do this early, for hard_smp_processor_id()  */
+			cpu_tasks[i].pid = -1;
+			set_bit(i, &cpu_online_map);
+
+			pid = idle_thread(idle_proc, i);
+			printk(KERN_INFO "\t#%d - idle thread pid = %d.. ",
+			       i, pid);
+
+			waittime = 200000000;
+			while (waittime-- && !test_bit(i, &smp_callin_map))
+				cpu_relax();
+
+			if (test_bit(i, &smp_callin_map))
+				printk("online\n");
+			else {
+				printk("failed\n");
+				clear_bit(i, &cpu_online_map);
+			}
+		}
+	}
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+	printk(KERN_INFO "setup_profiling_timer\n");
+	return(0);
+}
+
+void smp_call_function_slave(int cpu);
+
+void IPI_handler(int cpu)
+{
+	unsigned char c;
+	int fd;
+
+	fd = cpu_data[cpu].ipi_pipe[0];
+	while (read(fd, &c, 1) == 1) {
+		switch (c) {
+		case 'C':
+			smp_call_function_slave(cpu);
+			break;
+
+		case 'R':
+			current->need_resched = 1;
+			break;
+
+		default:
+			printk("CPU#%d received unknown IPI [%c]!\n", cpu, c);
+			break;
+		}
+	}
+}
+
+int hard_smp_processor_id(void)
+{
+	return(pid_to_processor_id(os_getpid()));
+}
+
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+static atomic_t scf_started;
+static atomic_t scf_finished;
+static void (*func)(void *info);
+static void *info;
+
+void smp_call_function_slave(int cpu)
+{
+	atomic_inc(&scf_started);
+	(*func)(info);
+	atomic_inc(&scf_finished);
+}
+
+int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, 
+		      int wait)
+{
+	int cpus = num_online_cpus() - 1;
+	int i;
+
+	if (!cpus)
+		return 0;
+
+	spin_lock_bh(&call_lock);
+	atomic_set(&scf_started, 0);
+	atomic_set(&scf_finished, 0);
+	func = _func;
+	info = _info;
+
+	for (i=0;i<NR_CPUS;i++)
+		if (i != current->processor && test_bit(i, &cpu_online_map))
+			write(cpu_data[i].ipi_pipe[1], "C", 1);
+
+	while (atomic_read(&scf_started) != cpus)
+		barrier();
+
+	if (wait)
+		while (atomic_read(&scf_finished) != cpus)
+			barrier();
+
+	spin_unlock_bh(&call_lock);
+	return 0;
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/sys_call_table.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,483 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/unistd.h"
+#include "linux/version.h"
+#include "linux/sys.h"
+#include "linux/swap.h"
+#include "asm/signal.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_exit;
+extern syscall_handler_t sys_fork;
+extern syscall_handler_t sys_creat;
+extern syscall_handler_t sys_link;
+extern syscall_handler_t sys_unlink;
+extern syscall_handler_t sys_chdir;
+extern syscall_handler_t sys_mknod;
+extern syscall_handler_t sys_chmod;
+extern syscall_handler_t sys_lchown16;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_stat;
+extern syscall_handler_t sys_getpid;
+extern syscall_handler_t sys_oldumount;
+extern syscall_handler_t sys_setuid16;
+extern syscall_handler_t sys_getuid16;
+extern syscall_handler_t sys_ptrace;
+extern syscall_handler_t sys_alarm;
+extern syscall_handler_t sys_fstat;
+extern syscall_handler_t sys_pause;
+extern syscall_handler_t sys_utime;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_access;
+extern syscall_handler_t sys_nice;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_sync;
+extern syscall_handler_t sys_kill;
+extern syscall_handler_t sys_rename;
+extern syscall_handler_t sys_mkdir;
+extern syscall_handler_t sys_rmdir;
+extern syscall_handler_t sys_pipe;
+extern syscall_handler_t sys_times;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_brk;
+extern syscall_handler_t sys_setgid16;
+extern syscall_handler_t sys_getgid16;
+extern syscall_handler_t sys_signal;
+extern syscall_handler_t sys_geteuid16;
+extern syscall_handler_t sys_getegid16;
+extern syscall_handler_t sys_acct;
+extern syscall_handler_t sys_umount;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ioctl;
+extern syscall_handler_t sys_fcntl;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_setpgid;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_olduname;
+extern syscall_handler_t sys_umask;
+extern syscall_handler_t sys_chroot;
+extern syscall_handler_t sys_ustat;
+extern syscall_handler_t sys_dup2;
+extern syscall_handler_t sys_getppid;
+extern syscall_handler_t sys_getpgrp;
+extern syscall_handler_t sys_sigaction;
+extern syscall_handler_t sys_sgetmask;
+extern syscall_handler_t sys_ssetmask;
+extern syscall_handler_t sys_setreuid16;
+extern syscall_handler_t sys_setregid16;
+extern syscall_handler_t sys_sigsuspend;
+extern syscall_handler_t sys_sigpending;
+extern syscall_handler_t sys_sethostname;
+extern syscall_handler_t sys_setrlimit;
+extern syscall_handler_t sys_old_getrlimit;
+extern syscall_handler_t sys_getrusage;
+extern syscall_handler_t sys_gettimeofday;
+extern syscall_handler_t sys_settimeofday;
+extern syscall_handler_t sys_getgroups16;
+extern syscall_handler_t sys_setgroups16;
+extern syscall_handler_t sys_symlink;
+extern syscall_handler_t sys_lstat;
+extern syscall_handler_t sys_readlink;
+extern syscall_handler_t sys_uselib;
+extern syscall_handler_t sys_reboot;
+extern syscall_handler_t old_readdir;
+extern syscall_handler_t sys_munmap;
+extern syscall_handler_t sys_truncate;
+extern syscall_handler_t sys_ftruncate;
+extern syscall_handler_t sys_fchmod;
+extern syscall_handler_t sys_fchown16;
+extern syscall_handler_t sys_getpriority;
+extern syscall_handler_t sys_setpriority;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_statfs;
+extern syscall_handler_t sys_fstatfs;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_socketcall;
+extern syscall_handler_t sys_syslog;
+extern syscall_handler_t sys_setitimer;
+extern syscall_handler_t sys_getitimer;
+extern syscall_handler_t sys_newstat;
+extern syscall_handler_t sys_newlstat;
+extern syscall_handler_t sys_newfstat;
+extern syscall_handler_t sys_uname;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_vhangup;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_sysinfo;
+extern syscall_handler_t sys_ipc;
+extern syscall_handler_t sys_fsync;
+extern syscall_handler_t sys_sigreturn;
+extern syscall_handler_t sys_rt_sigreturn;
+extern syscall_handler_t sys_clone;
+extern syscall_handler_t sys_setdomainname;
+extern syscall_handler_t sys_newuname;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_adjtimex;
+extern syscall_handler_t sys_mprotect;
+extern syscall_handler_t sys_sigprocmask;
+extern syscall_handler_t sys_create_module;
+extern syscall_handler_t sys_init_module;
+extern syscall_handler_t sys_delete_module;
+extern syscall_handler_t sys_get_kernel_syms;
+extern syscall_handler_t sys_quotactl;
+extern syscall_handler_t sys_getpgid;
+extern syscall_handler_t sys_fchdir;
+extern syscall_handler_t sys_bdflush;
+extern syscall_handler_t sys_sysfs;
+extern syscall_handler_t sys_personality;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_setfsuid16;
+extern syscall_handler_t sys_setfsgid16;
+extern syscall_handler_t sys_llseek;
+extern syscall_handler_t sys_getdents;
+extern syscall_handler_t sys_flock;
+extern syscall_handler_t sys_msync;
+extern syscall_handler_t sys_readv;
+extern syscall_handler_t sys_writev;
+extern syscall_handler_t sys_getsid;
+extern syscall_handler_t sys_fdatasync;
+extern syscall_handler_t sys_mlock;
+extern syscall_handler_t sys_munlock;
+extern syscall_handler_t sys_mlockall;
+extern syscall_handler_t sys_munlockall;
+extern syscall_handler_t sys_sched_setparam;
+extern syscall_handler_t sys_sched_getparam;
+extern syscall_handler_t sys_sched_setscheduler;
+extern syscall_handler_t sys_sched_getscheduler;
+extern syscall_handler_t sys_sched_get_priority_max;
+extern syscall_handler_t sys_sched_get_priority_min;
+extern syscall_handler_t sys_sched_rr_get_interval;
+extern syscall_handler_t sys_nanosleep;
+extern syscall_handler_t sys_mremap;
+extern syscall_handler_t sys_setresuid16;
+extern syscall_handler_t sys_getresuid16;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_query_module;
+extern syscall_handler_t sys_poll;
+extern syscall_handler_t sys_nfsservctl;
+extern syscall_handler_t sys_setresgid16;
+extern syscall_handler_t sys_getresgid16;
+extern syscall_handler_t sys_prctl;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_rt_sigaction;
+extern syscall_handler_t sys_rt_sigprocmask;
+extern syscall_handler_t sys_rt_sigpending;
+extern syscall_handler_t sys_rt_sigtimedwait;
+extern syscall_handler_t sys_rt_sigqueueinfo;
+extern syscall_handler_t sys_rt_sigsuspend;
+extern syscall_handler_t sys_pread64;
+extern syscall_handler_t sys_pwrite64;
+extern syscall_handler_t sys_chown16;
+extern syscall_handler_t sys_getcwd;
+extern syscall_handler_t sys_capget;
+extern syscall_handler_t sys_capset;
+extern syscall_handler_t sys_sigaltstack;
+extern syscall_handler_t sys_sendfile;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_ni_syscall;
+extern syscall_handler_t sys_vfork;
+extern syscall_handler_t sys_getrlimit;
+extern syscall_handler_t sys_mmap2;
+extern syscall_handler_t sys_truncate64;
+extern syscall_handler_t sys_ftruncate64;
+extern syscall_handler_t sys_stat64;
+extern syscall_handler_t sys_lstat64;
+extern syscall_handler_t sys_fstat64;
+extern syscall_handler_t sys_lchown;
+extern syscall_handler_t sys_getuid;
+extern syscall_handler_t sys_getgid;
+extern syscall_handler_t sys_geteuid;
+extern syscall_handler_t sys_getegid;
+extern syscall_handler_t sys_setreuid;
+extern syscall_handler_t sys_setregid;
+extern syscall_handler_t sys_getgroups;
+extern syscall_handler_t sys_setgroups;
+extern syscall_handler_t sys_fchown;
+extern syscall_handler_t sys_setresuid;
+extern syscall_handler_t sys_getresuid;
+extern syscall_handler_t sys_setresgid;
+extern syscall_handler_t sys_getresgid;
+extern syscall_handler_t sys_chown;
+extern syscall_handler_t sys_setuid;
+extern syscall_handler_t sys_setgid;
+extern syscall_handler_t sys_setfsuid;
+extern syscall_handler_t sys_setfsgid;
+extern syscall_handler_t sys_pivot_root;
+extern syscall_handler_t sys_mincore;
+extern syscall_handler_t sys_madvise;
+extern syscall_handler_t sys_fcntl64;
+extern syscall_handler_t sys_getdents64;
+extern syscall_handler_t sys_security;
+extern syscall_handler_t sys_gettid;
+extern syscall_handler_t sys_readahead;
+extern syscall_handler_t sys_tkill;
+extern syscall_handler_t sys_sendfile64;
+extern syscall_handler_t sys_futex;
+extern syscall_handler_t sys_sched_setaffinity;
+extern syscall_handler_t sys_sched_getaffinity;
+
+#if CONFIG_NFSD
+#define NFSSERVCTL sys_nfsserctl
+#else
+#define NFSSERVCTL sys_ni_syscall
+#endif
+
+extern syscall_handler_t um_mount;
+extern syscall_handler_t um_time;
+extern syscall_handler_t um_stime;
+
+#define LAST_GENERIC_SYSCALL __NR_sched_getaffinity
+
+#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+#define LAST_SYSCALL LAST_GENERIC_SYSCALL
+#else
+#define LAST_SYSCALL LAST_ARCH_SYSCALL
+#endif
+
+syscall_handler_t *sys_call_table[] = {
+	[ 0 ] = sys_ni_syscall,
+	[ __NR_exit ] = sys_exit,
+	[ __NR_fork ] = sys_fork,
+	[ __NR_read ] = (syscall_handler_t *) sys_read,
+	[ __NR_write ] = (syscall_handler_t *) sys_write,
+
+	/* These three are declared differently in asm/unistd.h */
+	[ __NR_open ] = (syscall_handler_t *) sys_open,
+	[ __NR_close ] = (syscall_handler_t *) sys_close,
+	[ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid,
+	[ __NR_creat ] = sys_creat,
+	[ __NR_link ] = sys_link,
+	[ __NR_unlink ] = sys_unlink,
+
+	/* declared differently in kern_util.h */
+	[ __NR_execve ] = (syscall_handler_t *) sys_execve,
+	[ __NR_chdir ] = sys_chdir,
+	[ __NR_time ] = um_time,
+	[ __NR_mknod ] = sys_mknod,
+	[ __NR_chmod ] = sys_chmod,
+	[ __NR_lchown ] = sys_lchown16,
+	[ __NR_break ] = sys_ni_syscall,
+	[ __NR_oldstat ] = sys_stat,
+	[ __NR_lseek ] = (syscall_handler_t *) sys_lseek,
+	[ __NR_getpid ] = sys_getpid,
+	[ __NR_mount ] = um_mount,
+	[ __NR_umount ] = sys_oldumount,
+	[ __NR_setuid ] = sys_setuid16,
+	[ __NR_getuid ] = sys_getuid16,
+	[ __NR_stime ] = um_stime,
+	[ __NR_ptrace ] = sys_ptrace,
+	[ __NR_alarm ] = sys_alarm,
+	[ __NR_oldfstat ] = sys_fstat,
+	[ __NR_pause ] = sys_pause,
+	[ __NR_utime ] = sys_utime,
+	[ __NR_stty ] = sys_ni_syscall,
+	[ __NR_gtty ] = sys_ni_syscall,
+	[ __NR_access ] = sys_access,
+	[ __NR_nice ] = sys_nice,
+	[ __NR_ftime ] = sys_ni_syscall,
+	[ __NR_sync ] = sys_sync,
+	[ __NR_kill ] = sys_kill,
+	[ __NR_rename ] = sys_rename,
+	[ __NR_mkdir ] = sys_mkdir,
+	[ __NR_rmdir ] = sys_rmdir,
+
+	/* Declared differently in asm/unistd.h */
+	[ __NR_dup ] = (syscall_handler_t *) sys_dup,
+	[ __NR_pipe ] = sys_pipe,
+	[ __NR_times ] = sys_times,
+	[ __NR_prof ] = sys_ni_syscall,
+	[ __NR_brk ] = sys_brk,
+	[ __NR_setgid ] = sys_setgid16,
+	[ __NR_getgid ] = sys_getgid16,
+	[ __NR_signal ] = sys_signal,
+	[ __NR_geteuid ] = sys_geteuid16,
+	[ __NR_getegid ] = sys_getegid16,
+	[ __NR_acct ] = sys_acct,
+	[ __NR_umount2 ] = sys_umount,
+	[ __NR_lock ] = sys_ni_syscall,
+	[ __NR_ioctl ] = sys_ioctl,
+	[ __NR_fcntl ] = sys_fcntl,
+	[ __NR_mpx ] = sys_ni_syscall,
+	[ __NR_setpgid ] = sys_setpgid,
+	[ __NR_ulimit ] = sys_ni_syscall,
+	[ __NR_oldolduname ] = sys_olduname,
+	[ __NR_umask ] = sys_umask,
+	[ __NR_chroot ] = sys_chroot,
+	[ __NR_ustat ] = sys_ustat,
+	[ __NR_dup2 ] = sys_dup2,
+	[ __NR_getppid ] = sys_getppid,
+	[ __NR_getpgrp ] = sys_getpgrp,
+	[ __NR_setsid ] = (syscall_handler_t *) sys_setsid,
+	[ __NR_sigaction ] = sys_sigaction,
+	[ __NR_sgetmask ] = sys_sgetmask,
+	[ __NR_ssetmask ] = sys_ssetmask,
+	[ __NR_setreuid ] = sys_setreuid16,
+	[ __NR_setregid ] = sys_setregid16,
+	[ __NR_sigsuspend ] = sys_sigsuspend,
+	[ __NR_sigpending ] = sys_sigpending,
+	[ __NR_sethostname ] = sys_sethostname,
+	[ __NR_setrlimit ] = sys_setrlimit,
+	[ __NR_getrlimit ] = sys_old_getrlimit,
+	[ __NR_getrusage ] = sys_getrusage,
+	[ __NR_gettimeofday ] = sys_gettimeofday,
+	[ __NR_settimeofday ] = sys_settimeofday,
+	[ __NR_getgroups ] = sys_getgroups16,
+	[ __NR_setgroups ] = sys_setgroups16,
+	[ __NR_symlink ] = sys_symlink,
+	[ __NR_oldlstat ] = sys_lstat,
+	[ __NR_readlink ] = sys_readlink,
+	[ __NR_uselib ] = sys_uselib,
+	[ __NR_swapon ] = (syscall_handler_t *) sys_swapon,
+	[ __NR_reboot ] = sys_reboot,
+	[ __NR_readdir ] = old_readdir,
+	[ __NR_munmap ] = sys_munmap,
+	[ __NR_truncate ] = sys_truncate,
+	[ __NR_ftruncate ] = sys_ftruncate,
+	[ __NR_fchmod ] = sys_fchmod,
+	[ __NR_fchown ] = sys_fchown16,
+	[ __NR_getpriority ] = sys_getpriority,
+	[ __NR_setpriority ] = sys_setpriority,
+	[ __NR_profil ] = sys_ni_syscall,
+	[ __NR_statfs ] = sys_statfs,
+	[ __NR_fstatfs ] = sys_fstatfs,
+	[ __NR_ioperm ] = sys_ni_syscall,
+	[ __NR_socketcall ] = sys_socketcall,
+	[ __NR_syslog ] = sys_syslog,
+	[ __NR_setitimer ] = sys_setitimer,
+	[ __NR_getitimer ] = sys_getitimer,
+	[ __NR_stat ] = sys_newstat,
+	[ __NR_lstat ] = sys_newlstat,
+	[ __NR_fstat ] = sys_newfstat,
+	[ __NR_olduname ] = sys_uname,
+	[ __NR_iopl ] = sys_ni_syscall,
+	[ __NR_vhangup ] = sys_vhangup,
+	[ __NR_idle ] = sys_ni_syscall,
+	[ __NR_wait4 ] = (syscall_handler_t *) sys_wait4,
+	[ __NR_swapoff ] = (syscall_handler_t *) sys_swapoff,
+	[ __NR_sysinfo ] = sys_sysinfo,
+	[ __NR_ipc ] = sys_ipc,
+	[ __NR_fsync ] = sys_fsync,
+	[ __NR_sigreturn ] = sys_sigreturn,
+	[ __NR_clone ] = sys_clone,
+	[ __NR_setdomainname ] = sys_setdomainname,
+	[ __NR_uname ] = sys_newuname,
+	[ __NR_adjtimex ] = sys_adjtimex,
+	[ __NR_mprotect ] = sys_mprotect,
+	[ __NR_sigprocmask ] = sys_sigprocmask,
+	[ __NR_create_module ] = sys_create_module,
+	[ __NR_init_module ] = sys_init_module,
+	[ __NR_delete_module ] = sys_delete_module,
+	[ __NR_get_kernel_syms ] = sys_get_kernel_syms,
+	[ __NR_quotactl ] = sys_quotactl,
+	[ __NR_getpgid ] = sys_getpgid,
+	[ __NR_fchdir ] = sys_fchdir,
+	[ __NR_bdflush ] = sys_bdflush,
+	[ __NR_sysfs ] = sys_sysfs,
+	[ __NR_personality ] = sys_personality,
+	[ __NR_afs_syscall ] = sys_ni_syscall,
+	[ __NR_setfsuid ] = sys_setfsuid16,
+	[ __NR_setfsgid ] = sys_setfsgid16,
+	[ __NR__llseek ] = sys_llseek,
+	[ __NR_getdents ] = sys_getdents,
+	[ __NR__newselect ] = (syscall_handler_t *) sys_select,
+	[ __NR_flock ] = sys_flock,
+	[ __NR_msync ] = sys_msync,
+	[ __NR_readv ] = sys_readv,
+	[ __NR_writev ] = sys_writev,
+	[ __NR_getsid ] = sys_getsid,
+	[ __NR_fdatasync ] = sys_fdatasync,
+	[ __NR__sysctl ] = (syscall_handler_t *) sys_sysctl,
+	[ __NR_mlock ] = sys_mlock,
+	[ __NR_munlock ] = sys_munlock,
+	[ __NR_mlockall ] = sys_mlockall,
+	[ __NR_munlockall ] = sys_munlockall,
+	[ __NR_sched_setparam ] = sys_sched_setparam,
+	[ __NR_sched_getparam ] = sys_sched_getparam,
+	[ __NR_sched_setscheduler ] = sys_sched_setscheduler,
+	[ __NR_sched_getscheduler ] = sys_sched_getscheduler,
+	[ __NR_sched_yield ] = (syscall_handler_t *) yield,
+	[ __NR_sched_get_priority_max ] = sys_sched_get_priority_max,
+	[ __NR_sched_get_priority_min ] = sys_sched_get_priority_min,
+	[ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval,
+	[ __NR_nanosleep ] = sys_nanosleep,
+	[ __NR_mremap ] = sys_mremap,
+	[ __NR_setresuid ] = sys_setresuid16,
+	[ __NR_getresuid ] = sys_getresuid16,
+	[ __NR_vm86 ] = sys_ni_syscall,
+	[ __NR_query_module ] = sys_query_module,
+	[ __NR_poll ] = sys_poll,
+	[ __NR_nfsservctl ] = NFSSERVCTL,
+	[ __NR_setresgid ] = sys_setresgid16,
+	[ __NR_getresgid ] = sys_getresgid16,
+	[ __NR_prctl ] = sys_prctl,
+	[ __NR_rt_sigreturn ] = sys_rt_sigreturn,
+	[ __NR_rt_sigaction ] = sys_rt_sigaction,
+	[ __NR_rt_sigprocmask ] = sys_rt_sigprocmask,
+	[ __NR_rt_sigpending ] = sys_rt_sigpending,
+	[ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait,
+	[ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo,
+	[ __NR_rt_sigsuspend ] = sys_rt_sigsuspend,
+	[ __NR_pread64 ] = sys_pread64,
+	[ __NR_pwrite64 ] = sys_pwrite64,
+	[ __NR_chown ] = sys_chown16,
+	[ __NR_getcwd ] = sys_getcwd,
+	[ __NR_capget ] = sys_capget,
+	[ __NR_capset ] = sys_capset,
+	[ __NR_sigaltstack ] = sys_sigaltstack,
+	[ __NR_sendfile ] = sys_sendfile,
+	[ __NR_getpmsg ] = sys_ni_syscall,
+	[ __NR_putpmsg ] = sys_ni_syscall,
+	[ __NR_vfork ] = sys_vfork,
+	[ __NR_ugetrlimit ] = sys_getrlimit,
+	[ __NR_mmap2 ] = sys_mmap2,
+	[ __NR_truncate64 ] = sys_truncate64,
+	[ __NR_ftruncate64 ] = sys_ftruncate64,
+	[ __NR_stat64 ] = sys_stat64,
+	[ __NR_lstat64 ] = sys_lstat64,
+	[ __NR_fstat64 ] = sys_fstat64,
+	[ __NR_fcntl64 ] = sys_fcntl64,
+	[ __NR_getdents64 ] = sys_getdents64,
+        [ __NR_security ] = sys_security,
+	[ __NR_gettid ] = sys_gettid,
+	[ __NR_readahead ] = sys_readahead,
+	[ __NR_setxattr ] = sys_ni_syscall,
+	[ __NR_lsetxattr ] = sys_ni_syscall,
+	[ __NR_fsetxattr ] = sys_ni_syscall,
+	[ __NR_getxattr ] = sys_ni_syscall,
+	[ __NR_lgetxattr ] = sys_ni_syscall,
+	[ __NR_fgetxattr ] = sys_ni_syscall,
+	[ __NR_listxattr ] = sys_ni_syscall,
+	[ __NR_llistxattr ] = sys_ni_syscall,
+	[ __NR_flistxattr ] = sys_ni_syscall,
+	[ __NR_removexattr ] = sys_ni_syscall,
+	[ __NR_lremovexattr ] = sys_ni_syscall,
+	[ __NR_fremovexattr ] = sys_ni_syscall,
+	[ __NR_tkill ] = sys_tkill,
+	[ __NR_sendfile64 ] = sys_sendfile64,
+	[ __NR_futex ] = sys_futex,
+	[ __NR_sched_setaffinity ] = sys_sched_setaffinity,
+	[ __NR_sched_getaffinity ] = sys_sched_getaffinity,
+
+	ARCH_SYSCALLS
+	[ LAST_SYSCALL + 1 ... NR_syscalls ] = 
+	        (syscall_handler_t *) sys_ni_syscall
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/syscall_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,439 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/file.h"
+#include "linux/smp_lock.h"
+#include "linux/mm.h"
+#include "linux/utsname.h"
+#include "linux/msg.h"
+#include "linux/shm.h"
+#include "linux/sys.h"
+#include "linux/unistd.h"
+#include "linux/slab.h"
+#include "linux/utime.h"
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/ipc.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "sysdep/syscalls.h"
+
+long um_mount(char * dev_name, char * dir_name, char * type,
+	      unsigned long new_flags, void * data)
+{
+	if(type == NULL) type = "";
+	return(sys_mount(dev_name, dir_name, type, new_flags, data));
+}
+
+long sys_fork(void)
+{
+	struct task_struct *p;
+
+	current->thread.forking = 1;
+        p = do_fork(SIGCHLD, 0, NULL, 0, NULL);
+	current->thread.forking = 0;
+	return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+}
+
+long sys_clone(unsigned long clone_flags, unsigned long newsp)
+{
+	struct task_struct *p;
+
+	current->thread.forking = 1;
+	p = do_fork(clone_flags, newsp, NULL, 0, NULL);
+	current->thread.forking = 0;
+	return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+}
+
+long sys_vfork(void)
+{
+	struct task_struct *p;
+
+	current->thread.forking = 1;
+	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL);
+	current->thread.forking = 0;
+	return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
+}
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+	unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+ out:
+	return error;
+}
+
+long sys_mmap2(unsigned long addr, unsigned long len,
+	       unsigned long prot, unsigned long flags,
+	       unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+int old_mmap(unsigned long addr, unsigned long len,
+	     unsigned long prot, unsigned long flags,
+	     unsigned long fd, unsigned long offset)
+{
+	int err = -EINVAL;
+	if (offset & ~PAGE_MASK)
+		goto out;
+
+	err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+ out:
+	return err;
+}
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+int sys_pipe(unsigned long * fildes)
+{
+        int fd[2];
+        int error;
+
+        error = do_pipe(fd);
+        if (!error) {
+                if (copy_to_user(fildes, fd, 2*sizeof(int)))
+                        error = -EFAULT;
+        }
+        return error;
+}
+
+int sys_sigaction(int sig, const struct old_sigaction *act,
+			 struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+int sys_ipc (uint call, int first, int second,
+	     int third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	case SEMOP:
+		return sys_semop (first, (struct sembuf *)ptr, second);
+	case SEMGET:
+		return sys_semget (first, second, third);
+	case SEMCTL: {
+		union semun fourth;
+		if (!ptr)
+			return -EINVAL;
+		if (get_user(fourth.__pad, (void **) ptr))
+			return -EFAULT;
+		return sys_semctl (first, second, third, fourth);
+	}
+
+	case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+				   second, third);
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+			if (!ptr)
+				return -EINVAL;
+			
+			if (copy_from_user(&tmp,
+					   (struct ipc_kludge *) ptr, 
+					   sizeof (tmp)))
+				return -EFAULT;
+			return sys_msgrcv (first, tmp.msgp, second,
+					   tmp.msgtyp, third);
+		}
+		default:
+		        panic("msgrcv with version != 0");
+			return sys_msgrcv (first,
+					   (struct msgbuf *) ptr,
+					   second, fifth, third);
+		}
+	case MSGGET:
+		return sys_msgget ((key_t) first, second);
+	case MSGCTL:
+		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				return ret;
+			return put_user (raddr, (ulong *) third);
+		}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				return -EINVAL;
+			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+		}
+	case SHMDT: 
+		return sys_shmdt ((char *)ptr);
+	case SHMGET:
+		return sys_shmget (first, second, third);
+	case SHMCTL:
+		return sys_shmctl (first, second,
+				   (struct shmid_ds *) ptr);
+	default:
+		return -EINVAL;
+	}
+}
+
+int sys_uname(struct old_utsname * name)
+{
+	int err;
+	if (!name)
+		return -EFAULT;
+	down_read(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up_read(&uts_sem);
+	return err?-EFAULT:0;
+}
+
+int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+  	down_read(&uts_sem);
+	
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,
+			       __OLD_UTS_LEN);
+	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->release,&system_utsname.release,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->release+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->version,&system_utsname.version,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->version+__OLD_UTS_LEN);
+	error |= __copy_to_user(&name->machine,&system_utsname.machine,
+				__OLD_UTS_LEN);
+	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+	
+	up_read(&uts_sem);
+	
+	error = error ? -EFAULT : 0;
+
+	return error;
+}
+
+int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+	return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
+}
+
+static inline int check_area(void *ptr, int size)
+{
+	return(verify_area(VERIFY_WRITE, ptr, size));
+}
+
+static int check_readlink(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[1], regs->regs.args[2]));
+}
+
+static int check_utime(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[1],
+			  sizeof(struct utimbuf)));
+}
+
+static int check_oldstat(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[1], 
+			  sizeof(struct __old_kernel_stat)));
+}
+
+static int check_stat(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[1], sizeof(struct stat)));
+}
+
+static int check_stat64(struct pt_regs *regs)
+{
+	return(check_area((void *) regs->regs.args[1], sizeof(struct stat64)));
+}
+
+struct bogus {
+	int kernel_ds;
+	int (*check_params)(struct pt_regs *);
+};
+
+struct bogus this_is_bogus[256] = {
+	[ __NR_mknod ] = { 1, NULL },
+	[ __NR_mkdir ] = { 1, NULL },
+	[ __NR_rmdir ] = { 1, NULL },
+	[ __NR_unlink ] = { 1, NULL },
+	[ __NR_symlink ] = { 1, NULL },
+	[ __NR_link ] = { 1, NULL },
+	[ __NR_rename ] = { 1, NULL },
+	[ __NR_umount ] = { 1, NULL },
+	[ __NR_mount ] = { 1, NULL },
+	[ __NR_pivot_root ] = { 1, NULL },
+	[ __NR_chdir ] = { 1, NULL },
+	[ __NR_chroot ] = { 1, NULL },
+	[ __NR_open ] = { 1, NULL },
+	[ __NR_quotactl ] = { 1, NULL },
+	[ __NR_sysfs ] = { 1, NULL },
+	[ __NR_readlink ] = { 1, check_readlink },
+	[ __NR_acct ] = { 1, NULL },
+	[ __NR_execve ] = { 1, NULL },
+	[ __NR_uselib ] = { 1, NULL },
+	[ __NR_statfs ] = { 1, NULL },
+	[ __NR_truncate ] = { 1, NULL },
+	[ __NR_access ] = { 1, NULL },
+	[ __NR_chmod ] = { 1, NULL },
+	[ __NR_chown ] = { 1, NULL },
+	[ __NR_lchown ] = { 1, NULL },
+	[ __NR_utime ] = { 1, check_utime },
+	[ __NR_oldlstat ] = { 1, check_oldstat },
+	[ __NR_oldstat ] = { 1, check_oldstat },
+	[ __NR_stat ] = { 1, check_stat },
+	[ __NR_lstat ] = { 1, check_stat },
+	[ __NR_stat64 ] = { 1, check_stat64 },
+	[ __NR_lstat64 ] = { 1, check_stat64 },
+	[ __NR_chown32 ] = { 1, NULL },
+};
+
+/* sys_utimes */
+
+static int check_bogosity(struct pt_regs *regs)
+{
+	struct bogus *bogon = &this_is_bogus[regs->regs.syscall];
+
+	if(!bogon->kernel_ds) return(0);
+	if(bogon->check_params && (*bogon->check_params)(regs))
+		return(-EFAULT);
+	set_fs(KERNEL_DS);
+	return(0);
+}
+
+int nsyscalls = 0;
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall(void *r)
+{
+	struct pt_regs *regs = r;
+	long res;
+	int syscall;
+
+	current->thread.nsyscalls++;
+	nsyscalls++;
+	syscall = regs->regs.syscall;
+
+	if((syscall >= NR_syscalls) || (syscall < 0))
+		res = -ENOSYS;
+	else if(honeypot && check_bogosity(regs))
+		res = -EFAULT;
+	else res = EXECUTE_SYSCALL(syscall, regs);
+
+	set_fs(USER_DS);
+
+	if(current->thread.singlestep_syscall){
+		current->thread.singlestep_syscall = 0;
+		current->ptrace &= ~PT_DTRACE;
+		force_sig(SIGTRAP, current);
+	}
+
+	return(res);
+}
+
+spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_syscall(void)
+{
+	spin_lock(&syscall_lock);
+}
+
+void unlock_syscall(void)
+{
+	spin_unlock(&syscall_lock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/syscall_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,116 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+/* XXX FIXME : Ensure that SIGIO and SIGVTALRM can't happen immediately
+ * after setting up syscall stack
+ * block SIGVTALRM in any code that's under wait_for_stop
+ */
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "ptrace_user.h"
+#include "task.h"
+#include "user_util.h"
+#include "kern_util.h"
+
+/* XXX Bogus */
+#define ERESTARTSYS	512
+#define ERESTARTNOINTR	513
+#define ERESTARTNOHAND	514
+
+struct {
+	int syscall;
+	int pid;
+	int result;
+	struct timeval start;
+	struct timeval end;
+} syscall_record[1024];
+
+int syscall_index = 0;
+
+extern int kern_timer_on;
+
+void syscall_handler(int sig, struct uml_pt_regs *regs)
+{
+	void *sc;
+	long result;
+	int index, syscall;
+
+	lock_syscall();
+	if(syscall_index == 1024) syscall_index = 0;
+	index = syscall_index;
+	syscall_index++;
+	unlock_syscall();
+
+	syscall = regs->syscall;
+	sc = regs->sc;
+	sc_to_regs(regs, sc, syscall);
+	SC_START_SYSCALL(sc);
+
+	syscall_record[index].syscall = syscall;
+	syscall_record[index].pid = current_pid();
+	syscall_record[index].result = 0xdeadbeef;
+	gettimeofday(&syscall_record[index].start, NULL);
+	syscall_trace();
+	result = execute_syscall(regs);
+
+	/* regs->sc may have changed while the system call ran (there may
+	 * have been an interrupt or segfault), so it needs to be refreshed.
+	 */
+	regs->sc = sc;
+
+	SC_SET_SYSCALL_RETURN(sc, result);
+	if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || 
+	   (result == -ERESTARTNOINTR))
+		do_signal(result);
+
+	syscall_trace();
+	syscall_record[index].result = result;
+	gettimeofday(&syscall_record[index].end, NULL);
+}
+
+int do_syscall(void *task, int pid)
+{
+	unsigned long proc_regs[FRAME_SIZE];
+	struct uml_pt_regs *regs;
+	int syscall;
+
+	if(ptrace_getregs(pid, proc_regs) < 0)
+		tracer_panic("Couldn't read registers");
+	syscall = PT_SYSCALL_NR(proc_regs);
+
+	regs = TASK_REGS(task);
+	UPT_SYSCALL_NR(regs) = syscall;
+
+	if(syscall < 1) return(0);
+
+	if((syscall != __NR_sigreturn) &&
+	   ((unsigned long *) PT_IP(proc_regs) >= &_stext) && 
+	   ((unsigned long *) PT_IP(proc_regs) <= &_etext))
+		tracer_panic("I'm tracing myself and I can't get out");
+
+	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+		  __NR_getpid) < 0)
+		tracer_panic("do_syscall : Nullifying syscall failed, "
+			     "errno = %d", errno);
+	return(1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/sysrq.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,98 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/kernel.h"
+#include "linux/module.h"
+#include "asm/page.h"
+#include "asm/processor.h"
+#include "sysrq.h"
+#include "user_util.h"
+
+ /*
+  * If the address is either in the .text section of the
+  * kernel, or in the vmalloc'ed module regions, it *may* 
+  * be the address of a calling routine
+  */
+ 
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	return (addr >= (unsigned long) &_stext &&
+		addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+void show_trace(unsigned long * stack)
+{
+        int i;
+        unsigned long addr;
+
+        if (!stack)
+                stack = (unsigned long*) &stack;
+
+        printk("Call Trace: ");
+        i = 1;
+        while (((long) stack & (THREAD_SIZE-1)) != 0) {
+                addr = *stack++;
+		if (kernel_text_address(addr)) {
+			if (i && ((i % 6) == 0))
+				printk("\n   ");
+			printk("[<%08lx>] ", addr);
+			i++;
+                }
+        }
+        printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	unsigned long esp = PT_REGS_SP(&tsk->thread.regs);
+
+	/* User space on another CPU? */
+	if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
+		return;
+	show_trace((unsigned long *)esp);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/time.c b/arch/um/kernel/time.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/time.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,121 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "process.h"
+#include "signal_user.h"
+
+extern struct timeval xtime;
+
+void timer_handler(int sig, struct uml_pt_regs *regs)
+{
+	timer_irq(regs);
+}
+
+void timer(void)
+{
+	gettimeofday(&xtime, NULL);
+}
+
+static struct itimerval profile_interval;
+
+void get_profile_timer(void)
+{
+	getitimer(ITIMER_PROF, &profile_interval);
+	profile_interval.it_value = profile_interval.it_interval;
+}
+
+void disable_profile_timer(void)
+{
+	struct itimerval interval = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+	setitimer(ITIMER_PROF, &interval, NULL);
+}
+
+static void set_interval(int timer_type)
+{
+	struct itimerval interval;
+
+	interval.it_interval.tv_sec = 0;
+	interval.it_interval.tv_usec = 1000000/hz();
+	interval.it_value.tv_sec = 0;
+	interval.it_value.tv_usec = 1000000/hz();
+	if(setitimer(timer_type, &interval, NULL) == -1)
+		panic("setitimer failed - errno = %d\n", errno);
+}
+
+void idle_timer(void)
+{
+	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+		panic("Couldn't unset SIGVTALRM handler");
+	set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
+		    SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_interval(ITIMER_REAL);
+}
+
+void user_time_init(void)
+{
+	if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+void time_init(void)
+{
+	if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+void set_timers(int set_signal)
+{
+	if(set_signal)
+		set_interval(ITIMER_VIRTUAL);
+	if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1)
+		panic("setitimer ITIMER_PROF failed - errno = %d\n", errno);
+}
+
+struct timeval local_offset = { 0, 0 };
+
+void do_gettimeofday(struct timeval *tv)
+{
+	gettimeofday(tv, NULL);
+	timeradd(tv, &local_offset, tv);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
+	timersub(tv, &now, &local_offset);
+}
+
+void idle_sleep(int secs)
+{
+	struct timespec ts;
+
+	ts.tv_sec = secs;
+	ts.tv_nsec = 0;
+	nanosleep(&ts, &ts);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/time_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,143 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/unistd.h"
+#include "linux/stddef.h"
+#include "linux/spinlock.h"
+#include "linux/sched.h"
+#include "linux/interrupt.h"
+#include "linux/init.h"
+#include "linux/delay.h"
+#include "asm/irq.h"
+#include "asm/param.h"
+#include "asm/current.h"
+#include "kern_util.h"
+#include "user_util.h"
+
+u64 jiffies_64;
+
+extern rwlock_t xtime_lock;
+
+int hz(void)
+{
+	return(HZ);
+}
+
+int timer_irq_inited = 0;
+
+/* kern_timer_on and missed_ticks are modified after kernel memory has been 
+ * write-protected, so this puts it in a section which will be left 
+ * write-enabled.
+ */
+int __attribute__ ((__section__ (".unprotected"))) kern_timer_on = 0;
+int __attribute__ ((__section__ (".unprotected"))) missed_ticks = 0;
+
+void timer_irq(struct uml_pt_regs *regs)
+{
+	int ticks = missed_ticks;
+
+        if(!timer_irq_inited) return;
+	missed_ticks = 0;
+	while(ticks--) do_IRQ(TIMER_IRQ, regs);
+}
+
+void boot_timer_handler(int sig)
+{
+	struct pt_regs regs;
+
+	regs.regs.is_user = 0;
+	do_timer(&regs);
+}
+
+void um_timer(int irq, void *dev, struct pt_regs *regs)
+{
+	do_timer(regs);
+	write_lock(&xtime_lock);
+	timer();
+	write_unlock(&xtime_lock);
+}
+
+long um_time(int * tloc)
+{
+	struct timeval now;
+
+	do_gettimeofday(&now);
+	if (tloc) {
+ 		if (put_user(now.tv_sec,tloc))
+			now.tv_sec = -EFAULT;
+	}
+	return now.tv_sec;
+}
+
+long um_stime(int * tptr)
+{
+	int value;
+	struct timeval new;
+
+	if (get_user(value, tptr))
+                return -EFAULT;
+	new.tv_sec = value;
+	new.tv_usec = 0;
+	do_settimeofday(&new);
+	return 0;
+}
+
+void __delay(um_udelay_t time)
+{
+	/* Stolen from the i386 __loop_delay */
+	int d0;
+	__asm__ __volatile__(
+		"\tjmp 1f\n"
+		".align 16\n"
+		"1:\tjmp 2f\n"
+		".align 16\n"
+		"2:\tdecl %0\n\tjns 2b"
+		:"=&a" (d0)
+		:"0" (time));
+}
+
+void __udelay(um_udelay_t usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / 1000000;
+	for(i=0;i<n;i++) ;
+}
+
+void __const_udelay(um_udelay_t usecs)
+{
+	int i, n;
+
+	n = (loops_per_jiffy * HZ * usecs) / 1000000;
+	for(i=0;i<n;i++) ;
+}
+
+int __init timer_init(void)
+{
+	int err;
+
+	user_time_init();
+	if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", 
+			      NULL)) != 0)
+		printk(KERN_ERR "timer_init : request_irq failed - "
+		       "errno = %d\n", -err);
+	timer_irq_inited = 1;
+	return(0);
+}
+
+__initcall(timer_init);
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/tlb.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,257 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/slab.h"
+#include "linux/bootmem.h"
+#include "asm-generic/tlb.h"
+#include "asm/pgtable.h"
+#include "asm/pgalloc.h"
+#include "asm/a.out.h"
+#include "asm/processor.h"
+#include "asm/mmu_context.h"
+#include "asm/uaccess.h"
+#include "asm/atomic.h"
+#include "mem_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "tlb.h"
+#include "os.h"
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
+		      unsigned long end_addr, int force)
+{
+	pgd_t *npgd;
+	pmd_t *npmd;
+	pte_t *npte;
+	unsigned long addr;
+	int r, w, x, err;
+
+	if((current->thread.extern_pid != -1) && 
+	   (current->thread.extern_pid != os_getpid()))
+		panic("fix_range fixing wrong address space, current = 0x%p",
+		      current);
+	if(mm == NULL) return;
+	for(addr=start_addr;addr<end_addr;){
+		if(addr == TASK_SIZE){
+			/* Skip over kernel text, kernel data, and physical
+			 * memory, which don't have ptes, plus kernel virtual
+			 * memory, which is flushed separately, and remap
+			 * the process stack.  The only way to get here is
+			 * if (end_addr == STACK_TOP) > TASK_SIZE, which is
+			 * only true in the honeypot case.
+			 */
+			addr = STACK_TOP - ABOVE_KMEM;
+			continue;
+		}
+		npgd = pgd_offset(mm, addr);
+		npmd = pmd_offset(npgd, addr);
+		if(pmd_present(*npmd)){
+			npte = pte_offset_kernel(npmd, addr);
+			r = pte_read(*npte);
+			w = pte_write(*npte);
+			x = pte_exec(*npte);
+			if(!pte_dirty(*npte)) w = 0;
+			if(!pte_young(*npte)){
+				r = 0;
+				w = 0;
+			}
+			if(force || pte_newpage(*npte)){
+				err = unmap((void *) addr, PAGE_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+				if(pte_present(*npte))
+					map(addr, pte_val(*npte) & PAGE_MASK,
+					    PAGE_SIZE, r, w, x);
+			}
+			else if(pte_newprot(*npte)){
+				protect(addr, PAGE_SIZE, r, w, x, 1);
+			}
+			*npte = pte_mkuptodate(*npte);
+			addr += PAGE_SIZE;
+		}
+		else {
+			if(force || pmd_newpage(*npmd)){
+				err = unmap((void *) addr, PMD_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+				pmd_mkuptodate(*npmd);
+			}
+			addr += PMD_SIZE;
+		}
+	}
+}
+
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
+void flush_kernel_range(unsigned long start, unsigned long end, int update_seq)
+{
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	int updated = 0, err;
+
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pmd = pmd_offset(pgd, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset_kernel(pmd, addr);
+			if(!pte_present(*pte) || pte_newpage(*pte)){
+				updated = 1;
+				err = unmap((void *) addr, PAGE_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+				if(pte_present(*pte))
+					map(addr, pte_val(*pte) & PAGE_MASK,
+					    PAGE_SIZE, 1, 1, 1);
+			}
+			else if(pte_newprot(*pte)){
+				updated = 1;
+				protect(addr, PAGE_SIZE, 1, 1, 1, 1);
+			}
+			addr += PAGE_SIZE;
+		}
+		else {
+			if(pmd_newpage(*pmd)){
+				updated = 1;
+				err = unmap((void *) addr, PMD_SIZE);
+				if(err < 0)
+					panic("munmap failed, errno = %d\n",
+					      -err);
+			}
+			addr += PMD_SIZE;
+		}
+	}
+	if(updated && update_seq) atomic_inc(&vmchange_seq);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+	flush_kernel_range(start, end, 1);
+}
+
+static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+{
+	int err;
+
+	err = protect(addr, PAGE_SIZE, 1, w, 1, must_succeed);
+	if(err == 0) return;
+	else if((err == -EFAULT) || (err == -ENOMEM)){
+		flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+		protect_vm_page(addr, w, 1);
+	}
+	else panic("protect_vm_page : protect failed, errno = %d\n", err);
+}
+
+void mprotect_kernel_vm(int w)
+{
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pmd = pmd_offset(pgd, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset_kernel(pmd, addr);
+			if(pte_present(*pte)) protect_vm_page(addr, w, 0);
+			addr += PAGE_SIZE;
+		}
+		else addr += PMD_SIZE;
+	}
+}
+
+void flush_tlb_kernel_vm(void)
+{
+	flush_tlb_kernel_range(start_vm, end_vm);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
+		     unsigned long end)
+{
+	if(vma->vm_mm != current->mm) 
+		return;
+
+	/* Assumes that the range start ... end is entirely within
+	 * either process memory or kernel vm
+	 */
+	if((start >= start_vm) && (start < end_vm)) 
+		flush_kernel_range(start, end, 1);
+	else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	unsigned long seq;
+
+	if(mm != current->mm) 
+		return;
+
+	fix_range(mm, 0, STACK_TOP, 0);
+
+	seq = atomic_read(&vmchange_seq);
+	if(current->thread.vm_seq == seq) return;
+	current->thread.vm_seq = seq;
+	flush_kernel_range(start_vm, end_vm, 0);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+	address &= PAGE_MASK;
+	flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+	flush_tlb_mm(current->mm);
+}
+
+void force_flush_all(void)
+{
+	fix_range(current->mm, 0, STACK_TOP, 1);
+	flush_kernel_range(start_vm, end_vm, 0);
+}
+
+pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
+{
+	return(pgd_offset(mm, address));
+}
+
+pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address)
+{
+	return(pmd_offset(pgd, address));
+}
+
+pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address)
+{
+	return(pte_offset_kernel(pmd, address));
+}
+
+pte_t *addr_pte(struct task_struct *task, unsigned long addr)
+{
+	return(pte_offset_kernel(pmd_offset(pgd_offset(task->mm, addr), addr), 
+				 addr));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/trap_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,435 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "linux/spinlock.h"
+#include "linux/config.h"
+#include "linux/init.h"
+#include "linux/ptrace.h"
+#include "asm/semaphore.h"
+#include "asm/pgtable.h"
+#include "asm/tlbflush.h"
+#include "asm/a.out.h"
+#include "asm/current.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "chan_kern.h"
+#include "debug.h"
+#include "mconsole_kern.h"
+#include "2_5compat.h"
+
+extern int nsyscalls;
+
+unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
+		   int is_user, void *sc)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	struct siginfo si;
+	void *catcher;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long page;
+
+	if((address >= start_vm) && (address < end_vm)){
+		flush_tlb_kernel_vm();
+		return(0);
+	}
+	if(mm == NULL) panic("Segfault with no mm");
+	catcher = current->thread.fault_catcher;
+	si.si_code = SEGV_MAPERR;
+	down_read(&mm->mmap_sem);
+	vma = find_vma(mm, address);
+	if(!vma) goto bad;
+	else if(vma->vm_start <= address) goto good_area;
+	else if(!(vma->vm_flags & VM_GROWSDOWN)) goto bad;
+	else if(expand_stack(vma, address)) goto bad;
+
+ good_area:
+	si.si_code = SEGV_ACCERR;
+	if(is_write && !(vma->vm_flags & VM_WRITE)) goto bad;
+	page = address & PAGE_MASK;
+	if(page == (unsigned long) current->thread_info + PAGE_SIZE)
+		panic("Kernel stack overflow");
+	pgd = pgd_offset(mm, page);
+	pmd = pmd_offset(pgd, page);
+ survive:
+	do {
+		switch (handle_mm_fault(mm, vma, address, is_write)){
+		case VM_FAULT_MINOR:
+			current->min_flt++;
+			break;
+		case VM_FAULT_MAJOR:
+			current->maj_flt++;
+			break;
+		case VM_FAULT_SIGBUS:
+			goto do_sigbus;
+		case VM_FAULT_OOM:
+			goto out_of_memory;
+		default:
+			BUG();
+		}
+		pte = pte_offset_kernel(pmd, page);
+	} while(!pte_present(*pte));
+	*pte = pte_mkyoung(*pte);
+	if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
+	flush_tlb_page(vma, page);
+	up_read(&mm->mmap_sem);
+	return(0);
+do_sigbus:
+	up_read(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	si.si_signo = SIGBUS;
+	si.si_errno = 0;
+	si.si_code = BUS_ADRERR;
+	si.si_addr = (void *)address;
+	force_sig_info(SIGBUS, &si, current);
+	if(!is_user) goto bad;
+	return(0);
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
+	printk("VM: killing process %s\n", current->comm);
+	if(is_user)
+		do_exit(SIGKILL);
+
+	/* Fall through to bad */
+
+ bad:
+	if(catcher != NULL){
+		current->thread.fault_addr = (void *) address;
+		up_read(&mm->mmap_sem);
+		do_longjmp(catcher);
+	} 
+	else if(current->thread.fault_addr != NULL){
+		panic("fault_addr set but no fault catcher");
+	}
+	else if(arch_fixup(ip, sc))
+		return(0);
+
+	if(!is_user) 
+		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
+		      address, ip);
+	si.si_signo = SIGSEGV;
+	si.si_addr = (void *) address;
+	current->thread.cr2 = address;
+	current->thread.err = is_write;
+	force_sig_info(SIGSEGV, &si, current);
+	up_read(&mm->mmap_sem);
+	return(0);
+}
+
+void bad_segv(unsigned long address, unsigned long ip, int is_write)
+{
+	struct siginfo si;
+
+	printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
+	       "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
+	si.si_signo = SIGSEGV;
+	si.si_code = SEGV_ACCERR;
+	si.si_addr = (void *) address;
+	current->thread.cr2 = address;
+	current->thread.err = is_write;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+void relay_signal(int sig, struct uml_pt_regs *regs)
+{
+	if(arch_handle_signal(sig, regs)) return;
+	if(!regs->is_user) panic("Kernel mode signal %d", sig);
+	force_sig(sig, current);
+}
+
+void bus_handler(int sig, struct uml_pt_regs *regs)
+{
+	if(current->thread.fault_catcher != NULL)
+		do_longjmp(current->thread.fault_catcher);
+	else relay_signal(sig, regs);
+}
+
+void trap_init(void)
+{
+}
+
+spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_trap(void)
+{
+	spin_lock(&trap_lock);
+}
+
+void unlock_trap(void)
+{
+	spin_unlock(&trap_lock);
+}
+
+extern int debugger_pid;
+extern int debugger_fd;
+extern int debugger_parent;
+
+#ifdef CONFIG_PT_PROXY
+
+int debugger_signal(int status, pid_t pid)
+{
+	return(debugger_proxy(status, pid));
+}
+
+void child_signal(pid_t pid, int status)
+{
+	child_proxy(pid, status);
+}
+
+static void gdb_announce(char *dev_name, int dev)
+{
+	printf("gdb assigned device '%s'\n", dev_name);
+}
+
+static struct chan_opts opts = {
+	announce : 	gdb_announce,
+	xterm_title :	"UML kernel debugger",
+	raw :		0,
+	tramp_stack :	0,
+};
+
+static void *xterm_data;
+static int xterm_fd;
+
+extern void *xterm_init(char *, int, struct chan_opts *);
+extern int xterm_open(int, int, int, void *);
+extern void xterm_close(int, void *);
+
+int open_gdb_chan(void)
+{
+	char stack[PAGE_SIZE];
+
+	opts.tramp_stack = (unsigned long) stack;
+	xterm_data = xterm_init("", 0, &opts);
+	xterm_fd = xterm_open(1, 1, 1, xterm_data);
+	return(xterm_fd);
+}
+
+static void exit_debugger_cb(void *unused)
+{
+	if(debugger_pid != -1){
+		if(gdb_pid != -1){
+			fake_child_exit();
+			gdb_pid = -1;
+		}
+		else kill_child_dead(debugger_pid);
+		debugger_pid = -1;
+		if(debugger_parent != -1)
+			detach(debugger_parent, SIGINT);
+	}
+	if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
+}
+
+static void exit_debugger(void)
+{
+	tracing_cb(exit_debugger_cb, NULL);
+}
+
+__uml_exitcall(exit_debugger);
+
+struct gdb_data {
+	char *str;
+	int err;
+};
+
+static void config_gdb_cb(void *arg)
+{
+	struct gdb_data *data = arg;
+	struct task_struct *task;
+	int pid;
+
+	data->err = -1;
+	if(debugger_pid != -1) exit_debugger_cb(NULL);
+	if(!strncmp(data->str, "pid,", strlen("pid,"))){
+		data->str += strlen("pid,");
+		pid = simple_strtoul(data->str, NULL, 0);
+		task = cpu_tasks[0].task;
+		debugger_pid = attach_debugger(task->thread.extern_pid,
+					       pid, 0);
+		if(debugger_pid != -1){
+			data->err = 0;
+			gdb_pid = pid;
+		}
+		return;
+	}
+	data->err = 0;
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int gdb_config(char *str)
+{
+	struct gdb_data data;
+
+	if(*str++ != '=') return(-1);
+	data.str = str;
+	tracing_cb(config_gdb_cb, &data);
+	return(data.err);
+}
+
+void remove_gdb_cb(void *unused)
+{
+	exit_debugger_cb(NULL);
+}
+
+int gdb_remove(char *unused)
+{
+	tracing_cb(remove_gdb_cb, NULL);
+	return(0);
+}
+
+#ifdef CONFIG_MCONSOLE
+
+static struct mc_device gdb_mc = {
+	name:		"gdb",
+	config:		gdb_config,
+	remove:		gdb_remove,
+};
+
+int gdb_mc_init(void)
+{
+	mconsole_register_dev(&gdb_mc);
+	return(0);
+}
+
+__initcall(gdb_mc_init);
+
+#endif
+
+void signal_usr1(int sig)
+{
+	if(debugger_pid != -1){
+		printk(KERN_ERR "The debugger is already running\n");
+		return;
+	}
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	int pid, status;
+
+	pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
+	status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+ 	if(pid < 0){
+		cont(idle_pid);
+		return(-1);
+	}
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	int status = 0, err;
+
+	err = attach(pid);
+	if(err < 0){
+		printf("Failed to attach pid %d, errno = %d\n", pid, -err);
+		return(-1);
+	}
+	if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+#ifdef notdef /* Put this back in when it does something useful */
+static int __init uml_gdb_init_setup(char *line, int *add)
+{
+	gdb_init = uml_strdup(line);
+	return 0;
+}
+
+__uml_setup("gdb=", uml_gdb_init_setup, 
+"gdb=<channel description>\n\n"
+);
+#endif
+
+static int __init uml_gdb_pid_setup(char *line, int *add)
+{
+	gdb_pid = simple_strtoul(line, NULL, 0);
+	*add = 0;
+	return 0;
+}
+
+__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
+"gdb-pid=<pid>\n"
+"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
+"    an already-running gdb or a debugger-like process like strace.\n\n"
+);
+
+#else
+
+int debugger_signal(int status, pid_t pid){ return(0); }
+void child_signal(pid_t pid, int status){ }
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+	kill_child_dead(idle_pid);
+	exit(1);
+}
+
+void signal_usr1(int sig)
+{
+	printk(KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n");
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY "
+	       "is off\n");
+	return(-1);
+}
+
+int config_gdb(char *str)
+{
+	return(-1);
+}
+
+int remove_gdb(void)
+{
+	return(-1);
+}
+
+int init_parent_proxy(int pid)
+{
+	return(-1);
+}
+
+void debugger_parent_signal(int status, int pid)
+{
+}
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/trap_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,568 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "signal_user.h"
+#include "mem_user.h"
+#include "user.h"
+#include "process.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "init.h"
+#include "chan_user.h"
+#include "irq_user.h"
+#include "frame_user.h"
+#include "syscall_user.h"
+#include "ptrace_user.h"
+#include "task.h"
+#include "os.h"
+
+static void signal_segv(int sig)
+{
+	write(2, "Seg fault in signals\n", strlen("Seg fault in signals\n"));
+	for(;;) ;
+}
+
+int detach(int pid, int sig)
+{
+	return(ptrace(PTRACE_DETACH, pid, 0, sig));
+}
+
+int attach(int pid)
+{
+	int err;
+
+	err = ptrace(PTRACE_ATTACH, pid, 0, 0);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int cont(int pid)
+{
+	return(ptrace(PTRACE_CONT, pid, 0, 0));
+}
+
+void kill_child_dead(int pid)
+{
+	kill(pid, SIGKILL);
+	kill(pid, SIGCONT);
+	while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
+}
+
+int debug = 0;
+int debug_stop = 1;
+int debug_parent = 0;
+
+int honeypot = 0;
+
+static int signal_tramp(void *arg)
+{
+	int (*proc)(void *);
+
+	if(honeypot && munmap((void *) (host_task_size - 0x10000000),
+			      0x10000000)) 
+		panic("Unmapping stack failed");
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+		panic("ptrace PTRACE_TRACEME failed");
+	os_stop_process(os_getpid());
+	change_sig(SIGWINCH, 0);
+	signal(SIGUSR1, SIG_IGN);
+	change_sig(SIGCHLD, 0);
+	signal(SIGSEGV, (__sighandler_t) sig_handler);
+	set_timers(0);
+	set_cmdline("(idle thread)");
+	set_init_pid(os_getpid());
+	proc = arg;
+	return((*proc)(NULL));
+}
+
+static void last_ditch_exit(int sig)
+{
+	signal(SIGINT, SIG_DFL);
+	signal(SIGTERM, SIG_DFL);
+	signal(SIGHUP, SIG_DFL);
+	uml_cleanup();
+	exit(1);
+}
+
+static void sleeping_process_signal(int pid, int sig)
+{
+	switch(sig){
+	/* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
+	 * right because the process must be in the kernel already.
+	 */
+	case SIGCONT:
+	case SIGTSTP:
+		if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "continue pid %d, errno = %d\n", pid,
+				     sig);
+		break;
+
+	/* This happens when the debugger (e.g. strace) is doing system call 
+	 * tracing on the kernel.  During a context switch, the current task
+	 * will be set to the incoming process and the outgoing process will
+	 * hop into write and then read.  Since it's not the current process
+	 * any more, the trace of those will land here.  So, we need to just 
+	 * PTRACE_SYSCALL it.
+	 */
+	case SIGTRAP:
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "PTRACE_SYSCALL pid %d, errno = %d\n",
+				     pid, sig);
+		break;
+	case SIGSTOP:
+		break;
+	default:
+		tracer_panic("sleeping process %d got unexpected "
+			     "signal : %d\n", pid, sig);
+		break;
+	}
+}
+
+#ifdef CONFIG_SMP
+#error need to make these arrays
+#endif
+
+int debugger_pid = -1;
+int debugger_parent = -1;
+int debugger_fd = -1;
+int gdb_pid = -1;
+
+struct {
+	unsigned long address;
+	int is_write;
+	int pid;
+	unsigned long sp;
+	int is_user;
+} segfault_record[1024];
+
+int segfault_index = 0;
+
+struct {
+	int pid;
+	int signal;
+	unsigned long addr;
+	struct timeval time;
+} signal_record[1024];
+
+int signal_index = 0;
+int nsignals = 0;
+int debug_trace = 0;
+extern int io_nsignals, io_count, intr_count;
+
+extern void signal_usr1(int sig);
+
+int tracing_pid = -1;
+
+int signals(int (*init_proc)(void *), void *sp)
+{
+	void *task = NULL;
+	unsigned long eip = 0;
+	int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
+	int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0;
+
+	capture_signal_stack();
+	signal(SIGPIPE, SIG_IGN);
+	setup_tracer_winch();
+	tracing_pid = os_getpid();
+	printk("tracing thread pid = %d\n", tracing_pid);
+
+	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
+	n = waitpid(pid, &status, WUNTRACED);
+	if(n < 0){
+		printf("waitpid on idle thread failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
+		printf("Failed to continue idle thread, errno = %d\n", errno);
+		exit(1);
+	}
+
+	signal(SIGSEGV, signal_segv);
+	signal(SIGUSR1, signal_usr1);
+	set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
+	if(debug_trace){
+		printk("Tracing thread pausing to be attached\n");
+		stop();
+	}
+	if(debug){
+		if(gdb_pid != -1) 
+			debugger_pid = attach_debugger(pid, gdb_pid, 1);
+		else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
+		if(debug_parent){
+			debugger_parent = os_process_parent(debugger_pid);
+			init_parent_proxy(debugger_parent);
+			err = attach(debugger_parent);
+			if(err){
+				printk("Failed to attach debugger parent %d, "
+				       "errno = %d\n", debugger_parent, err);
+				debugger_parent = -1;
+			}
+			else {
+				if(ptrace(PTRACE_SYSCALL, debugger_parent, 
+					  0, 0) < 0){
+					printk("Failed to continue debugger "
+					       "parent, errno = %d\n", errno);
+					debugger_parent = -1;
+				}
+			}
+		}
+	}
+	set_cmdline("(tracing thread)");
+	while(1){
+		if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
+			if(errno != ECHILD){
+				printk("wait failed - errno = %d\n", errno);
+			}
+			continue;
+		}
+		if(pid == debugger_pid){
+			int cont = 0;
+
+			if(WIFEXITED(status) || WIFSIGNALED(status))
+				debugger_pid = -1;
+			/* XXX Figure out how to deal with gdb and SMP */
+			else cont = debugger_signal(status, cpu_tasks[0].pid);
+			if(cont == PTRACE_SYSCALL) strace = 1;
+			continue;
+		}
+		else if(pid == debugger_parent){
+			debugger_parent_signal(status, pid);
+			continue;
+		}
+		nsignals++;
+		if(WIFEXITED(status)) ;
+#ifdef notdef
+		{
+			printk("Child %d exited with status %d\n", pid, 
+			       WEXITSTATUS(status));
+		}
+#endif
+		else if(WIFSIGNALED(status)){
+			sig = WTERMSIG(status);
+			if(sig != 9){
+				printk("Child %d exited with signal %d\n", pid,
+				       sig);
+			}
+		}
+		else if(WIFSTOPPED(status)){
+			sig = WSTOPSIG(status);
+			if(signal_index == 1024){
+				signal_index = 0;
+				last_index = 1023;
+			}
+			else last_index = signal_index - 1;
+			if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
+			    (sig == SIGALRM)) &&
+			   (signal_record[last_index].signal == sig) &&
+			   (signal_record[last_index].pid == pid))
+				signal_index = last_index;
+			signal_record[signal_index].pid = pid;
+			gettimeofday(&signal_record[signal_index].time, NULL);
+			eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+			signal_record[signal_index].addr = eip;
+			signal_record[signal_index++].signal = sig;
+			
+			proc_id = pid_to_processor_id(pid);
+			if(proc_id == -1){
+				sleeping_process_signal(pid, sig);
+				continue;
+			}
+
+			task = cpu_tasks[proc_id].task;
+			tracing = is_tracing(task);
+			old_tracing = tracing;
+
+			switch(sig){
+			case SIGUSR1:
+				sig = 0;
+				op = do_proc_op(task, proc_id);
+				switch(op){
+				case OP_TRACE_ON:
+					arch_leave_kernel(task, pid);
+					tracing = 1;
+					break;
+				case OP_REBOOT:
+				case OP_HALT:
+					unmap_physmem();
+					kmalloc_ok = 0;
+					ptrace(PTRACE_KILL, pid, 0, 0);
+					return(op == OP_REBOOT);
+				case OP_NONE:
+					printk("Detaching pid %d\n", pid);
+					detach(pid, SIGSTOP);
+					continue;
+				default:
+					break;
+				}
+				/* OP_EXEC switches host processes on us,
+				 * we want to continue the new one.
+				 */
+				pid = cpu_tasks[proc_id].pid;
+				break;
+			case SIGTRAP:
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status);
+					continue;
+				}
+				tracing = 0;
+				if(do_syscall(task, pid)) sig = SIGUSR2;
+				else clear_singlestep(task);
+				break;
+			case SIGPROF:
+				if(tracing) sig = 0;
+				break;
+			case SIGCHLD:
+			case SIGHUP:
+				sig = 0;
+				break;
+			case SIGSEGV:
+			case SIGIO:
+			case SIGALRM:
+			case SIGVTALRM:
+			case SIGFPE:
+			case SIGBUS:
+			case SIGILL:
+			case SIGWINCH:
+			default:
+				tracing = 0;
+				break;
+			}
+			set_tracing(task, tracing);
+
+			if(!tracing && old_tracing)
+				arch_enter_kernel(task, pid);
+
+			if(!tracing && (debugger_pid != -1) && (sig != 0) &&
+				(sig != SIGALRM) && (sig != SIGVTALRM) &&
+				(sig != SIGSEGV) && (sig != SIGTRAP) &&
+				(sig != SIGUSR2) && (sig != SIGIO)){
+				child_signal(pid, status);
+				continue;
+			}
+
+			if(tracing){
+				if(singlestepping(task))
+					cont_type = PTRACE_SINGLESTEP;
+				else cont_type = PTRACE_SYSCALL;
+			}
+			else cont_type = PTRACE_CONT;
+
+			if((cont_type == PTRACE_CONT) && 
+			   (debugger_pid != -1) && strace)
+				cont_type = PTRACE_SYSCALL;
+
+			if(ptrace(cont_type, pid, 0, sig) != 0){
+				tracer_panic("ptrace failed to continue "
+					     "process - errno = %d\n", 
+					     errno);
+			}
+		}
+	}
+	return(0);
+}
+
+static int __init uml_debugtrace_setup(char *line, int *add)
+{
+	debug_trace = 1;
+	return 0;
+}
+__uml_setup("debugtrace", uml_debugtrace_setup,
+"debugtrace\n"
+"    Causes the tracing thread to pause until it is attached by a\n"
+"    debugger and continued.  This is mostly for debugging crashes\n"
+"    early during boot, and should be pretty much obsoleted by\n"
+"    the debug switch.\n\n"
+);
+
+static int __init uml_honeypot_setup(char *line, int *add)
+{
+	jail_setup("", add);
+	honeypot = 1;
+	return 0;
+}
+__uml_setup("honeypot", uml_honeypot_setup, 
+"honeypot\n"
+"    This makes UML put process stacks in the same location as they are\n"
+"    on the host, allowing expoits such as stack smashes to work against\n"
+"    UML.  This implies 'jail'.\n\n"
+);
+
+int nsegfaults = 0;
+
+void segv_handler(int sig, struct uml_pt_regs *regs)
+{
+	struct sigcontext_struct *context = regs->sc;
+	int index;
+
+	if(regs->is_user && !SEGV_IS_FIXABLE(context)){
+		bad_segv(SC_FAULT_ADDR(context), SC_IP(context), 
+			 SC_FAULT_WRITE(context));
+		return;
+	}
+	lock_trap();
+	index = segfault_index++;
+	if(segfault_index == 1024) segfault_index = 0;
+	unlock_trap();
+	nsegfaults++;
+	segfault_record[index].address = SC_FAULT_ADDR(context);
+	segfault_record[index].pid = os_getpid();
+	segfault_record[index].is_write = SC_FAULT_WRITE(context);
+	segfault_record[index].sp = SC_SP(context);
+	segfault_record[index].is_user = regs->is_user;
+	segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context),
+	     regs->is_user, context);
+}
+
+extern int kern_timer_on;
+
+struct signal_info {
+	void (*handler)(int, struct uml_pt_regs *);
+	int is_irq;
+};
+
+static struct signal_info sig_info[] = {
+	[ SIGTRAP ] { handler :		relay_signal,
+		      is_irq :		0 },
+	[ SIGFPE ] { handler :		relay_signal,
+		     is_irq :		0 },
+	[ SIGILL ] { handler :		relay_signal,
+		     is_irq :		0 },
+	[ SIGBUS ] { handler :		bus_handler,
+		     is_irq :		0 },
+	[ SIGSEGV] { handler :		segv_handler,
+		     is_irq :		0 },
+	[ SIGIO ] { handler :		sigio_handler,
+		    is_irq :		1 },
+	[ SIGVTALRM ] { handler :	timer_handler,
+			is_irq :	1 },
+	[ SIGALRM ] { handler :		timer_handler,
+		      is_irq :		1 },
+	[ SIGUSR2 ] { handler :		syscall_handler,
+		      is_irq :		0 },
+};
+
+void sig_handler_common(int sig, struct sigcontext *sc)
+{
+	struct uml_pt_regs save_regs, *r;
+	struct signal_info *info;
+	int save_errno = errno, save_timer = kern_timer_on, is_user;
+
+	unprotect_kernel_mem();
+
+	r = (struct uml_pt_regs *) TASK_REGS(get_current());
+	save_regs = *r;
+	is_user = user_context(SC_SP(sc));
+	r->is_user = is_user;
+	r->sc = sc;
+	if(sig != SIGUSR2) r->syscall = -1;
+
+	change_sig(SIGUSR1, 1);
+	info = &sig_info[sig];
+	if(!info->is_irq) unblock_signals();
+
+	(*info->handler)(sig, r);
+
+	kern_timer_on = save_timer;
+	if(is_user){
+		interrupt_end();
+		block_signals();
+		change_sig(SIGUSR1, 0);
+		set_user_mode(NULL);
+	}
+	*r = save_regs;
+	errno = save_errno;
+	if(is_user) protect_kernel_mem();
+}
+
+void sig_handler(int sig, struct sigcontext sc)
+{
+	sig_handler_common(sig, &sc);
+}
+
+extern int timer_irq_inited, missed_ticks;
+
+extern int jail_timer_off;
+
+void alarm_handler(int sig, struct sigcontext sc)
+{
+	int user;
+
+	if(!timer_irq_inited) return;
+	missed_ticks++;
+	user = user_context(SC_SP(&sc));
+	if(!user && !kern_timer_on) return;
+	if(!user && jail_timer_off) return;
+	sig_handler_common(sig, &sc);
+}
+
+void do_longjmp(void *p)
+{
+    jmp_buf *jbuf = (jmp_buf *) p;
+
+    longjmp(*jbuf, 1);
+}
+
+static int __init uml_debug_setup(char *line, int *add)
+{
+	char *next;
+
+	debug = 1;
+	*add = 0;
+	if(*line != '=') return(0);
+	line++;
+
+	while(line != NULL){
+		next = strchr(line, ',');
+		if(next) *next++ = '\0';
+		
+		if(!strcmp(line, "go"))	debug_stop = 0;
+		else if(!strcmp(line, "parent")) debug_parent = 1;
+		else printk("Unknown debug option : '%s'\n", line);
+
+		line = next;
+	}
+	return(0);
+}
+
+__uml_setup("debug", uml_debug_setup,
+"debug\n"
+"    Starts up the kernel under the control of gdb. See the \n"
+"    kernel debugging tutorial and the debugging session pages\n"
+"    at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
+);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/tty_log.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,130 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and 
+ * geoffrey hing <ghing@net.ohio-state.edu>
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include "init.h"
+#include "user.h"
+#include "os.h"
+
+#define TTY_LOG_DIR "./"
+
+char *tty_log_dir = TTY_LOG_DIR;
+
+static int tty_log_fd = -1;
+
+#define TTY_LOG_OPEN 1
+#define TTY_LOG_CLOSE 2
+#define TTY_LOG_WRITE 3
+
+struct tty_log_buf {
+	int what;
+	unsigned long tty;
+	int len;
+};
+
+int open_tty_log(void *tty)
+{
+	struct timeval tv;
+	struct tty_log_buf data;
+	char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
+	int fd;
+
+	if(tty_log_fd != -1){
+		data = ((struct tty_log_buf) { what :	TTY_LOG_OPEN,
+					       tty : (unsigned long) tty,
+					       len : 0 });
+		write(tty_log_fd, &data, sizeof(data));
+		return(tty_log_fd);
+	}
+
+	gettimeofday(&tv, NULL);
+	sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 
+ 		(unsigned int) tv.tv_usec);
+
+	fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
+			  0644);
+	if(fd < 0){
+		printk("open_tty_log : couldn't open '%s', errno = %d\n",
+		       buf, -fd);
+	}
+	return(fd);
+}
+
+void close_tty_log(int fd, void *tty)
+{
+	struct tty_log_buf data;
+
+	if(tty_log_fd != -1){
+		data = ((struct tty_log_buf) { what :	TTY_LOG_CLOSE,
+					       tty : (unsigned long) tty,
+					       len : 0 });
+		write(tty_log_fd, &data, sizeof(data));
+		return;
+	}
+	close(fd);
+}
+
+int write_tty_log(int fd, char *buf, int len, void *tty)
+{
+	struct tty_log_buf data;
+
+	if(fd == tty_log_fd){
+		data = ((struct tty_log_buf) { what :	TTY_LOG_WRITE,
+					       tty : (unsigned long) tty,
+					       len : len });
+		write(tty_log_fd, &data, sizeof(data));
+	}
+	return(write(fd, buf, len));
+}
+
+static int __init set_tty_log_dir(char *name, int *add)
+{
+	tty_log_dir = name;
+	return 0;
+}
+
+__uml_setup("tty_log_dir=", set_tty_log_dir,
+"tty_log_dir=<directory>\n"
+"    This is used to specify the directory where the logs of all pty\n"
+"    data from this UML machine will be written.\n\n"
+);
+
+static int __init set_tty_log_fd(char *name, int *add)
+{
+	char *end;
+
+	tty_log_fd = strtoul(name, &end, 0);
+	if(*end != '\0'){
+		printk("set_tty_log_dir - strtoul failed on '%s'\n", name);
+		tty_log_fd = -1;
+	}
+	return 0;
+}
+
+__uml_setup("tty_log_fd=", set_tty_log_fd,
+"tty_log_fd=<fd>\n"
+"    This is used to specify a preconfigured file descriptor to which all\n"
+"    tty data will be written.  Preconfigure the descriptor with something\n"
+"    like '10>tty_log tty_log_fd=10'.\n\n"
+);
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/uaccess_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,126 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <setjmp.h>
+#include <string.h>
+#include "user_util.h"
+
+static unsigned long __do_user_copy(void *to, const void *from, int n,
+				    void **fault_addr, void **fault_catcher,
+				    void (*op)(void *to, const void *from,
+					       int n), int *faulted_out)
+{
+	unsigned long *faddrp = (unsigned long *) fault_addr, ret;
+
+	jmp_buf jbuf;
+	*fault_catcher = &jbuf;
+	if(setjmp(jbuf) == 0){
+		(*op)(to, from, n);
+		ret = 0;
+		*faulted_out = 0;
+	} 
+	else {
+		ret = *faddrp;
+		*faulted_out = 1;
+	}
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+	return ret;
+}
+
+static void __do_copy(void *to, const void *from, int n)
+{
+	memcpy(to, from, n);
+}	
+
+int __do_copy_from_user(void *to, const void *from, int n,
+			void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) from));
+}
+
+
+int __do_copy_to_user(void *to, const void *from, int n,
+		      void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) to));
+}
+
+static void __do_strncpy(void *dst, const void *src, int count)
+{
+	strncpy(dst, src, count);
+}	
+
+int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
+			   void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+			       __do_strncpy, &faulted);
+	if(!faulted) return(strlen(dst));
+	else return(-1);
+}
+
+static void __do_clear(void *to, const void *from, int n)
+{
+	memset(to, 0, n);
+}	
+
+int __do_clear_user(void *mem, unsigned long len,
+		    void **fault_addr, void **fault_catcher)
+{
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+			       __do_clear, &faulted);
+	if(!faulted) return(0);
+	else return(len - (fault - (unsigned long) mem));
+}
+
+int __do_strnlen_user(const char *str, unsigned long n,
+		      void **fault_addr, void **fault_catcher)
+{
+	int ret;
+	unsigned long *faddrp = (unsigned long *)fault_addr;
+	jmp_buf jbuf;
+
+	*fault_catcher = &jbuf;
+	if(setjmp(jbuf) == 0){
+		ret = strlen(str) + 1;
+	} 
+	else {
+		ret = *faddrp - (unsigned long) str;
+	}
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+	return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/um_arch.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,388 @@
+/* 
+ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/config.h"
+#include "linux/sched.h"
+#include "linux/notifier.h"
+#include "linux/mm.h"
+#include "linux/types.h"
+#include "linux/tty.h"
+#include "linux/init.h"
+#include "linux/bootmem.h"
+#include "linux/spinlock.h"
+#include "linux/utsname.h"
+#include "linux/sysrq.h"
+#include "linux/seq_file.h"
+#include "linux/delay.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/ptrace.h"
+#include "asm/elf.h"
+#include "asm/user.h"
+#include "ubd_user.h"
+#include "asm/current.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "kern.h"
+#include "mprot.h"
+#include "mem_user.h"
+#include "mem.h"
+#include "umid.h"
+#include "initrd.h"
+#include "init.h"
+#include "os.h"
+
+#define DEFAULT_COMMAND_LINE "root=6200"
+
+unsigned long thread_saved_pc(struct task_struct *task)
+{
+	return(os_process_pc(task->thread.extern_pid));
+}
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	int index;
+
+	index = (struct cpuinfo_um *)v - cpu_data;
+#ifdef CONFIG_SMP
+	if (!(cpu_online_map & (1 << index)))
+		return 0;
+#endif
+
+	seq_printf(m, "bogomips\t: %lu.%02lu\n",
+		   loops_per_jiffy/(500000/HZ),
+		   (loops_per_jiffy/(5000/HZ)) % 100);
+	seq_printf(m, "host\t\t: %s\n", host_info);
+
+	return(0);
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
+
+pte_t * __bad_pagetable(void)
+{
+	panic("Someone should implement __bad_pagetable");
+	return(NULL);
+}
+
+extern void start_kernel(void);
+
+extern int debug;
+extern int debug_stop;
+
+static int start_kernel_proc(void *unused)
+{
+	int pid;
+
+	block_signals();
+	pid = os_getpid();
+
+	cpu_tasks[0].pid = pid;
+	cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ 	cpu_online_map = 1;
+#endif
+	if(debug) os_stop_process(pid);
+	start_kernel();
+	return(0);
+}
+
+extern unsigned long high_physmem;
+
+#ifdef CONFIG_HOST_2G_2G
+#define TOP 0x80000000
+#else
+#define TOP 0xc0000000
+#endif
+
+#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
+#define START (TOP - SIZE)
+
+unsigned long host_task_size;
+unsigned long task_size;
+
+void set_task_sizes(int arg)
+{
+	/* Round up to the nearest 4M */
+	host_task_size = ROUND_4M((unsigned long) &arg);
+	task_size = START;
+}
+
+unsigned long uml_physmem;
+unsigned long uml_reserved;
+
+unsigned long start_vm;
+unsigned long end_vm;
+
+int ncpus = 1;
+
+static char *argv1_begin = NULL;
+static char *argv1_end = NULL;
+
+static int have_root __initdata = 0;
+long physmem_size = 32 * 1024 * 1024;
+
+void set_cmdline(char *cmd)
+{
+	char *umid, *ptr;
+	if(honeypot) return;
+
+	umid = get_umid(1);
+	if(umid != NULL){
+		snprintf(argv1_begin, 
+			 (argv1_end - argv1_begin) * sizeof(*ptr), 
+			 "(%s)", umid);
+		ptr = &argv1_begin[strlen(argv1_begin)];
+	}
+	else ptr = argv1_begin;
+
+	snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
+	memset(argv1_begin + strlen(argv1_begin), '\0', 
+	       argv1_end - argv1_begin - strlen(argv1_begin));  
+}
+
+static char *usage_string = 
+"User Mode Linux v%s\n"
+"	available at http://user-mode-linux.sourceforge.net/\n\n";
+
+static int __init uml_version_setup(char *line, int *add)
+{
+	printf("%s\n", system_utsname.release);
+	exit(0);
+}
+
+__uml_setup("--version", uml_version_setup,
+"--version\n"
+"    Prints the version number of the kernel.\n\n"
+);
+
+static int __init uml_root_setup(char *line, int *add)
+{
+	have_root = 1;
+	return 0;
+}
+
+__uml_setup("root=", uml_root_setup,
+"root=<file containing the root fs>\n"
+"    This is actually used by the generic kernel in exactly the same\n"
+"    way as in any other kernel. If you configure a number of block\n"
+"    devices and want to boot off something other than ubd0, you \n"
+"    would use something like:\n"
+"        root=/dev/ubd5\n\n"
+);
+
+#ifdef CONFIG_SMP
+static int __init uml_ncpus_setup(char *line, int *add)
+{
+       if (!sscanf(line, "%d", &ncpus)) {
+               printk("Couldn't parse [%s]\n", line);
+               return -1;
+       }
+
+       return 0;
+}
+
+__uml_setup("ncpus=", uml_ncpus_setup,
+"ncpus=<# of desired CPUs>\n"
+"    This tells an SMP kernel how many virtual processors to start.\n"
+"    Currently, this has no effect because SMP isn't enabled.\n\n" 
+);
+#endif
+
+static int __init Usage(char *line, int *add)
+{
+ 	const char **p;
+
+	printf(usage_string, system_utsname.release);
+ 	p = &__uml_help_start;
+ 	while (p < &__uml_help_end) {
+ 		printf("%s", *p);
+ 		p++;
+ 	}
+	exit(0);
+}
+
+__uml_setup("--help", Usage,
+"--help\n"
+"    Prints this message.\n\n"
+);
+
+static int __init uml_checksetup(char *line, int *add)
+{
+	struct uml_param *p;
+
+	p = &__uml_setup_start;
+	while(p < &__uml_setup_end) {
+		int n;
+
+		n = strlen(p->str);
+		if(!strncmp(line, p->str, n)){
+			if (p->setup_func(line + n, add)) return 1;
+		}
+		p++;
+	}
+	return 0;
+}
+
+static void __init uml_postsetup(void)
+{
+	initcall_t *p;
+
+	p = &__uml_postsetup_start;
+	while(p < &__uml_postsetup_end){
+		(*p)();
+		p++;
+	}
+	return;
+}
+
+extern int debug_trace;
+unsigned long brk_start;
+
+static struct vm_reserved kernel_vm_reserved;
+
+int linux_main(int argc, char **argv)
+{
+	unsigned long avail;
+	unsigned long virtmem_size;
+	unsigned int i, add, err;
+	void *sp;
+
+	for (i = 1; i < argc; i++){
+		if((i == 1) && (argv[i][0] == ' ')) continue;
+		add = 1;
+		uml_checksetup(argv[i], &add);
+		if(add) add_arg(saved_command_line, argv[i]);
+	}
+	if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
+
+	if(!jail)
+		remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
+	remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
+	brk_start = (unsigned long) sbrk(0);
+	remap_data(ROUND_DOWN(&__bss_start), ROUND_UP(brk_start), 1);
+
+	uml_physmem = START;
+
+	/* Reserve up to 4M after the current brk */
+	uml_reserved = ROUND_4M(brk_start) + (1 << 22);
+
+	setup_machinename(system_utsname.machine);
+
+	argv1_begin = argv[1];
+	argv1_end = &argv[1][strlen(argv[1])];
+  
+	set_usable_vm(uml_physmem, get_kmem_end());
+	high_physmem = uml_physmem + physmem_size;
+	high_memory = (void *) high_physmem;
+	setup_physmem(uml_physmem, uml_reserved, physmem_size);
+
+	/* Kernel vm starts after physical memory and is either the size
+	 * of physical memory or the remaining space left in the kernel
+	 * area of the address space, whichever is smaller.
+	 */
+
+	start_vm = VMALLOC_START;
+	if(start_vm >= get_kmem_end())
+		panic("Physical memory too large to allow any kernel "
+		      "virtual memory");
+
+	virtmem_size = physmem_size;
+	avail = get_kmem_end() - start_vm;
+	if(physmem_size > avail) virtmem_size = avail;
+	end_vm = start_vm + virtmem_size;
+
+	if(virtmem_size < physmem_size)
+		printk(KERN_INFO "Kernel virtual memory size shrunk to %ld "
+		       "bytes\n", virtmem_size);
+
+	err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
+	if(err)	panic("Failed to reserve VM area for kernel VM\n");
+
+  	uml_postsetup();
+
+	init_task.thread.kernel_stack = (unsigned long) &init_thread_info + 
+		2 * PAGE_SIZE;
+
+	task_protections((unsigned long) &init_thread_info);
+	sp = (void *) init_task.thread.kernel_stack + 2 * PAGE_SIZE - 
+		sizeof(unsigned long);
+	return(signals(start_kernel_proc, sp));
+}
+
+static int panic_exit(struct notifier_block *self, unsigned long unused1,
+		      void *unused2)
+{
+#ifdef CONFIG_SYSRQ
+	handle_sysrq('p', &current->thread.regs, NULL, NULL);
+#endif
+	machine_halt();
+	return(0);
+}
+
+static struct notifier_block panic_exit_notifier = {
+	notifier_call :		panic_exit,
+	next :			NULL,
+	priority :		0
+};
+
+void __init setup_arch(char **cmdline_p)
+{
+	notifier_chain_register(&panic_notifier_list, &panic_exit_notifier);
+	paging_init();
+ 	strcpy(command_line, saved_command_line);
+ 	*cmdline_p = command_line;
+	setup_hostinfo();
+}
+
+void __init check_bugs(void)
+{
+	arch_check_bugs();
+	check_ptrace();
+	check_sigio();
+}
+
+spinlock_t pid_lock = SPIN_LOCK_UNLOCKED;
+
+void lock_pid(void)
+{
+	spin_lock(&pid_lock);
+}
+
+void unlock_pid(void)
+{
+	spin_unlock(&pid_lock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/umid.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,302 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include "user.h"
+#include "umid.h"
+#include "init.h"
+#include "os.h"
+
+#define UMID_LEN 64
+#define UML_DIR "~/.uml/"
+
+static char umid[UMID_LEN] = { 0 };
+static char *uml_dir = UML_DIR;
+
+static int umid_is_random = 1;
+static int umid_inited = 0;
+
+static int make_umid(void);
+
+static int __init set_umid(char *name, int *add)
+{
+	if(umid_inited){
+		printk("Unique machine name can't be set twice\n");
+		return(-1);
+	}
+
+	if(strlen(name) > UMID_LEN - 1)
+		printk("Unique machine name is being truncated to %s "
+		       "characters\n", UMID_LEN);
+	strncpy(umid, name, UMID_LEN - 1);
+	umid[UMID_LEN - 1] = '\0';
+
+	umid_is_random = 0;
+	umid_inited = 1;
+	return 0;
+}
+
+__uml_setup("umid=", set_umid,
+"umid=<name>\n"
+"    This is used to assign a unique identity to this UML machine and\n"
+"    is used for naming the pid file and management console socket.\n\n"
+);
+
+int __init umid_file_name(char *name, char *buf, int len)
+{
+	int n;
+
+	if(!umid_inited && make_umid()) return(-1);
+
+	n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
+	if(n > len){
+		printk("umid_file_name : buffer too short\n");
+		return(-1);
+	}
+
+	sprintf(buf, "%s%s/%s", uml_dir, umid, name);
+	return(0);
+}
+
+extern int tracing_pid;
+
+static int __init create_pid_file(void)
+{
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+	char pid[sizeof("nnnnn\0")];
+	int fd;
+
+	if(umid_file_name("pid", file, sizeof(file))) return 0;
+
+	fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
+			  0644);
+	if(fd < 0){
+		printk("Open of machine pid file \"%s\" failed - "
+		       "errno = %d\n", file, -fd);
+		return 0;
+	}
+
+	sprintf(pid, "%d\n", (tracing_pid == -1) ? os_getpid() : tracing_pid);
+	if(write(fd, pid, strlen(pid)) != strlen(pid))
+		printk("Write of pid file failed - errno = %d\n", errno);
+	close(fd);
+	return 0;
+}
+
+static int actually_do_remove(char *dir)
+{
+	DIR *directory;
+	struct dirent *ent;
+	int len;
+	char file[256];
+
+	if((directory = opendir(dir)) == NULL){
+		printk("actually_do_remove : couldn't open directory '%s', "
+		       "errno = %d\n", dir, errno);
+		return(1);
+	}
+	while((ent = readdir(directory)) != NULL){
+		if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
+			continue;
+		len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1;
+		if(len > sizeof(file)){
+			printk("Not deleting '%s' from '%s' - name too long\n",
+			       ent->d_name, dir);
+			continue;
+		}
+		sprintf(file, "%s/%s", dir, ent->d_name);
+		if(unlink(file) < 0){
+			printk("actually_do_remove : couldn't remove '%s' "
+			       "from '%s', errno = %d\n", ent->d_name, dir, 
+			       errno);
+			return(1);
+		}
+	}
+	if(rmdir(dir) < 0){
+		printk("actually_do_remove : couldn't rmdir '%s', "
+		       "errno = %d\n", dir, errno);
+		return(1);
+	}
+	return(0);
+}
+
+void remove_umid_dir(void)
+{
+	char dir[strlen(uml_dir) + UMID_LEN + 1];
+	if(!umid_inited) return;
+
+	sprintf(dir, "%s%s", uml_dir, umid);
+	actually_do_remove(dir);
+}
+
+char *get_umid(int only_if_set)
+{
+	if(only_if_set && umid_is_random) return(NULL);
+	return(umid);
+}
+
+int not_dead_yet(char *dir)
+{
+	char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+	char pid[sizeof("nnnnn\0")], *end;
+	int dead, fd, p;
+
+	sprintf(file, "%s/pid", dir);
+	dead = 0;
+	if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){
+		if(fd != -ENOENT){
+			printk("not_dead_yet : couldn't open pid file '%s', "
+			       "errno = %d\n", file, -fd);
+			return(1);
+		}
+		dead = 1;
+	}
+	if(fd > 0){
+		if(read(fd, pid, sizeof(pid)) < 0){
+			printk("not_dead_yet : couldn't read pid file '%s', "
+			       "errno = %d\n", file, errno);
+			return(1);
+		}
+		p = strtoul(pid, &end, 0);
+		if(end == pid){
+			printk("not_dead_yet : couldn't parse pid file '%s', "
+			       "errno = %d\n", file, errno);
+			dead = 1;
+		}
+		if(((kill(p, 0) < 0) && (errno == ESRCH)) ||
+		   (p == tracing_pid)) 
+			dead = 1;
+	}
+	if(!dead) return(1);
+	return(actually_do_remove(dir));
+	return(0);
+}
+
+static int __init set_uml_dir(char *name, int *add)
+{
+	if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+		uml_dir = malloc(strlen(name) + 1);
+		if(uml_dir == NULL){
+			printk("Failed to malloc uml_dir - error = %d\n",
+			       errno);
+			uml_dir = name;
+			return(0);
+		}
+		sprintf(uml_dir, "%s/", name);
+	}
+	else uml_dir = name;
+	return 0;
+}
+
+static int __init make_uml_dir(void)
+{
+	char dir[MAXPATHLEN + 1] = { '\0' };
+	int len;
+
+	if(*uml_dir == '~'){
+		char *home = getenv("HOME");
+
+		if(home == NULL){
+			printk("make_uml_dir : no value in environment for "
+			       "$HOME\n");
+			exit(1);
+		}
+		strncpy(dir, home, sizeof(dir));
+		uml_dir++;
+	}
+	len = strlen(dir);
+	strncat(dir, uml_dir, sizeof(dir) - len);
+	len = strlen(dir);
+	if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){
+		dir[len] = '/';
+		dir[len + 1] = '\0';
+	}
+
+	if((uml_dir = malloc(strlen(dir) + 1)) == NULL){
+		printf("make_uml_dir : malloc failed, errno = %d\n", errno);
+		exit(1);
+	}
+	strcpy(uml_dir, dir);
+	
+	if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+	        printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
+		return(-1);
+	}
+	return 0;
+}
+
+static int __init make_umid(void)
+{
+	int fd, err;
+	char tmp[strlen(uml_dir) + UMID_LEN + 1];
+
+	strncpy(tmp, uml_dir, sizeof(tmp) - 1);
+	tmp[sizeof(tmp) - 1] = '\0';
+
+	if(*umid == 0){
+		strcat(tmp, "XXXXXX");
+		fd = mkstemp(tmp);
+		if(fd < 0){
+			printk("set_umid - mkstemp failed, errno = %d\n",
+			       errno);
+			return(1);
+		}
+
+		close(fd);
+		/* There's a nice tiny little race between this unlink and
+		 * the mkdir below.  It'd be nice if there were a mkstemp
+		 * for directories.
+		 */
+		unlink(tmp);
+		strcpy(umid, &tmp[strlen(uml_dir)]);
+	}
+	
+	sprintf(tmp, "%s%s", uml_dir, umid);
+
+	if((err = mkdir(tmp, 0777)) < 0){
+		if(errno == EEXIST){
+			if(not_dead_yet(tmp)){
+				printk("umid '%s' is in use\n", umid);
+				return(-1);
+			}
+			err = mkdir(tmp, 0777);
+		}
+	}
+	if(err < 0){
+		printk("Failed to create %s - errno = %d\n", umid, errno);
+		return(-1);
+	}
+
+	return(0);
+}
+
+__uml_setup("uml_dir=", set_uml_dir,
+"uml_dir=<directory>\n"
+"    The location to place the pid and umid files.\n\n"
+);
+
+__uml_postsetup(make_uml_dir);
+__uml_postsetup(make_umid);
+__uml_postsetup(create_pid_file);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/unmap.c b/arch/um/kernel/unmap.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/unmap.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "user.h"
+
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+	if(munmap(to, size) < 0){
+		return(-1);
+	}
+	if(mmap(to, size, prot,	MAP_SHARED | MAP_FIXED, fd, 0) != to){
+		return(-1);
+	}
+	if(munmap(from, size) < 0){
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/user_syms.c b/arch/um/kernel/user_syms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/user_syms.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <utime.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/ioctl.h>
+#include "user_util.h"
+#include "mem_user.h"
+
+/* XXX All the __CONFIG_* stuff is broken because this file can't include
+ * config.h
+ */
+
+/* Had to steal this from linux/module.h because that file can't be included
+ * since this includes various user-level headers.
+ */
+
+struct module_symbol
+{
+	unsigned long value;
+	const char *name;
+};
+
+/* Indirect stringification.  */
+
+#define __MODULE_STRING_1(x)	#x
+#define __MODULE_STRING(x)	__MODULE_STRING_1(x)
+
+#if !defined(__AUTOCONF_INCLUDED__)
+
+#define __EXPORT_SYMBOL(sym,str)   error config_must_be_included_before_module
+#define EXPORT_SYMBOL(var)	   error config_must_be_included_before_module
+#define EXPORT_SYMBOL_NOVERS(var)  error config_must_be_included_before_module
+
+#elif !defined(__CONFIG_MODULES__)
+
+#define __EXPORT_SYMBOL(sym,str)
+#define EXPORT_SYMBOL(var)
+#define EXPORT_SYMBOL_NOVERS(var)
+
+#else
+
+#define __EXPORT_SYMBOL(sym, str)			\
+const char __kstrtab_##sym[]				\
+__attribute__((section(".kstrtab"))) = str;		\
+const struct module_symbol __ksymtab_##sym 		\
+__attribute__((section("__ksymtab"))) =			\
+{ (unsigned long)&sym, __kstrtab_##sym }
+
+#if defined(__MODVERSIONS__) || !defined(__CONFIG_MODVERSIONS__)
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+#else
+#define EXPORT_SYMBOL(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var)))
+#endif
+
+#define EXPORT_SYMBOL_NOVERS(var)  __EXPORT_SYMBOL(var, __MODULE_STRING(var))
+
+#endif
+
+EXPORT_SYMBOL(__errno_location);
+
+EXPORT_SYMBOL(access);
+EXPORT_SYMBOL(open);
+EXPORT_SYMBOL(open64);
+EXPORT_SYMBOL(close);
+EXPORT_SYMBOL(read);
+EXPORT_SYMBOL(write);
+EXPORT_SYMBOL(dup2);
+EXPORT_SYMBOL(__xstat);
+EXPORT_SYMBOL(__lxstat);
+EXPORT_SYMBOL(__lxstat64);
+EXPORT_SYMBOL(lseek);
+EXPORT_SYMBOL(lseek64);
+EXPORT_SYMBOL(chown);
+EXPORT_SYMBOL(truncate);
+EXPORT_SYMBOL(utime);
+EXPORT_SYMBOL(chmod);
+EXPORT_SYMBOL(rename);
+EXPORT_SYMBOL(__xmknod);
+
+EXPORT_SYMBOL(symlink);
+EXPORT_SYMBOL(link);
+EXPORT_SYMBOL(unlink);
+EXPORT_SYMBOL(readlink);
+
+EXPORT_SYMBOL(mkdir);
+EXPORT_SYMBOL(rmdir);
+EXPORT_SYMBOL(opendir);
+EXPORT_SYMBOL(readdir);
+EXPORT_SYMBOL(closedir);
+EXPORT_SYMBOL(seekdir);
+EXPORT_SYMBOL(telldir);
+
+EXPORT_SYMBOL(ioctl);
+
+extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
+			__off64_t __offset);
+extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n,
+			 __off64_t __offset);
+EXPORT_SYMBOL(pread64);
+EXPORT_SYMBOL(pwrite64);
+
+EXPORT_SYMBOL(statfs);
+EXPORT_SYMBOL(statfs64);
+
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(getuid);
+
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(find_iomem);
diff -Nru a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/user_util.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,275 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/mman.h> 
+#include <sys/stat.h>
+#include <sys/ptrace.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include "asm/types.h"
+#include <ctype.h>
+#include <signal.h>
+#include <wait.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sched.h>
+#include <termios.h>
+#include <string.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "mem_user.h"
+#include "init.h"
+#include "helper.h"
+
+#define COMMAND_LINE_SIZE _POSIX_ARG_MAX
+
+char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
+char command_line[COMMAND_LINE_SIZE] = { 0 };
+
+void add_arg(char *cmd_line, char *arg)
+{
+	if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) {
+		printf("add_arg: Too much command line!\n");
+		exit(1);
+	}
+	if(strlen(cmd_line) > 0) strcat(cmd_line, " ");
+	strcat(cmd_line, arg);
+}
+
+void remap_data(void *segment_start, void *segment_end, int w)
+{
+	void *addr;
+	unsigned long size;
+	int data, prot;
+
+	if(w) prot = PROT_WRITE;
+	else prot = 0;
+	prot |= PROT_READ | PROT_EXEC;
+	size = (unsigned long) segment_end - 
+		(unsigned long) segment_start;
+	data = create_mem_file(size);
+	if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, 
+			MAP_SHARED, data, 0)) < 0){
+		perror("mapping new data segment");
+		exit(1);
+	}
+	memcpy(addr, segment_start, size);
+	if(switcheroo(data, prot, addr, segment_start, 
+		      size) < 0){
+		printf("switcheroo failed\n");
+		exit(1);
+	}
+}
+
+void stop(void)
+{
+	while(1) sleep(1000000);
+}
+
+void stack_protections(unsigned long address)
+{
+	int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+        if(mprotect((void *) address, page_size(), prot) < 0)
+		panic("protecting stack failed, errno = %d", errno);
+}
+
+void task_protections(unsigned long address)
+{
+	unsigned long guard = address + page_size();
+	unsigned long stack = guard + page_size();
+	int prot = 0;
+
+	if(mprotect((void *) stack, page_size(), prot) < 0)
+		panic("protecting guard page failed, errno = %d", errno);
+	prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+	if(mprotect((void *) stack, 2 * page_size(), prot) < 0)
+		panic("protecting stack failed, errno = %d", errno);
+}
+
+int wait_for_stop(int pid, int sig, int cont_type, void *relay)
+{
+	sigset_t *relay_signals = relay;
+	int status, ret;
+
+	while(1){
+		if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) ||
+		   !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
+			if(ret < 0){
+				if(errno == EINTR) continue;
+				printk("wait failed, errno = %d\n",
+				       errno);
+			}
+			else if(WIFEXITED(status)) 
+				printk("process exited with status %d\n", 
+				       WEXITSTATUS(status));
+			else if(WIFSIGNALED(status))
+				printk("process exited with signal %d\n", 
+				       WTERMSIG(status));
+			else if((WSTOPSIG(status) == SIGVTALRM) ||
+				(WSTOPSIG(status) == SIGALRM) ||
+				(WSTOPSIG(status) == SIGIO) ||
+				(WSTOPSIG(status) == SIGPROF) ||
+				(WSTOPSIG(status) == SIGCHLD) ||
+				(WSTOPSIG(status) == SIGWINCH) ||
+				(WSTOPSIG(status) == SIGINT)){
+				ptrace(cont_type, pid, 0, WSTOPSIG(status));
+				continue;
+			}
+			else if((relay_signals != NULL) &&
+				sigismember(relay_signals, WSTOPSIG(status))){
+				ptrace(cont_type, pid, 0, WSTOPSIG(status));
+				continue;
+			}
+			else printk("process stopped with signal %d\n", 
+				    WSTOPSIG(status));
+			panic("wait_for_stop failed to wait for %d to stop "
+			      "with %d\n", pid, sig);
+		}
+		return(status);
+	}
+}
+
+int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
+{
+	int pid;
+
+	pid = clone(fn, sp, flags, arg);
+ 	if(pid < 0) return(-1);
+	wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+	ptrace(PTRACE_CONT, pid, 0, 0);
+	return(pid);
+}
+
+int raw(int fd, int complain)
+{
+	struct termios tt;
+	int err;
+
+	tcgetattr(fd, &tt);
+	cfmakeraw(&tt);
+	err = tcsetattr(fd, TCSANOW, &tt);
+	if((err < 0) && complain){
+		printk("tcsetattr failed, errno = %d\n", errno);
+		return(-errno);
+	}
+	return(0);
+}
+
+void setup_machinename(char *machine_out)
+{
+	struct utsname host;
+
+	uname(&host);
+	strcpy(machine_out, host.machine);
+}
+
+char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
+
+void setup_hostinfo(void)
+{
+	struct utsname host;
+
+	uname(&host);
+	sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
+		host.release, host.version, host.machine);
+}
+
+void close_fd(int fd)
+{
+	close(fd);
+}
+
+char *tempdir = NULL;
+
+static void __init find_tempdir(void)
+{
+	char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+	int i;
+	char *dir = NULL;
+
+	if(tempdir != NULL) return;	/* We've already been called */
+	for(i = 0; dirs[i]; i++){
+		dir = getenv(dirs[i]);
+		if(dir != NULL) break;
+	}
+	if(dir == NULL) dir = "/tmp";
+	else if(*dir == '\0') dir = NULL;
+	if(dir != NULL) {
+		tempdir = malloc(strlen(dir) + 2);
+		if(tempdir == NULL){
+			fprintf(stderr, "Failed to malloc tempdir, "
+				"errno = %d\n", errno);
+			return;
+		}
+		strcpy(tempdir, dir);
+		strcat(tempdir, "/");
+	}
+}
+
+int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+{
+	char tempname[MAXPATHLEN];
+	int fd;
+
+	find_tempdir();
+	if (*template != '/')
+		strcpy(tempname, tempdir);
+	else
+		*tempname = 0;
+	strcat(tempname, template);
+	if((fd = mkstemp(tempname)) < 0){
+		fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
+			strerror(errno));
+		return -1;
+	}
+	if(do_unlink && (unlink(tempname) < 0)){
+		perror("unlink");
+		return -1;
+	}
+	if(out_tempname){
+		if((*out_tempname = strdup(tempname)) == NULL){
+			perror("strdup");
+			return -1;
+		}
+	}
+	return(fd);
+}
+
+int user_read(int fd, char *buf, int len)
+{
+	int err;
+
+	err = read(fd, buf, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int user_write(int fd, char *buf, int len)
+{
+	int err;
+
+	err = write(fd, buf, len);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/link.ld.in b/arch/um/link.ld.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/link.ld.in	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,143 @@
+OUTPUT_FORMAT("ELF_FORMAT")
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  . = START() + SIZEOF_HEADERS;
+
+  . = ALIGN(4096);
+  __binary_start = .;
+  .thread_private : {
+    __start_thread_private = .;
+    errno = .;
+    . += 4;
+    arch/um/kernel/unmap_fin.o (.data)
+    __end_thread_private = .;
+  }
+  . = ALIGN(4096);
+  .remap : { arch/um/kernel/unmap_fin.o (.text) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  . = ALIGN(4096);
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  .fini      : { *(.fini)    } =0x9090
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  _etext = .;
+  PROVIDE (etext = .);
+
+  . = ALIGN(4096);
+  PROVIDE (_sdata = .);
+
+  .unprotected : { *(.unprotected) }
+  . = ALIGN(4096);
+  PROVIDE (_unprotected_end = .);
+
+  . = ALIGN(4096);
+  __uml_setup_start = .;
+  .uml.setup.init : { *(.uml.setup.init) }
+  __uml_setup_end = .;
+  __uml_help_start = .;
+  .uml.help.init : { *(.uml.help.init) }
+  __uml_help_end = .;
+  __uml_postsetup_start = .;
+  .uml.postsetup.init : { *(.uml.postsetup.init) }
+  __uml_postsetup_end = .;
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
+  __initcall_end = .;
+  __uml_initcall_start = .;
+  .uml.initcall.init : { *(.uml.initcall.init) }
+  __uml_initcall_end = .;
+  __init_end = .;
+  __exitcall_begin = .;
+  .exitcall : { *(.exitcall.exit) }
+  __exitcall_end = .;
+  __uml_exitcall_begin = .;
+  .uml.exitcall : { *(.uml.exitcall.exit) }
+  __uml_exitcall_end = .;
+
+  .data.init : { *(.data.init) }
+  .data    :
+  {
+    . = ALIGN(16384);		/* init_task */
+    *(.data.init_task)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  . = ALIGN(0x1000);
+  .sbss      : 
+  {
+   __bss_start = .;
+   PROVIDE(_bss_start = .);
+   *(.sbss) 
+   *(.scommon) 
+  }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -Nru a/arch/um/main.c b/arch/um/main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/main.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,217 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h> 
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <asm/page.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "mem_user.h"
+#include "user.h"
+#include "init.h"
+
+unsigned long stacksizelim;
+
+char *linux_prog;
+
+#define PGD_BOUND (4 * 1024 * 1024)
+#define STACKSIZE (8 * 1024 * 1024)
+#define THREAD_NAME_LEN (256)
+
+char padding[THREAD_NAME_LEN] = { [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' };
+
+static void set_stklim(void)
+{
+	struct rlimit lim;
+
+	if(getrlimit(RLIMIT_STACK, &lim) < 0){
+		perror("getrlimit");
+		exit(1);
+	}
+	if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){
+		lim.rlim_cur = STACKSIZE;
+		if(setrlimit(RLIMIT_STACK, &lim) < 0){
+			perror("setrlimit");
+			exit(1);
+		}
+	}
+	stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
+}
+
+static __init void do_uml_initcalls(void)
+{
+	initcall_t *call;
+
+	call = &__uml_initcall_start;
+	while (call < &__uml_initcall_end){;
+		(*call)();
+		call++;
+	}
+}
+
+extern int uml_exitcode;
+
+int main(int argc, char **argv, char **envp)
+{
+	sigset_t mask;
+	int ret, i;
+	char **new_argv;
+
+	/* Enable all signals - in some environments, we can enter with
+	 * some signals blocked
+	 */
+
+	sigemptyset(&mask);
+	if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
+		perror("sigprocmask");
+		exit(1);
+	}
+
+	/* Allocate memory for thread command lines */
+	if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
+		new_argv = malloc((argc + 2) * sizeof(char*));
+		if(!new_argv) {
+			perror("Allocating extended argv");
+			exit(1);
+		}	
+		
+		new_argv[0] = argv[0];
+		new_argv[1] = padding;
+		
+		for(i = 2; i <= argc; i++)
+			new_argv[i] = argv[i - 1];
+		new_argv[argc + 1] = NULL;
+		
+#ifdef PROFILING
+		disable_profile_timer();
+#endif
+		execvp(new_argv[0], new_argv);
+		perror("execing with extended args");
+		exit(1);
+	}	
+
+	linux_prog = argv[0];
+
+	set_stklim();
+	set_task_sizes(0);
+
+	if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
+		perror("Mallocing argv");
+		exit(1);
+	}
+	for(i=0;i<argc;i++){
+		if((new_argv[i] = strdup(argv[i])) == NULL){
+			perror("Mallocing an arg");
+			exit(1);
+		}
+	}
+	new_argv[argc] = NULL;
+
+	do_uml_initcalls();
+	ret = linux_main(argc, argv);
+	
+	/* Reboot */
+	if(ret){
+		printf("\n");
+		execvp(new_argv[0], new_argv);
+		perror("Failed to exec kernel");
+		ret = 1;
+	}
+	printf("\n");
+	return(uml_exitcode);
+}
+
+int allocating_monbuf = 0;
+
+#ifdef PROFILING
+extern void __real___monstartup (unsigned long, unsigned long);
+
+void __wrap___monstartup (unsigned long lowpc, unsigned long highpc)
+{
+	allocating_monbuf = 1;
+	__real___monstartup(lowpc, highpc);
+	allocating_monbuf = 0;
+	get_profile_timer();
+}
+#endif
+
+extern void *__real_malloc(int);
+extern unsigned long host_task_size;
+
+static void *gmon_buf = NULL;
+
+void *__wrap_malloc(int size)
+{
+	if(allocating_monbuf){
+		unsigned long start, end;
+		int fd;
+
+		/* Turn this off now in case create_mem_file tries allocating
+		 * memory
+		 */
+		allocating_monbuf = 0;
+		fd = create_mem_file(size);
+
+		/* Calculate this here because linux_main hasn't run yet
+		 * and host_task_size figures in STACK_TOP, which figures
+		 * in kmem_end.
+		 */
+		set_task_sizes(0);
+
+		/* Same with stacksizelim */
+		set_stklim();
+
+		end = get_kmem_end();
+		start = (end - size) & PAGE_MASK;
+		gmon_buf = mmap((void *) start, size, PROT_READ | PROT_WRITE,
+			    MAP_SHARED | MAP_FIXED, fd, 0);
+		if(gmon_buf != (void *) start){
+			perror("Creating gprof buffer");
+			exit(1);
+		}
+		set_kmem_end(start);
+		return(gmon_buf);
+	}
+	if(kmalloc_ok) return(um_kmalloc(size));
+	else return(__real_malloc(size));
+}
+
+void *__wrap_calloc(int n, int size)
+{
+	void *ptr = __wrap_malloc(n * size);
+
+	if(ptr == NULL) return(NULL);
+	memset(ptr, 0, n * size);
+	return(ptr);
+}
+
+extern void __real_free(void *);
+
+void __wrap_free(void *ptr)
+{
+	/* Could maybe unmap the gmon buffer, but we're just about to
+	 * exit anyway
+	 */
+	if(ptr == gmon_buf) return;
+	if(kmalloc_ok) kfree(ptr);
+	else __real_free(ptr);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,17 @@
+# 
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+O_TARGET = os.o
+
+obj-y = file.o process.o tty.o
+
+include $(TOPDIR)/Rules.make
+
+$(obj-y) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
+
+archmrproper:
diff -Nru a/arch/um/os-Linux/drivers/Makefile b/arch/um/os-Linux/drivers/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,31 @@
+# 
+# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+O_TARGET := drivers.o
+
+list-multi := tuntap.o ethertap.o
+
+ethertap-objs := ethertap_kern.o ethertap_user.o
+tuntap-objs := tuntap_kern.o tuntap_user.o
+
+obj-y = 
+obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
+obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
+
+USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
+
+USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
+
+include $(TOPDIR)/Rules.make
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+ethertap.o : $(ethertap-objs)
+
+tuntap.o : $(tuntap-objs)
+
+$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)'
+	$(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs)
diff -Nru a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/etap.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,27 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "net_user.h"
+
+struct ethertap_data {
+	char *dev_name;
+	char *gate_addr;
+	int data_fd;
+	int control_fd;
+	void *dev;
+};
+
+extern struct net_user_info ethertap_user_info;
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/etap_kern.h b/arch/um/os-Linux/drivers/etap_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/etap_kern.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ETHERTAP_KERN_H
+#define __UM_ETHERTAP_KERN_H
+
+#include "net_kern.h"
+
+extern int ethertap_setup(char *arg, struct uml_net *dev);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/init.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "etap.h"
+#include "etap_kern.h"
+
+struct ethertap_setup {
+	char *dev_name;
+	char *gate_addr;
+};
+
+struct ethertap_setup ethertap_priv[MAX_UML_NETDEV] = { 
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		dev_name:	NULL,
+		gate_addr:	NULL,
+	}
+};
+
+static void etap_init(struct net_device *dev, int index)
+{
+	struct uml_net_private *pri;
+	struct ethertap_data *epri;
+
+	init_etherdev(dev, 0);
+	pri = dev->priv;
+	epri = (struct ethertap_data *) pri->user;
+	epri->dev_name = ethertap_priv[index].dev_name;
+	epri->gate_addr = ethertap_priv[index].gate_addr;
+	printk("ethertap backend - %s", epri->dev_name);
+	if(epri->gate_addr != NULL) 
+		printk(", IP = %s", epri->gate_addr);
+	printk("\n");
+	epri->data_fd = -1;
+	epri->control_fd = -1;
+}
+
+static unsigned short etap_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	int len;
+
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
+	if(*skb == NULL) return(-ENOMEM);
+	len = net_recvfrom(fd, (*skb)->mac.raw, 
+			   (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
+	if(len <= 0) return(len);
+	skb_pull(*skb, 2);
+	len -= 2;
+	return(len);
+}
+
+static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
+{
+	if(skb_headroom(*skb) < 2){
+	  	struct sk_buff *skb2;
+
+		skb2 = skb_realloc_headroom(*skb, 2);
+		dev_kfree_skb(*skb);
+		if (skb2 == NULL) return(-ENOMEM);
+		*skb = skb2;
+	}
+	skb_push(*skb, 2);
+	return(net_send(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info ethertap_kern_info = {
+	init:			etap_init,
+	protocol:		etap_protocol,
+	read:			etap_read,
+	write: 			etap_write,
+};
+
+static int ethertap_count = 0;
+
+int ethertap_setup(char *str, struct uml_net *dev)
+{
+	struct ethertap_setup *pri;
+	int err;
+
+	pri = &ethertap_priv[ethertap_count];
+	err = tap_setup_common(str, "ethertap", &pri->dev_name, dev->mac,
+			       &dev->have_mac, &pri->gate_addr);
+	if(err) return(err);
+	if(pri->dev_name == NULL){
+		printk("ethertap_setup : Missing tap device name\n");
+		return(1);
+	}
+
+	dev->user = &ethertap_user_info;
+	dev->kern = &ethertap_kern_info;
+	dev->private_size = sizeof(struct ethertap_data);
+	dev->transport_index = ethertap_count++;
+	return(0);
+}
+
+static struct transport ethertap_transport = {
+	list :	LIST_HEAD_INIT(ethertap_transport.list),
+	name :	"ethertap",
+	setup : ethertap_setup
+};
+
+static int register_ethertap(void)
+{
+	register_transport(&ethertap_transport);
+	return(1);
+}
+
+__initcall(register_ethertap);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/ethertap_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ * Licensed under the GPL.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include "user.h"
+#include "kern_util.h"
+#include "net_user.h"
+#include "etap.h"
+#include "helper.h"
+#include "os.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void etap_user_init(void *data, void *dev)
+{
+	struct ethertap_data *pri = data;
+
+	pri->dev = dev;
+}
+
+struct addr_change {
+	enum { ADD_ADDR, DEL_ADDR } what;
+	unsigned char addr[4];
+	unsigned char netmask[4];
+};
+
+static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
+			int fd)
+{
+	struct addr_change change;
+	void *output;
+
+	change.what = op;
+	memcpy(change.addr, addr, sizeof(change.addr));
+	memcpy(change.netmask, netmask, sizeof(change.netmask));
+	if(write(fd, &change, sizeof(change)) != sizeof(change))
+		printk("etap_change - request failed, errno = %d\n",
+		       errno);
+	output = um_kmalloc(page_size());
+	if(output == NULL)
+		printk("etap_change : Failed to allocate output buffer\n");
+	read_output(fd, output, page_size());
+	if(output != NULL){
+		printk("%s", output);
+		kfree(output);
+	}
+}
+
+static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
+			   void *arg)
+{
+	etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
+}
+
+static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
+			    void *arg)
+{
+	etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
+}
+
+struct etap_pre_exec_data {
+	int control_remote;
+	int control_me;
+	int data_me;
+};
+
+static void etap_pre_exec(void *arg)
+{
+	struct etap_pre_exec_data *data = arg;
+
+	dup2(data->control_remote, 1);
+	close(data->data_me);
+	close(data->control_me);
+}
+
+static int etap_tramp(char *dev, char *gate, int control_me, 
+		      int control_remote, int data_me, int data_remote)
+{
+	struct etap_pre_exec_data pe_data;
+	int pid, status, err;
+	char version_buf[sizeof("nnnnn\0")];
+	char data_fd_buf[sizeof("nnnnnn\0")];
+	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+	char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
+			       data_fd_buf, gate_buf, NULL };
+	char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 
+				 dev, data_fd_buf, NULL };
+	char **args, c;
+
+	sprintf(data_fd_buf, "%d", data_remote);
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+	if(gate != NULL){
+		strcpy(gate_buf, gate);
+		args = setup_args;
+	}
+	else args = nosetup_args;
+
+	err = 0;
+	pe_data.control_remote = control_remote;
+	pe_data.control_me = control_me;
+	pe_data.data_me = data_me;
+	pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
+
+	if(pid < 0) err = errno;
+	close(data_remote);
+	close(control_remote);
+	if(read(control_me, &c, sizeof(c)) != sizeof(c)){
+		printk("etap_tramp : read of status failed, errno = %d\n",
+		       errno);
+		return(EINVAL);
+	}
+	if(c != 1){
+		printk("etap_tramp : uml_net failed\n");
+		err = EINVAL;
+		if(waitpid(pid, &status, 0) < 0) err = errno;
+		else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){
+			printk("uml_net didn't exit with status 1\n");
+		}
+	}
+	return(err);
+}
+
+static int etap_open(void *data)
+{
+	struct ethertap_data *pri = data;
+	char *output;
+	int data_fds[2], control_fds[2], err, output_len;
+
+	err = tap_open_common(pri->dev, pri->gate_addr);
+	if(err) return(err);
+
+	err = os_pipe(data_fds, 0, 0);
+	if(err){
+		printk("data os_pipe failed - errno = %d\n", -err);
+		return(err);
+	}
+
+	err = os_pipe(control_fds, 1, 0);
+	if(err){
+		printk("control os_pipe failed - errno = %d\n", -err);
+		return(err);
+	}
+	
+	err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 
+			 control_fds[1], data_fds[0], data_fds[1]);
+	output_len = page_size();
+	output = um_kmalloc(output_len);
+	read_output(control_fds[0], output, output_len);
+
+	if(output == NULL)
+		printk("etap_open : failed to allocate output buffer\n");
+	else {
+		printk("%s", output);
+		kfree(output);
+	}
+
+	if(err != 0){
+		printk("etap_tramp failed - errno = %d\n", err);
+		return(-err);
+	}
+
+	pri->data_fd = data_fds[0];
+	pri->control_fd = control_fds[0];
+	iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
+	return(data_fds[0]);
+}
+
+static void etap_close(int fd, void *data)
+{
+	struct ethertap_data *pri = data;
+
+	iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
+	close(fd);
+	os_shutdown_socket(pri->data_fd, 1, 1);
+	close(pri->data_fd);
+	pri->data_fd = -1;
+	close(pri->control_fd);
+	pri->control_fd = -1;
+}
+
+static int etap_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
+			  void *data)
+{
+	struct ethertap_data *pri = data;
+
+	tap_check_ips(pri->gate_addr, addr);
+	if(pri->control_fd == -1) return;
+	etap_open_addr(addr, netmask, &pri->control_fd);
+}
+
+static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 
+			  void *data)
+{
+	struct ethertap_data *pri = data;
+
+	if(pri->control_fd == -1) return;
+	etap_close_addr(addr, netmask, &pri->control_fd);
+}
+
+struct net_user_info ethertap_user_info = {
+	init:		etap_user_init,
+	open:		etap_open,
+	close:	 	etap_close,
+	remove:	 	NULL,
+	set_mtu:	etap_set_mtu,
+	add_address:	etap_add_addr,
+	delete_address: etap_del_addr,
+	max_packet:	MAX_PACKET - ETH_HEADER_ETHERTAP
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/tuntap.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TUNTAP_H
+#define __UM_TUNTAP_H
+
+#include "net_user.h"
+
+struct tuntap_data {
+	char *dev_name;
+	int fixed_config;
+	char *gate_addr;
+	int fd;
+	void *dev;
+	unsigned char hw_addr[ETH_ADDR_LEN];
+	int hw_setup;
+};
+
+extern struct net_user_info tuntap_user_info;
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,116 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/netdevice.h"
+#include "linux/etherdevice.h"
+#include "linux/skbuff.h"
+#include "linux/init.h"
+#include "asm/errno.h"
+#include "net_kern.h"
+#include "net_user.h"
+#include "tuntap.h"
+
+struct tuntap_setup {
+	char *dev_name;
+	char *gate_addr;
+};
+
+struct tuntap_setup tuntap_priv[MAX_UML_NETDEV] = { 
+	[ 0 ... MAX_UML_NETDEV - 1 ] =
+	{
+		dev_name:	NULL,
+		gate_addr:	NULL,
+	}
+};
+
+static void tuntap_init(struct net_device *dev, int index)
+{
+	struct uml_net_private *pri;
+	struct tuntap_data *tpri;
+
+	init_etherdev(dev, 0);
+	pri = dev->priv;
+	tpri = (struct tuntap_data *) pri->user;
+	tpri->dev_name = tuntap_priv[index].dev_name;
+	tpri->fixed_config = (tpri->dev_name != NULL);
+	tpri->gate_addr = tuntap_priv[index].gate_addr;
+	printk("TUN/TAP backend - ");
+	if(tpri->gate_addr != NULL) 
+		printk("IP = %s", tpri->gate_addr);
+	printk("\n");
+	tpri->fd = -1;
+}
+
+static unsigned short tuntap_protocol(struct sk_buff *skb)
+{
+	return(eth_type_trans(skb, skb->dev));
+}
+
+static int tuntap_read(int fd, struct sk_buff **skb, 
+		       struct uml_net_private *lp)
+{
+	*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+	if(*skb == NULL) return(-ENOMEM);
+	return(net_read(fd, (*skb)->mac.raw, 
+			(*skb)->dev->mtu + ETH_HEADER_OTHER));
+}
+
+static int tuntap_write(int fd, struct sk_buff **skb, 
+			struct uml_net_private *lp)
+{
+	return(net_write(fd, (*skb)->data, (*skb)->len));
+}
+
+struct net_kern_info tuntap_kern_info = {
+	init:			tuntap_init,
+	protocol:		tuntap_protocol,
+	read:			tuntap_read,
+	write: 			tuntap_write,
+};
+
+static int tuntap_count = 0;
+
+int tuntap_setup(char *str, struct uml_net *dev)
+{
+	struct tuntap_setup *pri;
+	int err;
+
+	pri = &tuntap_priv[tuntap_count];
+	err = tap_setup_common(str, "tuntap", &pri->dev_name, dev->mac,  
+			       &dev->have_mac, &pri->gate_addr);
+	if(err) return(err);
+
+	dev->user = &tuntap_user_info;
+	dev->kern = &tuntap_kern_info;
+	dev->private_size = sizeof(struct tuntap_data);
+	dev->transport_index = tuntap_count++;
+	return(0);
+}
+
+static struct transport tuntap_transport = {
+	list :	LIST_HEAD_INIT(tuntap_transport.list),
+	name :	"tuntap",
+	setup : tuntap_setup
+};
+
+static int register_tuntap(void)
+{
+	register_transport(&tuntap_transport);
+	return(1);
+}
+
+__initcall(register_tuntap);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/tuntap_kern.h b/arch/um/os-Linux/drivers/tuntap_kern.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/tuntap_kern.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TUNTAP_KERN_H
+#define __UM_TUNTAP_KERN_H
+
+#include "net_kern.h"
+
+extern int tuntap_setup(char *arg, struct uml_net *dev);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/drivers/tuntap_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,223 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include "net_user.h"
+#include "tuntap.h"
+#include "kern_util.h"
+#include "user.h"
+#include "helper.h"
+#include "os.h"
+
+#define MAX_PACKET ETH_MAX_PACKET
+
+void tuntap_user_init(void *data, void *dev)
+{
+	struct tuntap_data *pri = data;
+
+	pri->dev = dev;
+}
+
+static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct tuntap_data *pri = data;
+
+	tap_check_ips(pri->gate_addr, addr);
+	if((pri->fd == -1) || pri->fixed_config) return;
+	open_addr(addr, netmask, pri->dev_name);
+}
+
+static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
+			    void *data)
+{
+	struct tuntap_data *pri = data;
+
+	if((pri->fd == -1) || pri->fixed_config) return;
+	close_addr(addr, netmask, pri->dev_name);
+}
+
+struct tuntap_pre_exec_data {
+	int stdout;
+	int close_me;
+};
+
+static void tuntap_pre_exec(void *arg)
+{
+	struct tuntap_pre_exec_data *data = arg;
+	
+	dup2(data->stdout, 1);
+	close(data->close_me);
+}
+
+static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
+			     char *buffer, int buffer_len, int *used_out)
+{
+	struct tuntap_pre_exec_data data;
+	char version_buf[sizeof("nnnnn\0")];
+	char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
+			 NULL };
+	char buf[CMSG_SPACE(sizeof(*fd_out))];
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct iovec iov;
+	int pid, n;
+
+	sprintf(version_buf, "%d", UML_NET_VERSION);
+
+	data.stdout = remote;
+	data.close_me = me;
+
+	pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
+
+	if(pid < 0) return(-pid);
+
+	close(remote);
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	if(buffer != NULL){
+		iov = ((struct iovec) { buffer, buffer_len });
+		msg.msg_iov = &iov;
+		msg.msg_iovlen = 1;
+	}
+	else {
+		msg.msg_iov = NULL;
+		msg.msg_iovlen = 0;
+	}
+	msg.msg_control = buf;
+	msg.msg_controllen = sizeof(buf);
+	msg.msg_flags = 0;
+	n = recvmsg(me, &msg, 0);
+	*used_out = n;
+	if(n < 0){
+		printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
+		       errno);
+		return(errno);
+	}
+	waitpid(pid, NULL, 0);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if(cmsg == NULL){
+		printk("tuntap_open_tramp : didn't receive a message\n");
+		return(EINVAL);
+	}
+	if((cmsg->cmsg_level != SOL_SOCKET) || 
+	   (cmsg->cmsg_type != SCM_RIGHTS)){
+		printk("tuntap_open_tramp : didn't receive a descriptor\n");
+		return(EINVAL);
+	}
+	*fd_out = ((int *) CMSG_DATA(cmsg))[0];
+	return(0);
+}
+
+static int tuntap_open(void *data)
+{
+	struct ifreq ifr;
+	struct tuntap_data *pri = data;
+	char *output, *buffer;
+	int err, fds[2], len, used;
+
+	err = tap_open_common(pri->dev, pri->gate_addr);
+	if(err) return(err);
+
+	if(pri->fixed_config){
+		if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){
+			printk("Failed to open /dev/net/tun, errno = %d\n",
+			       errno);
+			return(-errno);
+		}
+		memset(&ifr, 0, sizeof(ifr));
+		ifr.ifr_flags = IFF_TAP;
+		strncpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name) - 1);
+		if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
+			printk("TUNSETIFF failed, errno = %d", errno);
+			close(pri->fd);
+			return(-errno);
+		}
+	}
+	else {
+		err = os_pipe(fds, 0, 0);
+		if(err){
+			printk("tuntap_open : os_pipe failed - errno = %d\n",
+			       -err);
+			return(err);
+		}
+
+		buffer = get_output_buffer(&len);
+		if(buffer != NULL) len--;
+		used = 0;
+
+		err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
+					fds[1], buffer, len, &used);
+
+		output = buffer;
+		if(err == 0){
+			pri->dev_name = uml_strdup(buffer);
+			output += IFNAMSIZ;
+			printk(output);
+			free_output_buffer(buffer);
+		}
+		else {
+			printk(output);
+			free_output_buffer(buffer);
+			printk("tuntap_open_tramp failed - errno = %d\n", err);
+			return(-err);
+		}
+		close(fds[0]);
+		iter_addresses(pri->dev, open_addr, pri->dev_name);
+	}
+
+	return(pri->fd);
+}
+
+static void tuntap_close(int fd, void *data)
+{
+	struct tuntap_data *pri = data;
+
+	if(!pri->fixed_config) 
+		iter_addresses(pri->dev, close_addr, pri->dev_name);
+	close(fd);
+	pri->fd = -1;
+}
+
+static int tuntap_set_mtu(int mtu, void *data)
+{
+	return(mtu);
+}
+
+struct net_user_info tuntap_user_info = {
+	init:		tuntap_user_init,
+	open:		tuntap_open,
+	close:	 	tuntap_close,
+	remove:	 	NULL,
+	set_mtu:	tuntap_set_mtu,
+	add_address:	tuntap_add_addr,
+	delete_address: tuntap_del_addr,
+	max_packet:	MAX_PACKET
+};
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/file.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,344 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include "os.h"
+#include "user.h"
+#include "kern_util.h"
+
+int os_file_type(char *file)
+{
+	struct stat64 buf;
+
+	if(stat64(file, &buf) == -1)
+		return(-errno);
+
+	if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
+	else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
+	else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
+	else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
+	else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
+	else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
+	else return(OS_TYPE_FILE);
+}
+
+int os_file_mode(char *file, struct openflags *mode_out)
+{
+	*mode_out = OPENFLAGS();
+
+	if(!access(file, W_OK)) *mode_out = of_write(*mode_out);
+	else if(errno != EACCES) 
+		return(-errno);
+
+	if(!access(file, R_OK)) *mode_out = of_read(*mode_out);
+	else if(errno != EACCES) 
+		return(-errno);
+
+	return(0);
+}
+
+int os_open_file(char *file, struct openflags flags, int mode)
+{
+	int fd, f = 0;
+
+	if(flags.r && flags.w) f = O_RDWR;
+	else if(flags.r) f = O_RDONLY;
+	else if(flags.w) f = O_WRONLY;
+	else f = 0;
+
+	if(flags.s) f |= O_SYNC;
+	if(flags.c) f |= O_CREAT;
+	if(flags.t) f |= O_TRUNC;
+	if(flags.e) f |= O_EXCL;
+
+	fd = open64(file, f, mode);
+	if(fd < 0) return(-errno);
+	return(fd);
+}
+
+int os_connect_socket(char *name)
+{
+	struct sockaddr_un sock;
+	int fd, err;
+
+	sock.sun_family = AF_UNIX;
+	snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if(fd < 0)
+		return(fd);
+
+	err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
+	if(err)
+		return(err);
+
+	return(fd);
+}
+
+void os_close_file(int fd)
+{
+	close(fd);
+}
+
+int os_seek_file(int fd, __u64 offset)
+{
+	__u64 actual;
+
+	actual = lseek64(fd, offset, SEEK_SET);
+	if(actual != offset) return(-errno);
+	return(0);
+}
+
+int os_read_file(int fd, char *buf, int len)
+{
+	int n;
+
+	/* Force buf into memory if it's not already. */
+
+	/* XXX This fails if buf is kernel memory */
+#ifdef notdef
+	if(copy_to_user_proc(buf, &c, sizeof(c)))
+		return(-EFAULT);
+#endif
+
+	n = read(fd, buf, len);
+	if(n < 0)
+		return(-errno);
+	return(n);
+}
+
+int os_write_file(int fd, char *buf, int count)
+{
+	int n;
+
+	/* Force buf into memory if it's not already. */
+	
+	/* XXX This fails if buf is kernel memory */
+#ifdef notdef
+	if(copy_to_user_proc(buf, buf, buf[0]))
+		return(-EFAULT);
+#endif
+
+	n = write(fd, buf, count);
+	if(n < 0)
+		return(-errno);
+	return(n);
+}
+
+int os_file_size(char *file, long long *size_out)
+{
+	struct stat64 buf;
+
+	if(stat64(file, &buf) == -1){
+		printk("Couldn't stat \"%s\" : errno = %d\n", file, errno);
+		return(-errno);
+	}
+	if(S_ISBLK(buf.st_mode)){
+		int fd, blocks;
+
+		if((fd = open64(file, O_RDONLY)) < 0){
+			printk("Couldn't open \"%s\", errno = %d\n", file,
+			       errno);
+			return(-errno);
+		}
+		if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
+			printk("Couldn't get the block size of \"%s\", "
+			       "errno = %d\n", file, errno);
+			close(fd);
+			return(-errno);
+		}
+		*size_out = ((long long) blocks) * 512;
+		close(fd);
+		return(0);
+	}
+	*size_out = buf.st_size;
+	return(0);
+}
+
+int os_pipe(int *fds, int stream, int close_on_exec)
+{
+	int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
+
+	err = socketpair(AF_UNIX, type, 0, fds);
+	if(err) return(-errno);
+
+	if(!close_on_exec)
+		return(0);
+
+	if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0))
+		printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", 
+		       errno);
+
+	return(0);
+}
+
+int os_set_fd_async(int fd, int owner)
+{
+	if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
+		printk("os_set_fd_async : failed to set O_ASYNC and "
+		       "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
+		return(-errno);
+	}
+#ifdef notdef
+	if(fcntl(fd, F_SETFD, 1) < 0){
+		printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
+		       "errno = %d\n", errno);
+	}
+#endif
+
+	if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
+	   (fcntl(fd, F_SETOWN, owner) < 0)){
+		printk("os_set_fd_async : Failed to fcntl F_SETOWN "
+		       "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, 
+		       owner, errno);
+		return(-errno);
+	}
+
+	return(0);
+}
+
+int os_set_fd_block(int fd, int blocking)
+{
+	int flags;
+
+	flags = fcntl(fd, F_GETFL);
+
+	if(blocking) flags &= ~O_NONBLOCK;
+	else flags |= O_NONBLOCK;
+
+	if(fcntl(fd, F_SETFL, flags) < 0){
+		printk("Failed to change blocking on fd # %d, errno = %d\n",
+		       fd, errno);
+		return(-errno);
+	}
+	return(0);
+}
+
+int os_accept_connection(int fd)
+{
+	int err;
+
+	err = accept(fd, NULL, 0);
+	if(err) 
+		return(-errno);
+	return(0);
+}
+
+#ifndef SHUT_RD
+#define SHUT_RD 0
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 1
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 2
+#endif
+
+int os_shutdown_socket(int fd, int r, int w)
+{
+	int what, err;
+
+	if(r && w) what = SHUT_RDWR;
+	else if(r) what = SHUT_RD;
+	else if(w) what = SHUT_WR;
+	else {
+		printk("os_shutdown_socket : neither r or w was set\n");
+		return(-EINVAL);
+	}
+	err = shutdown(fd, what);
+	if(err)
+		return(-errno);
+	return(0);
+}
+
+int os_rcv_fd(int fd, int *helper_pid_out)
+{
+	int new, n;
+	char buf[CMSG_SPACE(sizeof(new))];
+	struct msghdr msg;
+	struct cmsghdr *cmsg;
+	struct iovec iov;
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	iov = ((struct iovec) { iov_base : helper_pid_out,
+				iov_len :  sizeof(*helper_pid_out) });
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = buf;
+	msg.msg_controllen = sizeof(buf);
+	msg.msg_flags = 0;
+
+	n = recvmsg(fd, &msg, 0);
+	if(n < 0){
+		printk("rcv_fd : recvmsg failed - errno = %d\n", errno);
+		return(-1);
+	}
+	else if(n != sizeof(iov.iov_len))
+		*helper_pid_out = -1;
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	if(cmsg == NULL){
+		printk("rcv_fd didn't receive anything, error = %d\n", errno);
+		return(-1);
+	}
+	if((cmsg->cmsg_level != SOL_SOCKET) || 
+	   (cmsg->cmsg_type != SCM_RIGHTS)){
+		printk("rcv_fd didn't receive a descriptor\n");
+		return(-1);
+	}
+
+	new = ((int *) CMSG_DATA(cmsg))[0];
+	return(new);
+}
+
+int create_unix_socket(char *file, int len)
+{
+	struct sockaddr_un addr;
+	int sock, err;
+
+	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (sock < 0){
+		printk("create_unix_socket - socket failed, errno = %d\n",
+		       errno);
+		return(-errno);
+	}
+
+	addr.sun_family = AF_UNIX;
+
+	/* XXX Be more careful about overflow */
+	snprintf(addr.sun_path, len, "%s", file);
+
+	err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0){
+		printk("create_listening_socket - bind failed, errno = %d\n",
+		       errno);
+		return(-errno);
+	}
+
+	return(sock);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/include/file.h b/arch/um/os-Linux/include/file.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/include/file.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,22 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __OS_FILE_H__
+#define __OS_FILE_H__
+
+#define DEV_NULL "/dev/null"
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/process.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,102 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include "os.h"
+#include "user.h"
+
+unsigned long os_process_pc(int pid)
+{
+	char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
+	unsigned long pc;
+	int fd;
+
+	sprintf(proc_stat, "/proc/%d/stat", pid);
+	fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
+	if(fd < 0){
+		printk("os_process_pc - couldn't open '%s', errno = %d\n", 
+		       proc_stat, errno);
+		return(-1);
+	}
+	if(read(fd, buf, sizeof(buf)) < 0){
+		printk("os_process_pc - couldn't read '%s', errno = %d\n", 
+		       proc_stat, errno);
+		close(fd);
+		return(-1);
+	}
+	close(fd);
+	pc = -1;
+	if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d "
+		  "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+		  "%*d %*d %*d %*d %ld", &pc) != 1){
+		printk("os_process_pc - couldn't find pc in '%s'\n", buf);
+	}
+	return(pc);
+}
+
+int os_process_parent(int pid)
+{
+	char stat[sizeof("/proc/nnnnn/stat\0")];
+	char data[256];
+	int parent, n, fd;
+
+	if(pid == -1) return(-1);
+
+	snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
+	fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
+	if(fd < 0){
+		printk("Couldn't open '%s', errno = %d\n", stat, -fd);
+		return(-1);
+	}
+
+	n = read(fd, data, sizeof(data));
+	close(fd);
+
+	if(n < 0){
+		printk("Couldn't read '%s', errno = %d\n", stat);
+		return(-1);
+	}
+
+	parent = -1;
+	/* XXX This will break if there is a space in the command */
+	n = sscanf(data, "%*d %*s %*c %d", &parent);
+	if(n != 1) printk("Failed to scan '%s'\n", data);
+
+	return(parent);
+}
+
+void os_stop_process(int pid)
+{
+	kill(pid, SIGSTOP);
+}
+
+void os_kill_process(int pid)
+{
+	kill(pid, SIGKILL);
+}
+
+void os_usr1_process(int pid)
+{
+	kill(pid, SIGUSR1);
+}
+
+int os_getpid(void)
+{
+	return(getpid());
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/os-Linux/tty.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,61 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include "os.h"
+#include "user.h"
+#include "kern_util.h"
+
+struct grantpt_info {
+	int fd;
+	int res;
+	int err;
+};
+
+static void grantpt_cb(void *arg)
+{
+	struct grantpt_info *info = arg;
+
+	info->res = grantpt(info->fd);
+	info->err = errno;
+}
+
+int get_pty(void)
+{
+	struct grantpt_info info;
+	int fd;
+
+	if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){
+		printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n",
+		       errno);
+		return(-1);
+	}
+
+	info.fd = fd;
+	tracing_cb(grantpt_cb, &info);
+
+	if(info.res < 0){
+		printk("get_pty : Couldn't grant pty - errno = %d\n", 
+		       info.err);
+		return(-1);
+	}
+	if(unlockpt(fd) < 0){
+		printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
+		return(-1);
+	}
+	return(fd);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/Makefile b/arch/um/ptproxy/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,26 @@
+LIB = ptproxy.a
+
+OBJS = proxy.o ptrace.o sysdep.o wait.o
+
+all: $(LIB)
+
+$(LIB): $(OBJS)
+	rm -f $@
+	ar cr $@ $^
+
+proxy.o: proxy.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+ptrace.o: ptrace.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+sysdep.o: sysdep.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+wait.o: wait.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+clean:
+	rm -f *.o core child ptproxy
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/um/ptproxy/proxy.c b/arch/um/ptproxy/proxy.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/proxy.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,371 @@
+/**********************************************************************
+proxy.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+Jeff Dike (jdike@karaya.com) : Modified for integration into uml
+**********************************************************************/
+
+/* XXX This file shouldn't refer to CONFIG_* */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/ioctl.h>
+#include <asm/unistd.h>
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+
+#include "user_util.h"
+#include "user.h"
+#include "os.h"
+
+static int debugger_wait(debugger_state *debugger, int *status, int options,
+			 int (*syscall)(debugger_state *debugger, pid_t child),
+			 int (*normal_return)(debugger_state *debugger, 
+					      pid_t unused),
+			 int (*wait_return)(debugger_state *debugger, 
+					    pid_t unused))
+{
+	if(debugger->real_wait){
+		debugger->handle_trace = normal_return;
+		syscall_continue(debugger->pid);
+		debugger->real_wait = 0;
+		return(1);
+	}
+	debugger->wait_status_ptr = status;
+	debugger->wait_options = options;
+	if((debugger->debugee != NULL) && debugger->debugee->event){
+		syscall_continue(debugger->pid);
+		wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
+			      NULL);
+		(*wait_return)(debugger, -1);
+		return(0);
+	}
+	else if(debugger->wait_options & WNOHANG){
+		syscall_cancel(debugger->pid, 0);
+		debugger->handle_trace = syscall;
+		return(0);
+	}
+	else {
+		syscall_pause(debugger->pid);
+		debugger->handle_trace = wait_return;
+		debugger->waiting = 1;
+	}
+	return(1);
+}
+
+/*
+ * Handle debugger trap, i.e. syscall.
+ */
+
+int debugger_syscall(debugger_state *debugger, pid_t child)
+{
+	long arg1, arg2, arg3, arg4, arg5, result;
+	int syscall, ret = 0;
+
+	syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, 
+			      &arg5);
+
+	switch(syscall){
+	case __NR_execve:
+		/* execve never returns */
+		debugger->handle_trace = debugger_syscall; 
+		break;
+
+	case __NR_ptrace:
+		if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
+		if(!debugger->debugee->in_context) 
+			child = debugger->debugee->pid;
+		result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
+				      &ret);
+		syscall_cancel(debugger->pid, result);
+		debugger->handle_trace = debugger_syscall;
+		return(ret);
+
+	case __NR_waitpid:
+	case __NR_wait4:
+		if(!debugger_wait(debugger, (int *) arg2, arg3, 
+				  debugger_syscall, debugger_normal_return, 
+				  proxy_wait_return))
+			return(0);
+		break;
+
+	case __NR_kill:
+		if(!debugger->debugee->in_context) 
+			child = debugger->debugee->pid;
+		if(arg1 == debugger->debugee->pid){
+			result = kill(child, arg2);
+			syscall_cancel(debugger->pid, result);
+			debugger->handle_trace = debugger_syscall;
+			return(0);
+		}
+		else debugger->handle_trace = debugger_normal_return;
+		break;
+
+	default:
+		debugger->handle_trace = debugger_normal_return;
+	}
+
+	syscall_continue(debugger->pid);
+	return(0);
+}
+
+static debugger_state parent;
+static int parent_syscall(debugger_state *debugger, int pid);
+
+int init_parent_proxy(int pid)
+{
+	parent = ((debugger_state) { pid :		pid,
+				     wait_options :	0,
+				     wait_status_ptr :	NULL,
+				     waiting :		0,
+				     real_wait :	0,
+				     expecting_child :	0,
+				     handle_trace : 	parent_syscall,
+				     debugee :		NULL } );
+	return(0);
+}
+
+int parent_normal_return(debugger_state *debugger, pid_t unused)
+{
+	debugger->handle_trace = parent_syscall;
+	syscall_continue(debugger->pid);
+	return(0);
+}
+
+static int parent_syscall(debugger_state *debugger, int pid)
+{
+	long arg1, arg2, arg3, arg4, arg5;
+	int syscall;
+
+	syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
+		
+	if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){
+		debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
+			      parent_normal_return, parent_wait_return);
+	}
+	else ptrace(PTRACE_SYSCALL, pid, 0, 0);
+	return(0);
+}
+
+int debugger_normal_return(debugger_state *debugger, pid_t unused)
+{
+	debugger->handle_trace = debugger_syscall;
+	syscall_continue(debugger->pid);
+	return(0);
+}
+
+void debugger_cancelled_return(debugger_state *debugger, int result)
+{
+	debugger->handle_trace = debugger_syscall;
+	syscall_set_result(debugger->pid, result);
+	syscall_continue(debugger->pid);
+}
+
+#ifdef CONFIG_SMP
+#error need to make these arrays
+#endif
+
+static debugger_state debugger;
+static debugee_state debugee;
+
+void init_proxy (pid_t debugger_pid, int stopped, int status)
+{
+	debugger.pid = debugger_pid;
+	debugger.handle_trace = debugger_syscall;
+	debugger.debugee = &debugee;
+	debugger.waiting = 0;
+	debugger.real_wait = 0;
+	debugger.expecting_child = 0;
+
+	debugee.pid = 0;
+	debugee.traced = 0;
+	debugee.stopped = stopped;
+	debugee.event = 0;
+	debugee.zombie = 0;
+	debugee.died = 0;
+	debugee.wait_status = status;
+	debugee.in_context = 1;
+}
+
+int debugger_proxy(int status, int pid)
+{
+	int ret = 0, sig;
+
+	if(WIFSTOPPED(status)){
+		sig = WSTOPSIG(status);
+		if (sig == SIGTRAP)
+			ret = (*debugger.handle_trace)(&debugger, pid);
+						       
+		else if(sig == SIGCHLD){
+			if(debugger.expecting_child){
+				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+				debugger.expecting_child = 0;
+			}
+			else if(debugger.waiting)
+				real_wait_return(&debugger);
+			else {
+				ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+				debugger.real_wait = 1;
+			}
+		}
+		else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
+	}
+	else if(WIFEXITED(status)){
+		tracer_panic("debugger (pid %d) exited with status %d", 
+			     debugger.pid, WEXITSTATUS(status));
+	}
+	else if(WIFSIGNALED(status)){
+		tracer_panic("debugger (pid %d) exited with signal %d", 
+			     debugger.pid, WTERMSIG(status));
+	}
+	else {
+		tracer_panic("proxy got unknown status (0x%x) on debugger "
+			     "(pid %d)", status, debugger.pid);
+	}
+	return(ret);
+}
+
+void child_proxy(pid_t pid, int status)
+{
+	debugee.event = 1;
+	debugee.wait_status = status;
+
+	if(WIFSTOPPED(status)){
+		debugee.stopped = 1;
+		debugger.expecting_child = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else if(WIFEXITED(status) || WIFSIGNALED(status)){
+		debugee.zombie = 1;
+		debugger.expecting_child = 1;
+		kill(debugger.pid, SIGCHLD);
+	}
+	else panic("proxy got unknown status (0x%x) on child (pid %d)", 
+		   status, pid);
+}
+
+void debugger_parent_signal(int status, int pid)
+{
+	int sig;
+
+	if(WIFSTOPPED(status)){
+		sig = WSTOPSIG(status);
+		if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
+		else ptrace(PTRACE_SYSCALL, pid, 0, sig);
+	}
+}
+
+void fake_child_exit(void)
+{
+	int status, pid;
+
+	child_proxy(1, W_EXITCODE(0, 0));
+	while(debugger.waiting == 1){
+		pid = waitpid(debugger.pid, &status, WUNTRACED);
+		if(pid != debugger.pid){
+			printk("fake_child_exit - waitpid failed, "
+			       "errno = %d\n", errno);
+			return;
+		}
+		debugger_proxy(status, debugger.pid);
+	}
+	pid = waitpid(debugger.pid, &status, WUNTRACED);
+	if(pid != debugger.pid){
+		printk("fake_child_exit - waitpid failed, "
+		       "errno = %d\n", errno);
+		return;
+	}
+	if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
+		printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
+		       errno);
+}
+
+char gdb_init_string[] = 
+"att 1
+b panic
+b stop
+handle SIGWINCH nostop noprint pass
+";
+
+int start_debugger(char *prog, int startup, int stop, int *fd_out)
+{
+	int slave, child;
+
+	slave = open_gdb_chan();
+	if((child = fork()) == 0){
+		char *tempname = NULL;
+		int fd;
+
+	        if(setsid() < 0) perror("setsid");
+		if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || 
+		   (dup2(slave, 2) < 0)){
+			printk("start_debugger : dup2 failed, errno = %d\n",
+			       errno);
+			exit(1);
+		}
+		if(ioctl(0, TIOCSCTTY, 0) < 0){
+			printk("start_debugger : TIOCSCTTY failed, "
+			       "errno = %d\n", errno);
+			exit(1);
+		}
+		if(tcsetpgrp (1, os_getpid()) < 0){
+			printk("start_debugger : tcsetpgrp failed, "
+			       "errno = %d\n", errno);
+#ifdef notdef
+			exit(1);
+#endif
+		}
+		if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
+			printk("start_debugger : make_tempfile failed, errno = %d\n",
+			       errno);
+			exit(1);
+		}
+		write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+		if(startup){
+			if(stop){
+				write(fd, "b start_kernel\n",
+				      strlen("b start_kernel\n"));
+			}
+			write(fd, "c\n", strlen("c\n"));
+		}
+		if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+			printk("start_debugger :  PTRACE_TRACEME failed, "
+			       "errno = %d\n", errno);
+			exit(1);
+		}
+		execlp("gdb", "gdb", "--command", tempname, prog, NULL);
+		printk("start_debugger : exec of gdb failed, errno = %d\n",
+		       errno);
+	}
+	if(child < 0){
+		printk("start_debugger : fork for gdb failed, errno = %d\n",
+		       errno);
+		return(-1);
+	}
+	*fd_out = slave;
+	return(child);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/ptproxy.h b/arch/um/ptproxy/ptproxy.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/ptproxy.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,61 @@
+/**********************************************************************
+ptproxy.h
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#ifndef __PTPROXY_H
+#define __PTPROXY_H
+
+#include <sys/types.h>
+
+typedef struct debugger debugger_state;
+typedef struct debugee debugee_state;
+
+struct debugger
+{
+	pid_t pid;
+	int wait_options;
+	int *wait_status_ptr;
+	unsigned int waiting : 1;
+	unsigned int real_wait : 1;
+	unsigned int expecting_child : 1;
+	int (*handle_trace) (debugger_state *, pid_t);
+
+	debugee_state *debugee;
+};
+
+struct debugee
+{
+	pid_t pid;
+	int wait_status;
+	unsigned int died : 1;
+	unsigned int event : 1;
+	unsigned int stopped : 1;
+	unsigned int trace_singlestep : 1;
+	unsigned int trace_syscall : 1;
+	unsigned int traced : 1;
+	unsigned int zombie : 1;
+	unsigned int in_context : 1;
+};
+
+extern int debugger_syscall(debugger_state *debugger, pid_t pid);
+extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
+
+extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
+			  int *strace_out);
+extern void debugger_cancelled_return(debugger_state *debugger, int result);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/ptrace.c b/arch/um/ptproxy/ptrace.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/ptrace.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,238 @@
+/**********************************************************************
+ptrace.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+Jeff Dike (jdike@karaya.com) : Modified for integration into uml
+**********************************************************************/
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <asm/ptrace.h>
+
+#include "ptproxy.h"
+#include "debug.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "ptrace_user.h"
+
+long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
+		  long arg3, long arg4, pid_t child, int *ret)
+{
+	sigset_t relay;
+	long result;
+	int status;
+
+	*ret = 0;
+	if(debugger->debugee->died) return(-ESRCH);
+
+	switch(arg1){
+	case PTRACE_ATTACH:
+		if(debugger->debugee->traced) return(-EPERM);
+
+		debugger->debugee->pid = arg2;
+		debugger->debugee->traced = 1;
+
+		if(is_valid_pid(arg2) && (arg2 != child)){
+			debugger->debugee->in_context = 0;
+			kill(arg2, SIGSTOP);
+			debugger->debugee->event = 1;
+			debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
+		}
+		else {
+			debugger->debugee->in_context = 1;
+			if(debugger->debugee->stopped) 
+				child_proxy(child, W_STOPCODE(SIGSTOP));
+			else kill(child, SIGSTOP);
+		}
+
+		return(0);
+
+	case PTRACE_DETACH:
+		if(!debugger->debugee->traced) return(-EPERM);
+		
+		debugger->debugee->traced = 0;
+		debugger->debugee->pid = 0;
+		if(!debugger->debugee->in_context)
+			kill(child, SIGCONT);
+
+		return(0);
+
+	case PTRACE_CONT:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		*ret = PTRACE_CONT;
+		return(ptrace(PTRACE_CONT, child, arg3, arg4));
+
+#ifdef UM_HAVE_GETFPREGS
+	case PTRACE_GETFPREGS:
+	{
+		long regs[FP_FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+		
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
+			       regs[i]);
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_GETFPXREGS
+	case PTRACE_GETFPXREGS:
+	{
+		long regs[FPX_FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+		
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
+			       regs[i]);
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_GETREGS
+	case PTRACE_GETREGS:
+	{
+		long regs[FRAME_SIZE];
+		int i, result;
+
+		result = ptrace(PTRACE_GETREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			ptrace (PTRACE_POKEDATA, debugger->pid,
+				arg4 + 4 * i, regs[i]);
+		return(result);
+	}
+	break;
+#endif
+
+	case PTRACE_KILL:
+		result = ptrace(PTRACE_KILL, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		return(result);
+
+	case PTRACE_PEEKDATA:
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKUSER:
+		/* The value being read out could be -1, so we have to 
+		 * check errno to see if there's an error, and zero it
+		 * beforehand so we're not faked out by an old error
+		 */
+
+		errno = 0;
+		result = ptrace(arg1, child, arg3, 0);
+		if((result == -1) && (errno != 0)) return(-errno);
+
+		result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
+		if(result == -1) return(-errno);
+			
+		return(result);
+
+	case PTRACE_POKEDATA:
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEUSER:
+		result = ptrace(arg1, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4);
+		return(result);
+
+#ifdef UM_HAVE_SETFPREGS
+	case PTRACE_SETFPREGS:
+	{
+		long regs[FP_FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
+					  arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_SETFPXREGS
+	case PTRACE_SETFPXREGS:
+	{
+		long regs[FPX_FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
+					  arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+#ifdef UM_HAVE_SETREGS
+	case PTRACE_SETREGS:
+	{
+		long regs[FRAME_SIZE];
+		int i;
+
+		for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
+			regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
+					 arg4 + 4 * i, 0);
+		result = ptrace(PTRACE_SETREGS, child, 0, regs);
+		if(result == -1) return(-errno);
+
+		return(result);
+	}
+#endif
+
+	case PTRACE_SINGLESTEP:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		sigemptyset(&relay);
+		sigaddset(&relay, SIGSEGV);
+		sigaddset(&relay, SIGILL);
+		sigaddset(&relay, SIGBUS);
+		result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
+		if(result == -1) return(-errno);
+		
+		status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
+				       &relay);
+		child_proxy(child, status);
+		return(result);
+
+	case PTRACE_SYSCALL:
+		if(!debugger->debugee->in_context) return(-EPERM);
+		result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
+		if(result == -1) return(-errno);
+
+		*ret = PTRACE_SYSCALL;
+		return(result);
+
+	case PTRACE_TRACEME:
+	default:
+		return(-EINVAL);
+	}
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/sysdep.c b/arch/um/ptproxy/sysdep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/sysdep.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,71 @@
+/**********************************************************************
+sysdep.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <linux/unistd.h>
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "user.h"
+
+int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, 
+		long *arg5)
+{
+	*arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0);
+	*arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0);
+	*arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0);
+	*arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0);
+	*arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0);
+	return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0));
+}
+
+void syscall_cancel(pid_t pid, int result)
+{
+	if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 
+		   __NR_getpid) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
+	   (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
+	   (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
+		printk("ptproxy: couldn't cancel syscall: errno = %d\n", 
+		       errno);
+}
+
+void syscall_set_result(pid_t pid, long result)
+{
+	ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result);
+}
+
+void syscall_continue(pid_t pid)
+{
+	ptrace(PTRACE_SYSCALL, pid, 0, 0);
+}
+
+int syscall_pause(pid_t pid) 
+{
+	if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
+		printk("syscall_change - ptrace failed, errno = %d\n", errno);
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/sysdep.h b/arch/um/ptproxy/sysdep.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/sysdep.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,25 @@
+/**********************************************************************
+sysdep.h
+
+Copyright (C) 1999 Lars Brinkhoff.
+Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+See the file COPYING for licensing terms and conditions.
+**********************************************************************/
+
+extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, 
+		       long *arg4, long *arg5);
+extern void syscall_cancel (pid_t pid, long result);
+extern void syscall_set_result (pid_t pid, long result);
+extern void syscall_continue (pid_t pid);
+extern int syscall_pause(pid_t pid);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/wait.c b/arch/um/ptproxy/wait.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/wait.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,86 @@
+/**********************************************************************
+wait.c
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+
+**********************************************************************/
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#include "ptproxy.h"
+#include "sysdep.h"
+#include "wait.h"
+#include "user_util.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/ptrace_user.h"
+#include "sysdep/sigcontext.h"
+
+int proxy_wait_return(struct debugger *debugger, pid_t unused)
+{
+	debugger->waiting = 0;
+
+	if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
+		debugger_cancelled_return(debugger, -ECHILD);
+		return(0);
+	}
+
+	if(debugger->debugee->zombie && debugger->debugee->event)
+		debugger->debugee->died = 1;
+
+	if(debugger->debugee->event){
+		debugger->debugee->event = 0;
+		ptrace(PTRACE_POKEDATA, debugger->pid,
+		       debugger->wait_status_ptr, 
+		       debugger->debugee->wait_status);
+		/* if (wait4)
+		   ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
+		debugger_cancelled_return(debugger, debugger->debugee->pid);
+		return(0);
+	}
+
+	/* pause will return -EINTR, which happens to be right for wait */
+	debugger_normal_return(debugger, -1);
+	return(0);
+}
+
+int parent_wait_return(struct debugger *debugger, pid_t unused)
+{
+	return(debugger_normal_return(debugger, -1));
+}
+
+int real_wait_return(struct debugger *debugger)
+{
+	unsigned long ip;
+	int err, pid;
+
+	pid = debugger->pid;
+	ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+	ip = IP_RESTART_SYSCALL(ip);
+	err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip);
+	if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
+		tracer_panic("real_wait_return : Failed to restart system "
+			     "call, errno = %d\n");
+	if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+	   debugger_normal_return(debugger, -1))
+		tracer_panic("real_wait_return : gdb failed to wait, "
+			     "errno = %d\n");
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/ptproxy/wait.h b/arch/um/ptproxy/wait.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/ptproxy/wait.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,15 @@
+/**********************************************************************
+wait.h
+
+Copyright (C) 1999 Lars Brinkhoff.  See the file COPYING for licensing
+terms and conditions.
+**********************************************************************/
+
+#ifndef __PTPROXY_WAIT_H
+#define __PTPROXY_WAIT_H
+
+extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
+extern int real_wait_return(struct debugger *debugger);
+extern int parent_wait_return(struct debugger *debugger, pid_t unused);
+
+#endif
diff -Nru a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/Makefile	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,44 @@
+O_TARGET = sys.o
+
+obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o old-checksum.o \
+	ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
+
+export-objs = ksyms.o
+
+USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o
+
+SYMLINKS = semaphore.c old-checksum.c checksum.S extable.c
+
+include $(TOPDIR)/Rules.make
+
+$(USER_OBJS) : %.o: %.c
+	$(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $<
+
+checksum.S old-checksum.c: 
+	-rm -f $@
+	-ln -s $(TOPDIR)/arch/i386/lib/$@ $@
+
+semaphore.c:
+	-rm -f $@
+	-ln -s $(TOPDIR)/arch/i386/kernel/$@ $@
+
+extable.c:
+	-rm -f $@
+	-ln -s $(TOPDIR)/arch/i386/mm/$@ $@
+
+clean:
+	$(MAKE) -C util clean
+
+fastdep:
+
+dep:
+
+archmrproper:
+	rm -f $(SYMLINKS)
+
+archclean:
+
+archdep:
+
+modules:
+
diff -Nru a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/bugs.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,156 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/signal.h>
+#include "kern_util.h"
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "task.h"
+
+#define MAXTOKEN 64
+
+int cpu_has_cmov = 1;
+int cpu_has_xmm = 0;
+
+static char token(int fd, char *buf, int len, char stop)
+{
+	int n;
+	char *ptr, *end, c;
+
+	ptr = buf;
+	end = &buf[len];
+	do {
+		n = read(fd, ptr, sizeof(*ptr));
+		c = *ptr++;
+		if(n == 0) return(0);
+		else if(n != sizeof(*ptr)){
+			printk("Reading /proc/cpuinfo failed, "
+			       "errno = %d\n", errno);
+			return(-errno);
+		}
+	} while((c != '\n') && (c != stop) && (ptr < end));
+
+	if(ptr == end){
+		printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
+		return(-1);
+	}
+	*(ptr - 1) = '\0';
+	return(c);
+}
+
+static int check_cpu_feature(char *feature, int *have_it)
+{
+	char buf[MAXTOKEN], c;
+	int fd, len = sizeof(buf)/sizeof(buf[0]), n;
+
+	printk("Checking for host processor %s support...", feature);
+	fd = open("/proc/cpuinfo", O_RDONLY);
+	if(fd < 0){
+		printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno);
+		return(0);
+	}
+
+	*have_it = 0;
+	buf[len - 1] = '\0';
+	while(1){
+		c = token(fd, buf, len - 1, ':');
+		if(c <= 0) goto out;
+		else if(c != ':'){
+			printk("Failed to find ':' in /proc/cpuinfo\n");
+			goto out;
+		}
+
+		if(!strncmp(buf, "flags", strlen("flags"))) break;
+
+		do {
+			n = read(fd, &c, sizeof(c));
+			if(n != sizeof(c)){
+				printk("Failed to find newline in "
+				       "/proc/cpuinfo, n = %d, errno = %d\n",
+				       n, errno);
+				goto out;
+			}
+		} while(c != '\n');
+	}
+
+	c = token(fd, buf, len - 1, ' ');
+	if(c < 0) goto out;
+	else if(c != ' '){
+		printk("Failed to find ':' in /proc/cpuinfo\n");
+		goto out;
+	}
+
+	while(1){
+		c = token(fd, buf, len - 1, ' ');
+		if(c < 0) goto out;
+		else if(c == '\n') break;
+
+		if(!strcmp(buf, feature)){
+			*have_it = 1;
+			goto out;
+		}
+	}
+ out:
+	if(*have_it == 0) printk("No\n");
+	else if(*have_it == 1) printk("Yes\n");
+	close(fd);
+	return(1);
+}
+
+void arch_check_bugs(void)
+{
+	int have_it;
+
+	if(access("/proc/cpuinfo", R_OK)){
+		printk("/proc/cpuinfo not available - skipping CPU capability "
+		       "checks\n");
+		return;
+	}
+	if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
+	if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
+}
+
+int arch_handle_signal(int sig, struct uml_pt_regs *regs)
+{
+	unsigned long ip;
+
+	/* This is testing for a cmov (0x0f 0x4x) instruction causing a
+	 * SIGILL in init.
+	 */
+	if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
+
+	ip = UPT_IP(regs);
+	if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
+		return(0);
+
+	if(cpu_has_cmov == 0)
+		panic("SIGILL caused by cmov, which this processor doesn't "
+		      "implement, boot a filesystem compiled for older "
+		      "processors");
+	else if(cpu_has_cmov == 1)
+		panic("SIGILL caused by cmov, which this processor claims to "
+		      "implement");
+	else if(cpu_has_cmov == -1)
+		panic("SIGILL caused by cmov, couldn't tell if this processor "
+		      "implements it, boot a filesystem compiled for older "
+		      "processors");
+	else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov);
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/fault.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+
+extern unsigned long search_exception_table(unsigned long addr);
+
+int arch_fixup(unsigned long address, void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+	unsigned long fixup;
+
+	fixup = search_exception_table(address);
+	if(fixup != 0){
+		sc->eip = fixup;
+		return(1);
+	}
+	return(0);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/ksyms.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,16 @@
+#include "linux/module.h"
+#include "linux/in6.h"
+#include "linux/rwsem.h"
+#include "asm/byteorder.h"
+#include "asm/semaphore.h"
+#include "asm/uaccess.h"
+#include "asm/checksum.h"
+#include "asm/errno.h"
+
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__down_failed_trylock);
+EXPORT_SYMBOL(__up_wakeup);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_generic);
diff -Nru a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/ldt.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/uaccess.h"
+
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
+
+int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+	if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
+	return(modify_ldt(func, ptr, bytecount));
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/ptrace.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,326 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/elf.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "ptrace_user.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/sc.h"
+
+void arch_switch(void)
+{
+	update_debugregs(current->thread.arch.debugregs_seq);
+}
+
+int is_syscall(unsigned long addr)
+{
+	unsigned short instr;
+	int n;
+
+	n = copy_from_user(&instr, (void *) addr, sizeof(instr));
+	if(n){
+		printk("is_syscall : failed to read instruction from 0x%lu\n", 
+		       addr);
+		return(0);
+	}
+	return(instr == 0x80cd);
+}
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x00044dd5
+
+int putreg(struct task_struct *child, int regno, unsigned long value)
+{
+	regno >>= 2;
+	switch (regno) {
+	case FS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		PT_REGS_FS(&child->thread.regs) = value;
+		return 0;
+	case GS:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		PT_REGS_GS(&child->thread.regs) = value;
+		return 0;
+	case DS:
+	case ES:
+		if (value && (value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case SS:
+	case CS:
+		if ((value & 3) != 3)
+			return -EIO;
+		value &= 0xffff;
+		break;
+	case EFL:
+		value &= FLAG_MASK;
+		value |= PT_REGS_EFLAGS(&child->thread.regs);
+		break;
+	}
+	PT_REGS_SET(&child->thread.regs, regno, value);
+	return 0;
+}
+
+unsigned long getreg(struct task_struct *child, int regno)
+{
+	unsigned long retval = ~0UL;
+
+	regno >>= 2;
+	switch (regno) {
+	case FS:
+	case GS:
+	case DS:
+	case ES:
+	case SS:
+	case CS:
+		retval = 0xffff;
+		/* fall through */
+	default:
+		retval &= PT_REG(&child->thread.regs, regno);
+	}
+	return retval;
+}
+
+struct i387_fxsave_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	mxcsr;
+	long	reserved;
+	long	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	long	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+	long	padding[56];
+};
+
+/*
+ * FPU tag word conversions.
+ */
+
+static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
+{
+	unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+ 
+	/* Transform each pair of bits into 01 (valid) or 00 (empty) */
+        tmp = ~twd;
+        tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+        /* and move the valid bits to the lower byte. */
+        tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+        tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+        tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+        return tmp;
+}
+
+static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave )
+{
+	struct _fpxreg *st = NULL;
+	unsigned long twd = (unsigned long) fxsave->twd;
+	unsigned long tag;
+	unsigned long ret = 0xffff0000;
+	int i;
+
+#define FPREG_ADDR(f, n)	((char *)&(f)->st_space + (n) * 16);
+
+	for ( i = 0 ; i < 8 ; i++ ) {
+		if ( twd & 0x1 ) {
+			st = (struct _fpxreg *) FPREG_ADDR( fxsave, i );
+
+			switch ( st->exponent & 0x7fff ) {
+			case 0x7fff:
+				tag = 2;		/* Special */
+				break;
+			case 0x0000:
+				if ( !st->significand[0] &&
+				     !st->significand[1] &&
+				     !st->significand[2] &&
+				     !st->significand[3] ) {
+					tag = 1;	/* Zero */
+				} else {
+					tag = 2;	/* Special */
+				}
+				break;
+			default:
+				if ( st->significand[3] & 0x8000 ) {
+					tag = 0;	/* Valid */
+				} else {
+					tag = 2;	/* Special */
+				}
+				break;
+			}
+		} else {
+			tag = 3;			/* Empty */
+		}
+		ret |= (tag << (2 * i));
+		twd = twd >> 1;
+	}
+	return ret;
+}
+
+/*
+b * FXSR floating point environment conversions.
+ */
+
+static inline int convert_fxsr_to_user(struct _fpstate *buf, 
+				       struct pt_regs *regs)
+{
+	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+	unsigned long env[7];
+	struct _fpreg *to;
+	struct _fpxreg *from;
+	int i;
+
+	env[0] = (unsigned long)fxsave->cwd | 0xffff0000;
+	env[1] = (unsigned long)fxsave->swd | 0xffff0000;
+	env[2] = twd_fxsr_to_i387(fxsave);
+	env[3] = fxsave->fip;
+	env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+	env[5] = fxsave->foo;
+	env[6] = fxsave->fos;
+
+	if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) )
+		return 1;
+
+	to = &buf->_st[0];
+	from = (struct _fpxreg *) &fxsave->st_space[0];
+	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+		if ( __copy_to_user( to, from, sizeof(*to) ) )
+			return 1;
+	}
+	return 0;
+}
+
+static inline int convert_fxsr_from_user(struct pt_regs *regs,
+					 struct _fpstate *buf)
+{
+	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+	unsigned long env[7];
+	struct _fpxreg *to;
+	struct _fpreg *from;
+	int i;
+
+	if ( __copy_from_user( env, buf, 7 * sizeof(long) ) )
+		return 1;
+
+	fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+	fxsave->swd = (unsigned short)(env[1] & 0xffff);
+	fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+	fxsave->fip = env[3];
+	fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16);
+	fxsave->fcs = (env[4] & 0xffff);
+	fxsave->foo = env[5];
+	fxsave->fos = env[6];
+
+	to = (struct _fpxreg *) &fxsave->st_space[0];
+	from = &buf->_st[0];
+	for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+		if ( __copy_from_user( to, from, sizeof(*from) ) )
+			return 1;
+	}
+	return 0;
+}
+
+int get_fpregs(unsigned long buf, struct task_struct *child)
+{
+	int err;
+
+	err = convert_fxsr_to_user((struct _fpstate *) buf, 
+				   &child->thread.regs);
+	if(err) return(-EFAULT);
+	else return(0);
+}
+
+int set_fpregs(unsigned long buf, struct task_struct *child)
+{
+	int err;
+
+	err = convert_fxsr_from_user(&child->thread.regs, 
+				     (struct _fpstate *) buf);
+	if(err) return(-EFAULT);
+	else return(0);
+}
+
+int get_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+	struct pt_regs *regs = &tsk->thread.regs;
+	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+	int err;
+
+	err = __copy_to_user((void *) buf, fxsave,
+			     sizeof(struct user_fxsr_struct));
+	if(err) return -EFAULT;
+	else return 0;
+}
+
+int set_fpxregs(unsigned long buf, struct task_struct *tsk)
+{
+	struct pt_regs *regs = &tsk->thread.regs;
+	struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs));
+	int err;
+
+	err = __copy_from_user(fxsave, (void *) buf,
+			       sizeof(struct user_fxsr_struct) );
+	if(err) return -EFAULT;
+	else return 0;
+}
+
+#ifdef notdef
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+	fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) |
+		    (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff));
+	fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
+	fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs));
+	fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff;
+	fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs));
+	fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs));
+	fpu->fos = 0;
+	memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)),
+	       sizeof(fpu->st_space));
+	return(1);
+}
+#endif
+static inline void copy_fpu_fxsave(struct pt_regs *regs,
+				   struct user_i387_struct *buf)
+{
+	struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs));
+	unsigned short *to;
+	unsigned short *from;
+	int i;
+
+	memcpy( buf, fpu, 7 * sizeof(long) );
+
+	to = (unsigned short *) &buf->st_space[0];
+	from = (unsigned short *) &fpu->st_space[0];
+	for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) {
+		memcpy( to, from, 5 * sizeof(unsigned short) );
+	}
+}
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
+{
+	copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu);
+	return(1);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/ptrace_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,116 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/stddef.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include "kern_util.h"
+#include "sysdep/thread.h"
+#include "user.h"
+#include "os.h"
+
+int ptrace_getregs(long pid, unsigned long *regs_out)
+{
+	return(ptrace(PTRACE_GETREGS, pid, 0, regs_out));
+}
+
+int ptrace_setregs(long pid, unsigned long *regs)
+{
+	return(ptrace(PTRACE_SETREGS, pid, 0, regs));
+}
+
+int ptrace_getfpregs(long pid, unsigned long *regs)
+{
+	return(ptrace(PTRACE_GETFPREGS, pid, 0, regs));
+}
+
+static void write_debugregs(int pid, unsigned long *regs)
+{
+	struct user *dummy;
+	int nregs, i;
+
+	dummy = NULL;
+	nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+	for(i = 0; i < nregs; i++){
+		if((i == 4) || (i == 5)) continue;
+		if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
+			  regs[i]) < 0)
+			printk("write_debugregs - ptrace failed, "
+			       "errno = %d\n", errno);
+	}
+}
+
+static void read_debugregs(int pid, unsigned long *regs)
+{
+	struct user *dummy;
+	int nregs, i;
+
+	dummy = NULL;
+	nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+	for(i = 0; i < nregs; i++){
+		regs[i] = ptrace(PTRACE_PEEKUSR, pid, 
+				 &dummy->u_debugreg[i], 0);
+	}
+}
+
+static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
+static int debugregs_seq = 0;
+
+void arch_enter_kernel(void *task, int pid)
+{
+	read_debugregs(pid, TASK_DEBUGREGS(task));
+	write_debugregs(pid, kernel_debugregs);
+}
+
+void arch_leave_kernel(void *task, int pid)
+{
+	read_debugregs(pid, kernel_debugregs);
+	write_debugregs(pid, TASK_DEBUGREGS(task));
+}
+
+void ptrace_pokeuser(unsigned long addr, unsigned long data)
+{
+	if((addr < offsetof(struct user, u_debugreg[0])) ||
+	   (addr > offsetof(struct user, u_debugreg[7])))
+		return;
+	addr -= offsetof(struct user, u_debugreg[0]);
+	addr = addr >> 2;
+	if(kernel_debugregs[addr] == data) return;
+
+	kernel_debugregs[addr] = data;
+	debugregs_seq++;
+}
+
+static void update_debugregs_cb(void *arg)
+{
+	int pid = *((int *) arg);
+
+	write_debugregs(pid, kernel_debugregs);
+}
+
+void update_debugregs(int seq)
+{
+	int me;
+
+	if(seq == debugregs_seq) return;
+
+	me = os_getpid();
+	tracing_cb(update_debugregs_cb, &me);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/sigcontext.c b/arch/um/sys-i386/sigcontext.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/sigcontext.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,119 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <asm/ptrace.h>
+#include <asm/sigcontext.h>
+#include "sysdep/ptrace.h"
+#include "kern_util.h"
+#include "frame_user.h"
+
+int sc_size(void *data)
+{
+	struct arch_frame_data *arch = data;
+
+	return(sizeof(struct sigcontext) + arch->fpstate_size);
+}
+
+int copy_sc_to_user(void *to_ptr, void *from_ptr, void *data)
+{
+	struct arch_frame_data *arch = data;
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	struct _fpstate *to_fp, *from_fp;
+	int err;
+
+	to_fp = (struct _fpstate *)((unsigned long) to + sizeof(*to));
+	from_fp = from->fpstate;
+	err = copy_to_user_proc(to, from, sizeof(*to));
+	if(from_fp != NULL){
+		err |= copy_to_user_proc(&to->fpstate, &to_fp,
+					 sizeof(to->fpstate));
+		err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size);
+	}
+	return(err);
+}
+
+int copy_sc_from_user(void *to_ptr, void *from_ptr, void *data)
+{
+	struct arch_frame_data *arch = data;
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	struct _fpstate *to_fp, *from_fp;
+	unsigned long sigs;
+	int err;
+
+	to_fp = to->fpstate;
+	from_fp = from->fpstate;
+	sigs = to->oldmask;
+	err = copy_from_user_proc(to, from, sizeof(*to));
+	to->oldmask = sigs;
+	if(to_fp != NULL){
+		err |= copy_from_user_proc(&to->fpstate, &to_fp,
+					   sizeof(to->fpstate));
+		err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size);
+	}
+	return(err);
+}
+
+void sc_to_sc(void *to_ptr, void *from_ptr)
+{
+	struct sigcontext *to = to_ptr, *from = from_ptr;
+	int size = sizeof(*to) + signal_frame_sc.arch.fpstate_size;
+
+	memcpy(to, from, size);
+	if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1);
+}
+
+unsigned long *sc_sigmask(void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+
+	return(&sc->oldmask);
+}
+
+int sc_get_fpregs(unsigned long buf, void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+	struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf;
+	int err = 0;
+
+	if(from == NULL){
+		err |= clear_user_proc(&to->cw, sizeof(to->cw));
+		err |= clear_user_proc(&to->sw, sizeof(to->sw));
+		err |= clear_user_proc(&to->tag, sizeof(to->tag));
+		err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff));
+		err |= clear_user_proc(&to->cssel, sizeof(to->cssel));
+		err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff));
+		err |= clear_user_proc(&to->datasel, sizeof(to->datasel));
+		err |= clear_user_proc(&to->_st, sizeof(to->_st));
+	}
+	else {
+		err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw));
+		err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw));
+		err |= copy_to_user_proc(&to->tag, &from->tag, 
+					 sizeof(to->tag));
+		err |= copy_to_user_proc(&to->ipoff, &from->ipoff, 
+					 sizeof(to->ipoff));
+		err |= copy_to_user_proc(&to->cssel,& from->cssel, 
+					 sizeof(to->cssel));
+		err |= copy_to_user_proc(&to->dataoff, &from->dataoff, 
+				    sizeof(to->dataoff));
+		err |= copy_to_user_proc(&to->datasel, &from->datasel, 
+				    sizeof(to->datasel));
+		err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st));
+	}
+	return(err);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/syscalls.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,68 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+extern int old_mmap(unsigned long addr, unsigned long len,
+		    unsigned long prot, unsigned long flags,
+		    unsigned long fd, unsigned long offset);
+
+int old_mmap_i386(struct mmap_arg_struct *arg)
+{
+	struct mmap_arg_struct a;
+	int err = -EFAULT;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		goto out;
+
+	err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+ out:
+	return err;
+}
+
+struct sel_arg_struct {
+	unsigned long n;
+	fd_set *inp, *outp, *exp;
+	struct timeval *tvp;
+};
+
+int old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	/* sys_select() does the appropriate kernel locking */
+	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/sysrq.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,30 @@
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs *regs)
+{
+        printk("\n");
+        printk("EIP: %04lx:[<%08lx>] CPU: %d %s", 
+	       0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs),
+	       smp_processor_id(), print_tainted());
+        if (PT_REGS_CS(regs) & 3)
+                printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs),
+		       PT_REGS_SP(regs));
+        printk(" EFLAGS: %08lx\n    %s\n", PT_REGS_EFLAGS(regs),
+	       print_tainted());
+        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+                PT_REGS_EAX(regs), PT_REGS_EBX(regs), 
+	       PT_REGS_ECX(regs), 
+	       PT_REGS_EDX(regs));
+        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+	       PT_REGS_ESI(regs), PT_REGS_EDI(regs), 
+	       PT_REGS_EBP(regs));
+        printk(" DS: %04lx ES: %04lx\n",
+	       0xffff & PT_REGS_DS(regs), 
+	       0xffff & PT_REGS_ES(regs));
+
+        show_trace((unsigned long *) &regs);
+}
diff -Nru a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/util/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,16 @@
+host-progs = mk_sc
+
+mk_sc-objs = mk_sc.o
+
+include $(TOPDIR)/Rules.make
+
+mk_thread : mk_thread_kern.o mk_thread_user.o
+	$(CC) $(CFLAGS) -o $@ mk_thread_user.o mk_thread_kern.o
+
+mk_thread_user.o : mk_thread_user.c
+	$(CC) $(USER_CFLAGS) -c -o $@ $<
+
+clean :
+	$(RM) $(host-progs) mk_thread
+
+archmrproper : clean
diff -Nru a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/util/mk_sc.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <signal.h>
+#include <linux/stddef.h>
+
+#define SC_OFFSET(name, field) \
+  printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\
+	 offsetof(struct sigcontext, field))
+
+#define SC_FP_OFFSET(name, field) \
+  printf("#define " name \
+	 "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
+	 offsetof(struct _fpstate, field))
+
+#define SC_FP_OFFSET_PTR(name, field, type) \
+  printf("#define " name \
+	 "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\
+	 offsetof(struct _fpstate, field))
+
+int main(int argc, char **argv)
+{
+  SC_OFFSET("SC_IP", eip);
+  SC_OFFSET("SC_SP", esp);
+  SC_OFFSET("SC_FS", fs);
+  SC_OFFSET("SC_GS", gs);
+  SC_OFFSET("SC_DS", ds);
+  SC_OFFSET("SC_ES", es);
+  SC_OFFSET("SC_SS", ss);
+  SC_OFFSET("SC_CS", cs);
+  SC_OFFSET("SC_EFLAGS", eflags);
+  SC_OFFSET("SC_EAX", eax);
+  SC_OFFSET("SC_EBX", ebx);
+  SC_OFFSET("SC_ECX", ecx);
+  SC_OFFSET("SC_EDX", edx);
+  SC_OFFSET("SC_EDI", edi);
+  SC_OFFSET("SC_ESI", esi);
+  SC_OFFSET("SC_EBP", ebp);
+  SC_OFFSET("SC_TRAPNO", trapno);
+  SC_OFFSET("SC_ERR", err);
+  SC_OFFSET("SC_CR2", cr2);
+  SC_OFFSET("SC_FPSTATE", fpstate);
+  SC_FP_OFFSET("SC_FP_CW", cw);
+  SC_FP_OFFSET("SC_FP_SW", sw);
+  SC_FP_OFFSET("SC_FP_TAG", tag);
+  SC_FP_OFFSET("SC_FP_IPOFF", ipoff);
+  SC_FP_OFFSET("SC_FP_CSSEL", cssel);
+  SC_FP_OFFSET("SC_FP_DATAOFF", dataoff);
+  SC_FP_OFFSET("SC_FP_DATASEL", datasel);
+  SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate");
+  SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void");
+  return(0);
+}
diff -Nru a/arch/um/sys-i386/util/mk_thread_kern.c b/arch/um/sys-i386/util/mk_thread_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/util/mk_thread_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,7 @@
+#include "linux/stddef.h"
+#include "linux/sched.h"
+
+int debugreg(void)
+{
+  return(offsetof(struct task_struct, thread.arch.debugregs));
+}
diff -Nru a/arch/um/sys-i386/util/mk_thread_user.c b/arch/um/sys-i386/util/mk_thread_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-i386/util/mk_thread_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <linux/stddef.h>
+#include <asm/user.h>
+
+extern int debugreg(void);
+
+int main(int argc, char **argv)
+{
+  printf("#define TASK_DEBUGREGS(task) ((unsigned long *) "
+	 "&(((char *) (task))[%d]))\n", debugreg());
+  return(0);
+}
diff -Nru a/arch/um/sys-ia64/Makefile b/arch/um/sys-ia64/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ia64/Makefile	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,26 @@
+OBJ = sys.o
+
+OBJS =
+
+all: $(OBJ)
+
+$(OBJ): $(OBJS)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+clean:
+	rm -f $(OBJS)
+
+fastdep:
+
+archmrproper:
+
+archclean:
+	rm -f link.ld
+	@$(MAKEBOOT) clean
+
+archdep:
+	@$(MAKEBOOT) dep
+
+modules:
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,80 @@
+OBJ = sys.o
+
+.S.o:
+	$(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+
+OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \
+	ptrace_user.o sysrq.o
+
+EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel
+
+all: $(OBJ)
+
+$(OBJ): $(OBJS)
+	rm -f $@
+	$(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@
+
+ptrace_user.o: ptrace_user.c
+	$(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+sigcontext.o: sigcontext.c
+	$(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+
+semaphore.c:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+checksum.S:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/lib/$@ $@
+
+mk_defs.c:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+ppc_defs.head:
+	rm -f $@
+	ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@
+
+ppc_defs.h: mk_defs.c ppc_defs.head \
+		$(TOPDIR)/include/asm-ppc/mmu.h \
+		$(TOPDIR)/include/asm-ppc/processor.h \
+		$(TOPDIR)/include/asm-ppc/pgtable.h \
+		$(TOPDIR)/include/asm-ppc/ptrace.h
+#	$(CC) $(CFLAGS) -S mk_defs.c
+	cp ppc_defs.head ppc_defs.h
+# for bk, this way we can write to the file even if it's not checked out
+	echo '#define THREAD 608' >> ppc_defs.h
+	echo '#define PT_REGS 8' >> ppc_defs.h
+	echo '#define CLONE_VM 256' >> ppc_defs.h
+#	chmod u+w ppc_defs.h
+#	grep '^#define' mk_defs.s >> ppc_defs.h
+#	rm mk_defs.s
+
+# the asm link is horrible, and breaks the other targets.  This is also
+# not going to work with parallel makes.
+
+checksum.o: checksum.S
+	rm -f asm
+	ln -s $(TOPDIR)/include/asm-ppc asm
+	$(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+	rm -f asm
+
+misc.o: misc.S ppc_defs.h
+	rm -f asm
+	ln -s $(TOPDIR)/include/asm-ppc asm
+	$(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o
+	rm -f asm
+
+clean:
+	rm -f $(OBJS)
+	rm -f ppc_defs.h
+	rm -f checksum.S semaphore.c mk_defs.c
+
+fastdep:
+
+dep:
+
+modules:
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/um/sys-ppc/misc.S b/arch/um/sys-ppc/misc.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/misc.S	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,116 @@
+/*
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * A couple of functions stolen from arch/ppc/kernel/misc.S for UML
+ * by Chris Emerson.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include "ppc_asm.h"
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx)
+#define CACHE_LINE_SIZE		16
+#define LG_CACHE_LINE_SIZE	4
+#define MAX_COPY_PREFETCH	1
+#elif !defined(CONFIG_PPC64BRIDGE)
+#define CACHE_LINE_SIZE		32
+#define LG_CACHE_LINE_SIZE	5
+#define MAX_COPY_PREFETCH	4
+#else
+#define CACHE_LINE_SIZE		128
+#define LG_CACHE_LINE_SIZE	7
+#define MAX_COPY_PREFETCH	1
+#endif /* CONFIG_4xx || CONFIG_8xx */
+
+	.text
+
+/*
+ * Clear a page using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced).  This only works on cacheable memory.
+ */
+_GLOBAL(clear_page)
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+#ifdef CONFIG_8xx
+	li	r4, 0
+1:	stw	r4, 0(r3)
+	stw	r4, 4(r3)
+	stw	r4, 8(r3)
+	stw	r4, 12(r3)
+#else
+1:	dcbz	0,r3
+#endif
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	blr
+
+/*
+ * Copy a whole page.  We use the dcbz instruction on the destination
+ * to reduce memory traffic (it eliminates the unnecessary reads of
+ * the destination into cache).  This requires that the destination
+ * is cacheable.
+ */
+#define COPY_16_BYTES		\
+	lwz	r6,4(r4);	\
+	lwz	r7,8(r4);	\
+	lwz	r8,12(r4);	\
+	lwzu	r9,16(r4);	\
+	stw	r6,4(r3);	\
+	stw	r7,8(r3);	\
+	stw	r8,12(r3);	\
+	stwu	r9,16(r3)
+
+_GLOBAL(copy_page)
+	addi	r3,r3,-4
+	addi	r4,r4,-4
+	li	r5,4
+
+#ifndef CONFIG_8xx
+#if MAX_COPY_PREFETCH > 1
+	li	r0,MAX_COPY_PREFETCH
+	li	r11,4
+	mtctr	r0
+11:	dcbt	r11,r4
+	addi	r11,r11,CACHE_LINE_SIZE
+	bdnz	11b
+#else /* MAX_COPY_PREFETCH == 1 */
+	dcbt	r5,r4
+	li	r11,CACHE_LINE_SIZE+4
+#endif /* MAX_COPY_PREFETCH */
+#endif /* CONFIG_8xx */
+
+	li	r0,4096/CACHE_LINE_SIZE
+	mtctr	r0
+1:
+#ifndef CONFIG_8xx
+	dcbt	r11,r4
+	dcbz	r5,r3
+#endif
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 32
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 64
+	COPY_16_BYTES
+	COPY_16_BYTES
+#if CACHE_LINE_SIZE >= 128
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+	COPY_16_BYTES
+#endif
+#endif
+#endif
+	bdnz	1b
+	blr
diff -Nru a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/miscthings.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,56 @@
+#include "linux/threads.h"
+#include "linux/stddef.h"  // for NULL
+#include "linux/elf.h"  // for AT_NULL
+
+/* unsigned int local_bh_count[NR_CPUS]; */
+unsigned long isa_io_base = 0;
+
+/* The following function nicked from arch/ppc/kernel/process.c and
+ * adapted slightly */
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+void shove_aux_table(unsigned long sp)
+{
+	int argc;
+	char *p;
+	unsigned long e;
+	unsigned long aux_start, offset;
+
+	argc = *(int *)sp;
+	sp += sizeof(int) + (argc + 1) * sizeof(char *);
+	/* skip over the environment pointers */
+	do {
+		p = *(char **)sp;
+		sp += sizeof(char *);
+	} while (p != NULL);
+	aux_start = sp;
+	/* skip to the end of the auxiliary table */
+	do {
+		e = *(unsigned long *)sp;
+		sp += 2 * sizeof(unsigned long);
+	} while (e != AT_NULL);
+	offset = ((aux_start + 15) & ~15) - aux_start;
+	if (offset != 0) {
+		do {
+			sp -= sizeof(unsigned long);
+			e = *(unsigned long *)sp;
+			*(unsigned long *)(sp + offset) = e;
+		} while (sp > aux_start);
+	}
+}
+/* END stuff taken from arch/ppc/kernel/process.c */
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/ptrace.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,28 @@
+#include "linux/sched.h"
+#include "asm/ptrace.h"
+
+int putreg(struct task_struct *child, unsigned long regno, 
+		  unsigned long value)
+{
+	child->thread.process_regs.regs[regno >> 2] = value;
+	return 0;
+}
+
+unsigned long getreg(struct task_struct *child, unsigned long regno)
+{
+	unsigned long retval = ~0UL;
+
+	retval &= child->thread.process_regs.regs[regno >> 2];
+	return retval;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-ppc/ptrace_user.c b/arch/um/sys-ppc/ptrace_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/ptrace_user.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,40 @@
+#include <sys/ptrace.h>
+#include <errno.h>
+#include <asm/ptrace.h>
+#include "sysdep/ptrace.h"
+
+int ptrace_getregs(long pid, unsigned long *regs_out)
+{
+    int i;
+    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
+	errno = 0;
+	regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0);
+	if (errno) {
+	    return -errno;
+	}
+    }
+    return 0;
+}
+
+int ptrace_setregs(long pid, unsigned long *regs_in)
+{
+    int i;
+    for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) {
+	if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) {
+	    if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) {
+		return -errno;
+	    }
+	}
+    }
+    return 0;
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/sigcontext.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,15 @@
+#include "asm/ptrace.h"
+#include "asm/sigcontext.h"
+#include "sysdep/ptrace.h"
+#include "user_util.h"
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/sys-ppc/sysrq.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "asm/ptrace.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs_subarch *regs)
+{
+	printk("\n");
+	printk("show_regs(): insert regs here.\n");
+#if 0
+        printk("\n");
+        printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip,
+	       smp_processor_id());
+        if (regs->xcs & 3)
+                printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp);
+        printk(" EFLAGS: %08lx\n", regs->eflags);
+        printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
+                regs->eax, regs->ebx, regs->ecx, regs->edx);
+        printk("ESI: %08lx EDI: %08lx EBP: %08lx",
+                regs->esi, regs->edi, regs->ebp);
+        printk(" DS: %04x ES: %04x\n",
+                0xffff & regs->xds, 0xffff & regs->xes);
+#endif
+
+        show_trace(&regs->gpr[1]);
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/util/Makefile b/arch/um/util/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/util/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,15 @@
+all : mk_task
+
+mk_task : mk_task_user.o mk_task_kern.o
+	$(CC) -o mk_task mk_task_user.o mk_task_kern.o
+
+mk_task_user.o : mk_task_user.c
+	$(CC) -c $< 
+
+mk_task_kern.o : mk_task_kern.c
+	$(CC) $(CFLAGS) -c $< 
+
+clean :
+	$(RM) mk_task *.o *~
+
+archmrproper : clean
diff -Nru a/arch/um/util/mk_task_kern.c b/arch/um/util/mk_task_kern.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/util/mk_task_kern.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,17 @@
+#include "linux/sched.h"
+#include "linux/stddef.h"
+
+extern void print(char *name, char *type, int offset);
+extern void print_ptr(char *name, char *type, int offset);
+extern void print_head(void);
+extern void print_tail(void);
+
+int main(int argc, char **argv)
+{
+  print_head();
+  print_ptr("TASK_REGS", "struct uml_pt_regs", 
+	    offsetof(struct task_struct, thread.regs));
+  print("TASK_PID", "int", offsetof(struct task_struct, pid));
+  print_tail();
+  return(0);
+}
diff -Nru a/arch/um/util/mk_task_user.c b/arch/um/util/mk_task_user.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/util/mk_task_user.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+void print(char *name, char *type, int offset)
+{
+  printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+void print_ptr(char *name, char *type, int offset)
+{
+  printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type,
+	 offset);
+}
+
+void print_head(void)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_task\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __TASK_H\n");
+  printf("#define __TASK_H\n");
+  printf("\n");
+}
+
+void print_tail(void)
+{
+  printf("\n");
+  printf("#endif\n");
+}
diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in
--- a/drivers/acpi/Config.in	Sun Sep 15 19:20:23 2002
+++ b/drivers/acpi/Config.in	Sun Sep 15 19:20:23 2002
@@ -2,91 +2,78 @@
 # ACPI Configuration
 #
 
-if [ "$CONFIG_X86" = "y" ]; then
+mainmenu_option next_comment
+comment 'ACPI Support'
 
-  mainmenu_option next_comment
-  comment 'ACPI Support'
-  bool         'ACPI Support' CONFIG_ACPI
-  if [ "$CONFIG_ACPI" = "y" ]; then
-    if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
-      bool         'CPU Enumeration Only' CONFIG_ACPI_HT_ONLY
-    fi
-
-    if [ "$CONFIG_ACPI_HT_ONLY" = "y" ]; then
-      define_bool CONFIG_ACPI_BOOT		y
-    else
-      define_bool CONFIG_ACPI_BOOT		y
-      define_bool CONFIG_ACPI_BUS		y
-      define_bool CONFIG_ACPI_INTERPRETER	y
-      define_bool CONFIG_ACPI_EC		y
-      define_bool CONFIG_ACPI_POWER		y
-      if [ "$CONFIG_PCI" = "y" ]; then
-        define_bool CONFIG_ACPI_PCI		y
-      fi
-      define_bool CONFIG_ACPI_SLEEP		$CONFIG_SOFTWARE_SUSPEND
-      define_bool CONFIG_ACPI_SYSTEM		y
-      tristate     '  AC Adapter'	CONFIG_ACPI_AC
-      tristate     '  Battery'		CONFIG_ACPI_BATTERY
-      tristate     '  Button'		CONFIG_ACPI_BUTTON
-      tristate     '  Fan'		CONFIG_ACPI_FAN
-      tristate     '  Processor'	CONFIG_ACPI_PROCESSOR
-      dep_tristate '  Thermal Zone' 	CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
-      if [ "$CONFIG_NUMA" = "y" ]; then
-         dep_bool       '  NUMA support'     CONFIG_ACPI_NUMA $CONFIG_NUMA
+if [ "$CONFIG_X86" = "y" ]; then
+   bool 'ACPI Support' CONFIG_ACPI
+   if [ "$CONFIG_ACPI" = "y" ]; then
+      if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
+         bool         'CPU Enumeration Only' CONFIG_ACPI_HT_ONLY
       fi
-      tristate     '  Toshiba Laptop Extras'	CONFIG_ACPI_TOSHIBA
-      bool         '  Debug Statements'	CONFIG_ACPI_DEBUG
-    fi
-  fi
 
-  endmenu
+      define_bool CONFIG_ACPI_BOOT y
 
+      if [ "$CONFIG_ACPI_HT_ONLY" != "y" ]; then
+         tristate '  AC Adapter' CONFIG_ACPI_AC
+         tristate '  Battery' CONFIG_ACPI_BATTERY
+         tristate '  Button' CONFIG_ACPI_BUTTON
+         tristate '  Fan' CONFIG_ACPI_FAN
+         tristate '  Processor'	CONFIG_ACPI_PROCESSOR
+         dep_tristate '  Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
+         if [ "$CONFIG_NUMA" = "y" ]; then
+            dep_bool '  NUMA support' CONFIG_ACPI_NUMA $CONFIG_NUMA
+         fi
+         tristate '  Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA
+         bool '  Debug Statements' CONFIG_ACPI_DEBUG
+
+         define_bool CONFIG_ACPI_BOOT y
+         define_bool CONFIG_ACPI_BUS y
+         define_bool CONFIG_ACPI_INTERPRETER y
+         define_bool CONFIG_ACPI_EC y
+         define_bool CONFIG_ACPI_POWER y
+         define_bool CONFIG_ACPI_PCI $CONFIG_PCI
+         define_bool CONFIG_ACPI_SLEEP $CONFIG_SOFTWARE_SUSPEND
+         define_bool CONFIG_ACPI_SYSTEM	y
+      fi
+   fi
 fi
 
-
 if [ "$CONFIG_IA64" = "y" ]; then
-
-  if [ "$CONFIG_IA64_SGI_SN" = "y" ]; then
-    mainmenu_option next_comment
-    comment 'ACPI Support'
-    define_bool CONFIG_ACPI		y
-    define_bool CONFIG_ACPI_EFI		y
-    define_bool CONFIG_ACPI_BOOT	y
-    define_bool CONFIG_ACPI_BUS		n
-    define_bool CONFIG_ACPI_INTERPRETER n
-    define_bool CONFIG_ACPI_PCI		n
-    define_bool CONFIG_ACPI_POWER 	n
-    define_bool CONFIG_ACPI_SYSTEM 	n
-    define_bool CONFIG_ACPI_BUTTON	n
-    define_bool CONFIG_ACPI_FAN		n
-    define_bool CONFIG_ACPI_PROCESSOR	n
-    define_bool CONFIG_ACPI_THERMAL	n
-    define_bool CONFIG_ACPI_NUMA	y
-    endmenu
-  fi
-
-  if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
-    mainmenu_option next_comment
-    comment 'ACPI Support'
-    if [ "$CONFIG_PCI" = "y" ]; then
-      define_bool CONFIG_ACPI_PCI 	y
-    fi
-    define_bool CONFIG_ACPI		y
-    define_bool CONFIG_ACPI_EFI		y
-    define_bool CONFIG_ACPI_BOOT	y
-    define_bool CONFIG_ACPI_BUS		y
-    define_bool CONFIG_ACPI_INTERPRETER y
-    define_bool CONFIG_ACPI_POWER 	y
-    define_bool CONFIG_ACPI_SYSTEM 	y
-    tristate     '  Button'		CONFIG_ACPI_BUTTON
-    tristate     '  Fan'		CONFIG_ACPI_FAN
-    tristate     '  Processor'		CONFIG_ACPI_PROCESSOR
-    dep_tristate '  Thermal Zone'       CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
-    if [ "$CONFIG_NUMA" = "y" ]; then
-       dep_bool       '  NUMA support'       CONFIG_ACPI_NUMA $CONFIG_NUMA
-    fi
-    bool         '  Debug Statements' 	CONFIG_ACPI_DEBUG
-    endmenu
-  fi
-
+   if [ "$CONFIG_IA64_SGI_SN" = "y" ]; then
+      define_bool CONFIG_ACPI y
+      define_bool CONFIG_ACPI_EFI y
+      define_bool CONFIG_ACPI_BOOT y
+      define_bool CONFIG_ACPI_BUS n
+      define_bool CONFIG_ACPI_INTERPRETER n
+      define_bool CONFIG_ACPI_PCI n
+      define_bool CONFIG_ACPI_POWER n
+      define_bool CONFIG_ACPI_SYSTEM n
+      define_bool CONFIG_ACPI_BUTTON n
+      define_bool CONFIG_ACPI_FAN n
+      define_bool CONFIG_ACPI_PROCESSOR n
+      define_bool CONFIG_ACPI_THERMAL n
+      define_bool CONFIG_ACPI_NUMA y
+   fi
+
+   if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+      tristate     '  Button' CONFIG_ACPI_BUTTON
+      tristate     '  Fan' CONFIG_ACPI_FAN
+      tristate     '  Processor' CONFIG_ACPI_PROCESSOR
+      dep_tristate '  Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR
+      if [ "$CONFIG_NUMA" = "y" ]; then
+         dep_bool '  NUMA support' CONFIG_ACPI_NUMA $CONFIG_NUMA
+      fi
+      bool '  Debug Statements' CONFIG_ACPI_DEBUG
+      define_bool CONFIG_ACPI_PCI $CONFIG_PCI
+      define_bool CONFIG_ACPI y
+      define_bool CONFIG_ACPI_EFI y
+      define_bool CONFIG_ACPI_BOOT y
+      define_bool CONFIG_ACPI_BUS y
+      define_bool CONFIG_ACPI_INTERPRETER y
+      define_bool CONFIG_ACPI_POWER y
+      define_bool CONFIG_ACPI_SYSTEM y
+   fi
 fi
+
+endmenu
diff -Nru a/drivers/acpi/ac.c b/drivers/acpi/ac.c
--- a/drivers/acpi/ac.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/acpi/ac.c	Sun Sep 15 19:19:37 2002
@@ -51,7 +51,7 @@
 	.class =	ACPI_AC_CLASS,
 	.ids =		ACPI_AC_HID,
 	.ops =		{
-				.add =	acpi_ac_add,
+				.add =		acpi_ac_add,
 				.remove =	acpi_ac_remove,
 			},
 };
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/acpi/acpi_ksyms.c	Sun Sep 15 19:19:30 2002
@@ -114,6 +114,7 @@
 #ifdef CONFIG_ACPI_BUS
 
 EXPORT_SYMBOL(acpi_fadt);
+EXPORT_SYMBOL(acpi_walk_namespace);
 EXPORT_SYMBOL(acpi_root_dir);
 EXPORT_SYMBOL(acpi_bus_get_device);
 EXPORT_SYMBOL(acpi_bus_get_status);
@@ -127,4 +128,3 @@
 EXPORT_SYMBOL(acpi_init);
 
 #endif /*CONFIG_ACPI_BUS*/
-
diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c
--- a/drivers/acpi/battery.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/acpi/battery.c	Sun Sep 15 19:19:29 2002
@@ -162,7 +162,7 @@
 	}
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	if (!result)
 		(*bif) = (struct acpi_battery_info *) data.pointer;
@@ -223,7 +223,7 @@
 	}
 
 end:
-	kfree(buffer.pointer);
+	acpi_os_free(buffer.pointer);
 
 	if (!result)
 		(*bst) = (struct acpi_battery_status *) data.pointer;
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	Sun Sep 15 19:19:53 2002
+++ b/drivers/acpi/bus.c	Sun Sep 15 19:19:53 2002
@@ -32,7 +32,9 @@
 #include <linux/sched.h>
 #include <linux/pm.h>
 #include <linux/proc_fs.h>
+#ifdef CONFIG_X86
 #include <asm/mpspec.h>
+#endif
 #include "acpi_bus.h"
 #include "acpi_drivers.h"
 #include "include/acinterp.h"	/* for acpi_ex_eisa_id_to_string() */
@@ -665,7 +667,7 @@
 	if (!event_is_open)
 		return_VALUE(0);
 
-	event = kmalloc(sizeof(struct acpi_bus_event), GFP_KERNEL);
+	event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
 	if (!event)
 		return_VALUE(-ENOMEM);
 
@@ -1967,11 +1969,13 @@
 		goto error1;
 	}
 
+#ifdef CONFIG_X86
 	/* Ensure the SCI is set to level-triggered, active-low */
 	if (acpi_ioapic)
 		mp_override_legacy_irq(acpi_fadt.sci_int, 3, 3, acpi_fadt.sci_int);
 	else
 		eisa_set_level_irq(acpi_fadt.sci_int);
+#endif
 
 	status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
 	if (ACPI_FAILURE(status)) {
diff -Nru a/drivers/acpi/button.c b/drivers/acpi/button.c
--- a/drivers/acpi/button.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/acpi/button.c	Sun Sep 15 19:19:28 2002
@@ -70,7 +70,6 @@
 
 static struct proc_dir_entry	*acpi_button_dir = NULL;
 
-
 static int
 acpi_button_read_info (
 	char			*page,
diff -Nru a/drivers/acpi/debugger/Makefile b/drivers/acpi/debugger/Makefile
--- a/drivers/acpi/debugger/Makefile	Sun Sep 15 19:20:18 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-$(CONFIG_ACPI_INTERPRETER) := $(patsubst %.c,%.o,$(wildcard *.c))
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
-
-include $(TOPDIR)/Rules.make
diff -Nru a/drivers/acpi/debugger/dbcmds.c b/drivers/acpi/debugger/dbcmds.c
--- a/drivers/acpi/debugger/dbcmds.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1114 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbcmds - debug commands and output routines
- *              $Revision: 87 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acdispat.h"
-#include "amlcode.h"
-#include "acnamesp.h"
-#include "acevents.h"
-#include "acdebug.h"
-#include "acresrc.h"
-#include "acdisasm.h"
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbcmds")
-
-
-/*
- * Arguments for the Objects command
- * These object types map directly to the ACPI_TYPES
- */
-
-static ARGUMENT_INFO        acpi_db_object_types [] =
-{ {"ANY"},
-	{"NUMBERS"},
-	{"STRINGS"},
-	{"BUFFERS"},
-	{"PACKAGES"},
-	{"FIELDS"},
-	{"DEVICES"},
-	{"EVENTS"},
-	{"METHODS"},
-	{"MUTEXES"},
-	{"REGIONS"},
-	{"POWERRESOURCES"},
-	{"PROCESSORS"},
-	{"THERMALZONES"},
-	{"BUFFERFIELDS"},
-	{"DDBHANDLES"},
-	{NULL}           /* Must be null terminated */
-};
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_walk_for_references
- *
- * PARAMETERS:  Callback from Walk_namespace
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Check if this namespace object refers to the target object
- *              that is passed in as the context value.
- *
- * Note: Currently doesn't check subobjects within the Node's object
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_walk_for_references (
-	acpi_handle             obj_handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
-{
-	acpi_operand_object     *obj_desc = (acpi_operand_object *) context;
-	acpi_namespace_node     *node = (acpi_namespace_node *) obj_handle;
-
-
-	/* Check for match against the namespace node itself */
-
-	if (node == (void *) obj_desc) {
-		acpi_os_printf ("Object is a Node [%4.4s]\n", node->name.ascii);
-	}
-
-	/* Check for match against the object attached to the node */
-
-	if (acpi_ns_get_attached_object (node) == obj_desc) {
-		acpi_os_printf ("Reference at Node->Object %p [%4.4s]\n", node, node->name.ascii);
-	}
-
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_find_references
- *
- * PARAMETERS:  Object_arg      - String with hex value of the object
- *
- * RETURN:      None
- *
- * DESCRIPTION: Search namespace for all references to the input object
- *
- ******************************************************************************/
-
-void
-acpi_db_find_references (
-	NATIVE_CHAR             *object_arg)
-{
-	acpi_operand_object     *obj_desc;
-
-
-	/* Convert string to object pointer */
-
-	obj_desc = ACPI_TO_POINTER (ACPI_STRTOUL (object_arg, NULL, 16));
-
-	/* Search all nodes in namespace */
-
-	(void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			  acpi_db_walk_for_references, (void *) obj_desc, NULL);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_locks
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display information about internal mutexes.
- *
- ******************************************************************************/
-
-void
-acpi_db_display_locks (void)
-{
-	u32                     i;
-
-
-	for (i = 0; i < MAX_MTX; i++) {
-		acpi_os_printf ("%26s : %s\n", acpi_ut_get_mutex_name (i),
-				 acpi_gbl_acpi_mutex_info[i].owner_id == ACPI_MUTEX_NOT_ACQUIRED
-						? "Locked" : "Unlocked");
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_table_info
- *
- * PARAMETERS:  Table_arg       - String with name of table to be displayed
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display information about loaded tables.  Current
- *              implementation displays all loaded tables.
- *
- ******************************************************************************/
-
-void
-acpi_db_display_table_info (
-	NATIVE_CHAR             *table_arg)
-{
-	u32                     i;
-
-
-	for (i = 0; i < NUM_ACPI_TABLES; i++) {
-		if (acpi_gbl_acpi_tables[i].pointer) {
-			acpi_os_printf ("%s at %p length %X\n", acpi_gbl_acpi_table_data[i].name,
-					 acpi_gbl_acpi_tables[i].pointer, acpi_gbl_acpi_tables[i].length);
-		}
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_unload_acpi_table
- *
- * PARAMETERS:  Table_arg       - Name of the table to be unloaded
- *              Instance_arg    - Which instance of the table to unload (if
- *                                there are multiple tables of the same type)
- *
- * RETURN:      Nonde
- *
- * DESCRIPTION: Unload an ACPI table.
- *              Instance is not implemented
- *
- ******************************************************************************/
-
-void
-acpi_db_unload_acpi_table (
-	NATIVE_CHAR             *table_arg,
-	NATIVE_CHAR             *instance_arg)
-{
-	u32                     i;
-	acpi_status             status;
-
-
-	/* Search all tables for the target type */
-
-	for (i = 0; i < NUM_ACPI_TABLES; i++) {
-		if (!ACPI_STRNCMP (table_arg, acpi_gbl_acpi_table_data[i].signature,
-				acpi_gbl_acpi_table_data[i].sig_length)) {
-			/* Found the table, unload it */
-
-			status = acpi_unload_table (i);
-			if (ACPI_SUCCESS (status)) {
-				acpi_os_printf ("[%s] unloaded and uninstalled\n", table_arg);
-			}
-			else {
-				acpi_os_printf ("%s, while unloading [%s]\n",
-					acpi_format_exception (status), table_arg);
-			}
-
-			return;
-		}
-	}
-
-	acpi_os_printf ("Unknown table type [%s]\n", table_arg);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_set_method_breakpoint
- *
- * PARAMETERS:  Location            - AML offset of breakpoint
- *              Walk_state          - Current walk info
- *              Op                  - Current Op (from parse walk)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Set a breakpoint in a control method at the specified
- *              AML offset
- *
- ******************************************************************************/
-
-void
-acpi_db_set_method_breakpoint (
-	NATIVE_CHAR             *location,
-	acpi_walk_state         *walk_state,
-	acpi_parse_object       *op)
-{
-	u32                     address;
-
-
-	if (!op) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	/* Get and verify the breakpoint address */
-
-	address = ACPI_STRTOUL (location, NULL, 16);
-	if (address <= op->common.aml_offset) {
-		acpi_os_printf ("Breakpoint %X is beyond current address %X\n", address, op->common.aml_offset);
-	}
-
-	/* Save breakpoint in current walk */
-
-	walk_state->user_breakpoint = address;
-	acpi_os_printf ("Breakpoint set at AML offset %X\n", address);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_set_method_call_breakpoint
- *
- * PARAMETERS:  Op                  - Current Op (from parse walk)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Set a breakpoint in a control method at the specified
- *              AML offset
- *
- ******************************************************************************/
-
-void
-acpi_db_set_method_call_breakpoint (
-	acpi_parse_object       *op)
-{
-
-
-	if (!op) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-
-	acpi_gbl_step_to_next_call = TRUE;
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_disassemble_aml
- *
- * PARAMETERS:  Statements          - Number of statements to disassemble
- *              Op                  - Current Op (from parse walk)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
- *              of statements specified.
- *
- ******************************************************************************/
-
-void
-acpi_db_disassemble_aml (
-	NATIVE_CHAR             *statements,
-	acpi_parse_object       *op)
-{
-	u32                     num_statements = 8;
-
-
-	if (!op) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	if (statements) {
-		num_statements = ACPI_STRTOUL (statements, NULL, 0);
-	}
-
-	acpi_dm_disassemble (NULL, op, num_statements);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_dump_namespace
- *
- * PARAMETERS:  Start_arg       - Node to begin namespace dump
- *              Depth_arg       - Maximum tree depth to be dumped
- *
- * RETURN:      None
- *
- * DESCRIPTION: Dump entire namespace or a subtree.  Each node is displayed
- *              with type and other information.
- *
- ******************************************************************************/
-
-void
-acpi_db_dump_namespace (
-	NATIVE_CHAR             *start_arg,
-	NATIVE_CHAR             *depth_arg)
-{
-	acpi_handle             subtree_entry = acpi_gbl_root_node;
-	u32                     max_depth = ACPI_UINT32_MAX;
-
-
-	/* No argument given, just start at the root and dump entire namespace */
-
-	if (start_arg) {
-		/* Check if numeric argument, must be a Node */
-
-		if ((start_arg[0] >= 0x30) && (start_arg[0] <= 0x39)) {
-			subtree_entry = ACPI_TO_POINTER (ACPI_STRTOUL (start_arg, NULL, 16));
-			if (!acpi_os_readable (subtree_entry, sizeof (acpi_namespace_node))) {
-				acpi_os_printf ("Address %p is invalid in this address space\n", subtree_entry);
-				return;
-			}
-
-			if (ACPI_GET_DESCRIPTOR_TYPE (subtree_entry) != ACPI_DESC_TYPE_NAMED) {
-				acpi_os_printf ("Address %p is not a valid Named object\n", subtree_entry);
-				return;
-			}
-		}
-
-		/* Alpha argument */
-
-		else {
-			/* The parameter is a name string that must be resolved to a Named obj*/
-
-			subtree_entry = acpi_db_local_ns_lookup (start_arg);
-			if (!subtree_entry) {
-				subtree_entry = acpi_gbl_root_node;
-			}
-		}
-
-		/* Now we can check for the depth argument */
-
-		if (depth_arg) {
-			max_depth = ACPI_STRTOUL (depth_arg, NULL, 0);
-		}
-	}
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-	acpi_os_printf ("ACPI Namespace (from %p subtree):\n", subtree_entry);
-
-	/* Display the subtree */
-
-	acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-	acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, ACPI_UINT32_MAX, subtree_entry);
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_dump_namespace_by_owner
- *
- * PARAMETERS:  Owner_arg       - Owner ID whose nodes will be displayed
- *              Depth_arg       - Maximum tree depth to be dumped
- *
- * RETURN:      None
- *
- * DESCRIPTION: Dump elements of the namespace that are owned by the Owner_id.
- *
- ******************************************************************************/
-
-void
-acpi_db_dump_namespace_by_owner (
-	NATIVE_CHAR             *owner_arg,
-	NATIVE_CHAR             *depth_arg)
-{
-	acpi_handle             subtree_entry = acpi_gbl_root_node;
-	u32                     max_depth = ACPI_UINT32_MAX;
-	u16                     owner_id;
-
-
-	owner_id = (u16) ACPI_STRTOUL (owner_arg, NULL, 0);
-
-	/* Now we can check for the depth argument */
-
-	if (depth_arg) {
-		max_depth = ACPI_STRTOUL (depth_arg, NULL, 0);
-	}
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-	acpi_os_printf ("ACPI Namespace by owner %X:\n", owner_id);
-
-	/* Display the subtree */
-
-	acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-	acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, owner_id, subtree_entry);
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_send_notify
- *
- * PARAMETERS:  Name            - Name of ACPI object to send the notify to
- *              Value           - Value of the notify to send.
- *
- * RETURN:      None
- *
- * DESCRIPTION: Send an ACPI notification.  The value specified is sent to the
- *              named object as an ACPI notify.
- *
- ******************************************************************************/
-
-void
-acpi_db_send_notify (
-	NATIVE_CHAR             *name,
-	u32                     value)
-{
-	acpi_namespace_node     *node;
-	acpi_status             status;
-
-
-	/* Translate name to an Named object */
-
-	node = acpi_db_local_ns_lookup (name);
-	if (!node) {
-		return;
-	}
-
-	/* Decode Named object type */
-
-	switch (node->type) {
-	case ACPI_TYPE_DEVICE:
-	case ACPI_TYPE_THERMAL:
-
-		 /* Send the notify */
-
-		status = acpi_ev_queue_notify_request (node, value);
-		if (ACPI_FAILURE (status)) {
-			acpi_os_printf ("Could not queue notify\n");
-		}
-		break;
-
-	default:
-		acpi_os_printf ("Named object is not a device or a thermal object\n");
-		break;
-	}
-
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_set_method_data
- *
- * PARAMETERS:  Type_arg        - L for local, A for argument
- *              Index_arg       - which one
- *              Value_arg       - Value to set.
- *
- * RETURN:      None
- *
- * DESCRIPTION: Set a local or argument for the running control method.
- *              NOTE: only object supported is Number.
- *
- ******************************************************************************/
-
-void
-acpi_db_set_method_data (
-	NATIVE_CHAR             *type_arg,
-	NATIVE_CHAR             *index_arg,
-	NATIVE_CHAR             *value_arg)
-{
-	NATIVE_CHAR             type;
-	u32                     index;
-	u32                     value;
-	acpi_walk_state         *walk_state;
-	acpi_operand_object     *obj_desc;
-	acpi_status             status;
-
-
-	/* Validate Type_arg */
-
-	ACPI_STRUPR (type_arg);
-	type = type_arg[0];
-	if ((type != 'L') &&
-		(type != 'A')) {
-		acpi_os_printf ("Invalid SET operand: %s\n", type_arg);
-		return;
-	}
-
-	/* Get the index and value */
-
-	index = ACPI_STRTOUL (index_arg, NULL, 16);
-	value = ACPI_STRTOUL (value_arg, NULL, 16);
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-
-	/* Create and initialize the new object */
-
-	obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
-	if (!obj_desc) {
-		acpi_os_printf ("Could not create an internal object\n");
-		return;
-	}
-
-	obj_desc->integer.value = value;
-
-
-	/* Store the new object into the target */
-
-	switch (type) {
-	case 'A':
-
-		/* Set a method argument */
-
-		if (index > MTH_MAX_ARG) {
-			acpi_os_printf ("Arg%d - Invalid argument name\n", index);
-			return;
-		}
-
-		status = acpi_ds_store_object_to_local (AML_ARG_OP, index, obj_desc, walk_state);
-		if (ACPI_FAILURE (status)) {
-			return;
-		}
-
-		obj_desc = walk_state->arguments[index].object;
-
-		acpi_os_printf ("Arg%d: ", index);
-		acpi_db_display_internal_object (obj_desc, walk_state);
-		break;
-
-	case 'L':
-
-		/* Set a method local */
-
-		if (index > MTH_MAX_LOCAL) {
-			acpi_os_printf ("Local%d - Invalid local variable name\n", index);
-			return;
-		}
-
-		status = acpi_ds_store_object_to_local (AML_LOCAL_OP, index, obj_desc, walk_state);
-		if (ACPI_FAILURE (status)) {
-			return;
-		}
-
-		obj_desc = walk_state->local_variables[index].object;
-
-		acpi_os_printf ("Local%d: ", index);
-		acpi_db_display_internal_object (obj_desc, walk_state);
-		break;
-
-	default:
-		break;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_walk_for_specific_objects
- *
- * PARAMETERS:  Callback from Walk_namespace
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Display short info about objects in the namespace
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_walk_for_specific_objects (
-	acpi_handle             obj_handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
-{
-	acpi_operand_object     *obj_desc;
-	acpi_status             status;
-	acpi_buffer             buffer;
-
-
-	obj_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) obj_handle);
-
-	/* Get and display the full pathname to this object */
-
-	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
-	status = acpi_ns_handle_to_pathname (obj_handle, &buffer);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle);
-		return (AE_OK);
-	}
-
-	acpi_os_printf ("%32s", buffer.pointer);
-	ACPI_MEM_FREE (buffer.pointer);
-
-
-	/* Display short information about the object */
-
-	if (obj_desc) {
-		switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
-		case ACPI_TYPE_METHOD:
-			acpi_os_printf (" #Args %d Concurrency %X", obj_desc->method.param_count, obj_desc->method.concurrency);
-			break;
-
-		case ACPI_TYPE_INTEGER:
-			acpi_os_printf (" Value %X", obj_desc->integer.value);
-			break;
-
-		case ACPI_TYPE_STRING:
-			acpi_os_printf (" \"%s\"", obj_desc->string.pointer);
-			break;
-
-		case ACPI_TYPE_REGION:
-			acpi_os_printf (" Space_id %X Address %X Length %X", obj_desc->region.space_id, obj_desc->region.address, obj_desc->region.length);
-			break;
-
-		case ACPI_TYPE_PACKAGE:
-			acpi_os_printf (" #Elements %X", obj_desc->package.count);
-			break;
-
-		case ACPI_TYPE_BUFFER:
-			acpi_os_printf (" Length %X", obj_desc->buffer.length);
-			break;
-
-		default:
-			/* Ignore other object types */
-			break;
-		}
-	}
-
-	acpi_os_printf ("\n");
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_objects
- *
- * PARAMETERS:  Obj_type_arg        - Type of object to display
- *              Display_count_arg   - Max depth to display
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display objects in the namespace of the requested type
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_display_objects (
-	NATIVE_CHAR             *obj_type_arg,
-	NATIVE_CHAR             *display_count_arg)
-{
-	acpi_object_type        type;
-
-
-	/* Get the object type */
-
-	type = acpi_db_match_argument (obj_type_arg, acpi_db_object_types);
-	if (type == ACPI_TYPE_NOT_FOUND) {
-		acpi_os_printf ("Invalid or unsupported argument\n");
-		return (AE_OK);
-	}
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-	acpi_os_printf ("Objects of type [%s] defined in the current ACPI Namespace: \n",
-		acpi_ut_get_type_name (type));
-
-	acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-
-	/* Walk the namespace from the root */
-
-	(void) acpi_walk_namespace (type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			   acpi_db_walk_for_specific_objects, (void *) &type, NULL);
-
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_walk_and_match_name
- *
- * PARAMETERS:  Callback from Walk_namespace
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Find a particular name/names within the namespace.  Wildcards
- *              are supported -- '?' matches any character.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_walk_and_match_name (
-	acpi_handle             obj_handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
-{
-	acpi_status             status;
-	NATIVE_CHAR             *requested_name = (NATIVE_CHAR *) context;
-	u32                     i;
-	acpi_buffer             buffer;
-
-
-	/* Check for a name match */
-
-	for (i = 0; i < 4; i++) {
-		/* Wildcard support */
-
-		if ((requested_name[i] != '?') &&
-			(requested_name[i] != ((acpi_namespace_node *) obj_handle)->name.ascii[i])) {
-			/* No match, just exit */
-
-			return (AE_OK);
-		}
-	}
-
-
-	/* Get the full pathname to this object */
-
-	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
-	status = acpi_ns_handle_to_pathname (obj_handle, &buffer);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could Not get pathname for object %p\n", obj_handle);
-	}
-	else {
-		acpi_os_printf ("%32s (%p) - %s\n", buffer.pointer, obj_handle,
-			acpi_ut_get_type_name (((acpi_namespace_node *) obj_handle)->type));
-		ACPI_MEM_FREE (buffer.pointer);
-	}
-
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_find_name_in_namespace
- *
- * PARAMETERS:  Name_arg        - The 4-character ACPI name to find.
- *                                wildcards are supported.
- *
- * RETURN:      None
- *
- * DESCRIPTION: Search the namespace for a given name (with wildcards)
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_find_name_in_namespace (
-	NATIVE_CHAR             *name_arg)
-{
-
-	if (ACPI_STRLEN (name_arg) > 4) {
-		acpi_os_printf ("Name must be no longer than 4 characters\n");
-		return (AE_OK);
-	}
-
-	/* Walk the namespace from the root */
-
-	(void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			   acpi_db_walk_and_match_name, name_arg, NULL);
-
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_set_scope
- *
- * PARAMETERS:  Name                - New scope path
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Set the "current scope" as maintained by this utility.
- *              The scope is used as a prefix to ACPI paths.
- *
- ******************************************************************************/
-
-void
-acpi_db_set_scope (
-	NATIVE_CHAR             *name)
-{
-	acpi_status             status;
-	acpi_namespace_node     *node;
-
-
-	if (!name || name[0] == 0) {
-		acpi_os_printf ("Current scope: %s\n", acpi_gbl_db_scope_buf);
-		return;
-	}
-
-	acpi_db_prep_namestring (name);
-
-
-	if (name[0] == '\\') {
-		/* Validate new scope from the root */
-
-		status = acpi_ns_get_node_by_path (name, acpi_gbl_root_node, ACPI_NS_NO_UPSEARCH, &node);
-		if (ACPI_FAILURE (status)) {
-			goto error_exit;
-		}
-
-		ACPI_STRCPY (acpi_gbl_db_scope_buf, name);
-		ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\");
-	}
-	else {
-		/* Validate new scope relative to old scope */
-
-		status = acpi_ns_get_node_by_path (name, acpi_gbl_db_scope_node, ACPI_NS_NO_UPSEARCH, &node);
-		if (ACPI_FAILURE (status)) {
-			goto error_exit;
-		}
-
-		ACPI_STRCAT (acpi_gbl_db_scope_buf, name);
-		ACPI_STRCAT (acpi_gbl_db_scope_buf, "\\");
-	}
-
-	acpi_gbl_db_scope_node = node;
-	acpi_os_printf ("New scope: %s\n", acpi_gbl_db_scope_buf);
-	return;
-
-
-error_exit:
-
-	acpi_os_printf ("Could not attach scope: %s, %s\n", name, acpi_format_exception (status));
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_resources
- *
- * PARAMETERS:  Object_arg      - String with hex value of the object
- *
- * RETURN:      None
- *
- * DESCRIPTION:
- *
- ******************************************************************************/
-
-void
-acpi_db_display_resources (
-	NATIVE_CHAR             *object_arg)
-{
-#if ACPI_MACHINE_WIDTH != 16
-
-	acpi_operand_object     *obj_desc;
-	acpi_status             status;
-	acpi_buffer             return_obj;
-
-
-	acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-	acpi_dbg_level |= ACPI_LV_RESOURCES;
-
-	/* Convert string to object pointer */
-
-	obj_desc = ACPI_TO_POINTER (ACPI_STRTOUL (object_arg, NULL, 16));
-
-	/* Prepare for a return object of arbitrary size */
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	/* _PRT */
-
-	acpi_os_printf ("Evaluating _PRT\n");
-
-	status = acpi_evaluate_object (obj_desc, "_PRT", NULL, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not obtain _PRT: %s\n", acpi_format_exception (status));
-		goto get_crs;
-	}
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	status = acpi_get_irq_routing_table (obj_desc, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Get_irq_routing_table failed: %s\n", acpi_format_exception (status));
-	}
-
-	else {
-		acpi_rs_dump_irq_list ((u8 *) acpi_gbl_db_buffer);
-	}
-
-
-	/* _CRS */
-
-get_crs:
-	acpi_os_printf ("Evaluating _CRS\n");
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	status = acpi_evaluate_object (obj_desc, "_CRS", NULL, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not obtain _CRS: %s\n", acpi_format_exception (status));
-		goto get_prs;
-	}
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	status = acpi_get_current_resources (obj_desc, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Acpi_get_current_resources failed: %s\n", acpi_format_exception (status));
-		goto get_prs;
-	}
-
-	else {
-		acpi_rs_dump_resource_list (ACPI_CAST_PTR (acpi_resource, acpi_gbl_db_buffer));
-	}
-
-	status = acpi_set_current_resources (obj_desc, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Acpi_set_current_resources failed: %s\n", acpi_format_exception (status));
-		goto get_prs;
-	}
-
-
-	/* _PRS */
-
-get_prs:
-	acpi_os_printf ("Evaluating _PRS\n");
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	status = acpi_evaluate_object (obj_desc, "_PRS", NULL, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not obtain _PRS: %s\n", acpi_format_exception (status));
-		goto cleanup;
-	}
-
-	return_obj.pointer          = acpi_gbl_db_buffer;
-	return_obj.length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	status = acpi_get_possible_resources (obj_desc, &return_obj);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Acpi_get_possible_resources failed: %s\n", acpi_format_exception (status));
-	}
-
-	else {
-		acpi_rs_dump_resource_list (ACPI_CAST_PTR (acpi_resource, acpi_gbl_db_buffer));
-	}
-
-
-cleanup:
-
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-	return;
-#endif
-
-}
-
-
-typedef struct
-{
-	u32                 nodes;
-	u32                 objects;
-} ACPI_INTEGRITY_INFO;
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_integrity_walk
- *
- * PARAMETERS:  Callback from Walk_namespace
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Examine one NS node for valid values.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_integrity_walk (
-	acpi_handle             obj_handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
-{
-	ACPI_INTEGRITY_INFO     *info = (ACPI_INTEGRITY_INFO *) context;
-	acpi_namespace_node     *node = (acpi_namespace_node *) obj_handle;
-	acpi_operand_object     *object;
-
-
-	info->nodes++;
-	if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
-		acpi_os_printf ("Invalid Descriptor Type for Node %p, Type = %X\n",
-			node, ACPI_GET_DESCRIPTOR_TYPE (node));
-	}
-
-	if (node->type > INTERNAL_TYPE_MAX) {
-		acpi_os_printf ("Invalid Object Type for Node %p, Type = %X\n",
-			node, node->type);
-	}
-
-	if (!acpi_ut_valid_acpi_name (node->name.integer)) {
-		acpi_os_printf ("Invalid Acpi_name for Node %p\n", node);
-	}
-
-	object = acpi_ns_get_attached_object (node);
-	if (object) {
-		info->objects++;
-		if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) {
-			acpi_os_printf ("Invalid Descriptor Type for Object %p, Type = %X\n",
-				object, ACPI_GET_DESCRIPTOR_TYPE (object));
-		}
-	}
-
-
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_check_integrity
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Check entire namespace for data structure integrity
- *
- ******************************************************************************/
-
-void
-acpi_db_check_integrity (void)
-{
-	ACPI_INTEGRITY_INFO     info = {0,0};
-
-	/* Search all nodes in namespace */
-
-	(void) acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			  acpi_db_integrity_walk, (void *) &info, NULL);
-
-	acpi_os_printf ("Verified %d namespace nodes with %d Objects\n", info.nodes, info.objects);
-
-}
-
-#endif /* ACPI_DEBUGGER */
diff -Nru a/drivers/acpi/debugger/dbdisply.c b/drivers/acpi/debugger/dbdisply.c
--- a/drivers/acpi/debugger/dbdisply.c	Sun Sep 15 19:20:12 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,859 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbdisply - debug display commands
- *              $Revision: 78 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "amlcode.h"
-#include "acdispat.h"
-#include "acnamesp.h"
-#include "acparser.h"
-#include "acinterp.h"
-#include "acdebug.h"
-
-
-#ifdef ACPI_DEBUGGER
-
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbdisply")
-
-
-/******************************************************************************
- *
- * FUNCTION:    Acpi_db_get_pointer
- *
- * PARAMETERS:  Target          - Pointer to string to be converted
- *
- * RETURN:      Converted pointer
- *
- * DESCRIPTION: Convert an ascii pointer value to a real value
- *
- *****************************************************************************/
-
-void *
-acpi_db_get_pointer (
-	void                    *target)
-{
-	void                    *obj_ptr;
-
-
-#if ACPI_MACHINE_WIDTH == 16
-#include <stdio.h>
-
-	/* Have to handle 16-bit pointers of the form segment:offset */
-
-	if (!sscanf (target, "%p", &obj_ptr)) {
-		acpi_os_printf ("Invalid pointer: %s\n", target);
-		return (NULL);
-	}
-
-#else
-
-	/* Simple flat pointer */
-
-	obj_ptr = ACPI_TO_POINTER (ACPI_STRTOUL (target, NULL, 16));
-#endif
-
-	return (obj_ptr);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_dump_parser_descriptor
- *
- * PARAMETERS:  Op              - A parser Op descriptor
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display a formatted parser object
- *
- ******************************************************************************/
-
-void
-acpi_db_dump_parser_descriptor (
-	acpi_parse_object       *op)
-{
-	const acpi_opcode_info  *info;
-
-
-	info = acpi_ps_get_opcode_info (op->common.aml_opcode);
-
-	acpi_os_printf ("Parser Op Descriptor:\n");
-	acpi_os_printf ("%20.20s : %4.4X\n", "Opcode", op->common.aml_opcode);
-
-	ACPI_DEBUG_ONLY_MEMBERS (acpi_os_printf ("%20.20s : %s\n", "Opcode Name", info->name));
-
-	acpi_os_printf ("%20.20s : %p\n", "Value/Arg_list", op->common.value.arg);
-	acpi_os_printf ("%20.20s : %p\n", "Parent", op->common.parent);
-	acpi_os_printf ("%20.20s : %p\n", "Next_op", op->common.next);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_decode_and_display_object
- *
- * PARAMETERS:  Target          - String with object to be displayed.  Names
- *                                and hex pointers are supported.
- *              Output_type     - Byte, Word, Dword, or Qword (B|W|D|Q)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display a formatted ACPI object
- *
- ******************************************************************************/
-
-void
-acpi_db_decode_and_display_object (
-	NATIVE_CHAR             *target,
-	NATIVE_CHAR             *output_type)
-{
-	void                    *obj_ptr;
-	acpi_namespace_node     *node;
-	acpi_operand_object     *obj_desc;
-	u32                     display = DB_BYTE_DISPLAY;
-	NATIVE_CHAR             buffer[80];
-	acpi_buffer             ret_buf;
-	acpi_status             status;
-	u32                     size;
-
-
-	if (!target) {
-		return;
-	}
-
-	/* Decode the output type */
-
-	if (output_type) {
-		ACPI_STRUPR (output_type);
-		if (output_type[0] == 'W') {
-			display = DB_WORD_DISPLAY;
-		}
-		else if (output_type[0] == 'D') {
-			display = DB_DWORD_DISPLAY;
-		}
-		else if (output_type[0] == 'Q') {
-			display = DB_QWORD_DISPLAY;
-		}
-	}
-
-	ret_buf.length = sizeof (buffer);
-	ret_buf.pointer = buffer;
-
-	/* Differentiate between a number and a name */
-
-	if ((target[0] >= 0x30) && (target[0] <= 0x39)) {
-		obj_ptr = acpi_db_get_pointer (target);
-		if (!acpi_os_readable (obj_ptr, 16)) {
-			acpi_os_printf ("Address %p is invalid in this address space\n", obj_ptr);
-			return;
-		}
-
-		/* Decode the object type */
-
-		switch (ACPI_GET_DESCRIPTOR_TYPE (obj_ptr)) {
-		case ACPI_DESC_TYPE_NAMED:
-
-			/* This is a namespace Node */
-
-			if (!acpi_os_readable (obj_ptr, sizeof (acpi_namespace_node))) {
-				acpi_os_printf ("Cannot read entire Named object at address %p\n", obj_ptr);
-				return;
-			}
-
-			node = obj_ptr;
-			goto dump_nte;
-
-
-		case ACPI_DESC_TYPE_OPERAND:
-
-			/* This is a ACPI OPERAND OBJECT */
-
-			if (!acpi_os_readable (obj_ptr, sizeof (acpi_operand_object))) {
-				acpi_os_printf ("Cannot read entire ACPI object at address %p\n", obj_ptr);
-				return;
-			}
-
-			acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX);
-			acpi_ex_dump_object_descriptor (obj_ptr, 1);
-			break;
-
-
-		case ACPI_DESC_TYPE_PARSER:
-
-			/* This is a Parser Op object */
-
-			if (!acpi_os_readable (obj_ptr, sizeof (acpi_parse_object))) {
-				acpi_os_printf ("Cannot read entire Parser object at address %p\n", obj_ptr);
-				return;
-			}
-
-			acpi_ut_dump_buffer (obj_ptr, sizeof (acpi_parse_object), display, ACPI_UINT32_MAX);
-			acpi_db_dump_parser_descriptor ((acpi_parse_object *) obj_ptr);
-			break;
-
-
-		default:
-
-			/* Is not a recognizeable object */
-
-			size = 16;
-			if (acpi_os_readable (obj_ptr, 64)) {
-				size = 64;
-			}
-
-			/* Just dump some memory */
-
-			acpi_ut_dump_buffer (obj_ptr, size, display, ACPI_UINT32_MAX);
-			break;
-		}
-
-		return;
-	}
-
-	/* The parameter is a name string that must be resolved to a Named obj */
-
-	node = acpi_db_local_ns_lookup (target);
-	if (!node) {
-		return;
-	}
-
-
-dump_nte:
-	/* Now dump the Named obj */
-
-	status = acpi_get_name (node, ACPI_FULL_PATHNAME, &ret_buf);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not convert name to pathname\n");
-	}
-
-	else {
-		acpi_os_printf ("Object (%p) Pathname: %s\n", node, ret_buf.pointer);
-	}
-
-	if (!acpi_os_readable (node, sizeof (acpi_namespace_node))) {
-		acpi_os_printf ("Invalid Named object at address %p\n", node);
-		return;
-	}
-
-	acpi_ut_dump_buffer ((void *) node, sizeof (acpi_namespace_node), display, ACPI_UINT32_MAX);
-	acpi_ex_dump_node (node, 1);
-
-	obj_desc = acpi_ns_get_attached_object (node);
-	if (obj_desc) {
-		acpi_os_printf ("\nAttached Object (%p):\n", obj_desc);
-		if (!acpi_os_readable (obj_desc, sizeof (acpi_operand_object))) {
-			acpi_os_printf ("Invalid internal ACPI Object at address %p\n", obj_desc);
-			return;
-		}
-
-		acpi_ut_dump_buffer ((void *) obj_desc, sizeof (acpi_operand_object), display, ACPI_UINT32_MAX);
-		acpi_ex_dump_object_descriptor (obj_desc, 1);
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_decode_internal_object
- *
- * PARAMETERS:  Obj_desc        - Object to be displayed
- *
- * RETURN:      None
- *
- * DESCRIPTION: Short display of an internal object.  Numbers and Strings.
- *
- ******************************************************************************/
-
-void
-acpi_db_decode_internal_object (
-	acpi_operand_object     *obj_desc)
-{
-	u32                     i;
-
-
-	if (!obj_desc) {
-		acpi_os_printf (" Uninitialized\n");
-		return;
-	}
-
-	if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
-		acpi_os_printf ("%p", obj_desc);
-		return;
-	}
-
-	acpi_os_printf (" %s", acpi_ut_get_object_type_name (obj_desc));
-
-	switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
-	case ACPI_TYPE_INTEGER:
-
-		acpi_os_printf (" %8.8X%8.8X", ACPI_HIDWORD (obj_desc->integer.value),
-				   ACPI_LODWORD (obj_desc->integer.value));
-		break;
-
-
-	case ACPI_TYPE_STRING:
-
-		acpi_os_printf ("(%d) \"%.24s",
-				obj_desc->string.length, obj_desc->string.pointer);
-
-		if (obj_desc->string.length > 24)
-		{
-			acpi_os_printf ("...");
-		}
-		else
-		{
-			acpi_os_printf ("\"");
-		}
-		break;
-
-
-	case ACPI_TYPE_BUFFER:
-
-		acpi_os_printf ("(%d)", obj_desc->buffer.length);
-		for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) {
-			acpi_os_printf (" %2.2X", obj_desc->buffer.pointer[i]);
-		}
-		break;
-
-
-	default:
-
-		acpi_os_printf ("%p", obj_desc);
-		break;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_decode_node
- *
- * PARAMETERS:  Node        - Object to be displayed
- *
- * RETURN:      None
- *
- * DESCRIPTION: Short display of a namespace node
- *
- ******************************************************************************/
-
-void
-acpi_db_decode_node (
-	acpi_namespace_node     *node)
-{
-
-
-	acpi_os_printf ("<Node>          Name %4.4s Type-%s",
-		node->name.ascii, acpi_ut_get_type_name (node->type));
-
-	if (node->flags & ANOBJ_METHOD_ARG) {
-		acpi_os_printf (" [Method Arg]");
-	}
-	if (node->flags & ANOBJ_METHOD_LOCAL) {
-		acpi_os_printf (" [Method Local]");
-	}
-
-	acpi_db_decode_internal_object (acpi_ns_get_attached_object (node));
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_internal_object
- *
- * PARAMETERS:  Obj_desc        - Object to be displayed
- *              Walk_state      - Current walk state
- *
- * RETURN:      None
- *
- * DESCRIPTION: Short display of an internal object
- *
- ******************************************************************************/
-
-void
-acpi_db_display_internal_object (
-	acpi_operand_object     *obj_desc,
-	acpi_walk_state         *walk_state)
-{
-	u8                      type;
-
-
-	acpi_os_printf ("%p ", obj_desc);
-
-	if (!obj_desc) {
-		acpi_os_printf ("<Null_obj>\n");
-		return;
-	}
-
-	/* Decode the object type */
-
-	switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
-	case ACPI_DESC_TYPE_PARSER:
-
-		acpi_os_printf ("<Parser> ");
-		break;
-
-
-	case ACPI_DESC_TYPE_NAMED:
-
-		acpi_db_decode_node ((acpi_namespace_node *) obj_desc);
-		break;
-
-
-	case ACPI_DESC_TYPE_OPERAND:
-
-		type = ACPI_GET_OBJECT_TYPE (obj_desc);
-		if (type > INTERNAL_TYPE_MAX) {
-			acpi_os_printf (" Type %hX [Invalid Type]", type);
-			return;
-		}
-
-		/* Decode the ACPI object type */
-
-		switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
-		case INTERNAL_TYPE_REFERENCE:
-
-			switch (obj_desc->reference.opcode) {
-			case AML_LOCAL_OP:
-
-				acpi_os_printf ("[Local%d] ", obj_desc->reference.offset);
-				if (walk_state) {
-					obj_desc = walk_state->local_variables[obj_desc->reference.offset].object;
-					acpi_os_printf ("%p", obj_desc);
-					acpi_db_decode_internal_object (obj_desc);
-				}
-				break;
-
-
-			case AML_ARG_OP:
-
-				acpi_os_printf ("[Arg%d] ", obj_desc->reference.offset);
-				if (walk_state) {
-					obj_desc = walk_state->arguments[obj_desc->reference.offset].object;
-					acpi_os_printf ("%p", obj_desc);
-					acpi_db_decode_internal_object (obj_desc);
-				}
-				break;
-
-
-			case AML_DEBUG_OP:
-
-				acpi_os_printf ("[Debug] ");
-				break;
-
-
-			case AML_INDEX_OP:
-
-				acpi_os_printf ("[Index]        ");
-				acpi_db_decode_internal_object (obj_desc->reference.object);
-				break;
-
-
-			case AML_REF_OF_OP:
-
-				acpi_os_printf ("[Reference]    ");
-
-				/* Reference can be to a Node or an Operand object */
-
-				switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc->reference.object)) {
-				case ACPI_DESC_TYPE_NAMED:
-					acpi_db_decode_node (obj_desc->reference.object);
-					break;
-
-				case ACPI_DESC_TYPE_OPERAND:
-					acpi_db_decode_internal_object (obj_desc->reference.object);
-					break;
-
-				default:
-					break;
-				}
-				break;
-
-
-			default:
-
-				acpi_os_printf ("Unknown Reference opcode %X\n",
-					obj_desc->reference.opcode);
-				break;
-			}
-			break;
-
-		default:
-
-			acpi_os_printf ("<Obj> ");
-			acpi_os_printf ("         ");
-			acpi_db_decode_internal_object (obj_desc);
-			break;
-		}
-		break;
-
-
-	default:
-
-		acpi_os_printf ("<Not a valid ACPI Object Descriptor> ");
-		break;
-	}
-
-	acpi_os_printf ("\n");
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_method_info
- *
- * PARAMETERS:  Start_op        - Root of the control method parse tree
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display information about the current method
- *
- ******************************************************************************/
-
-void
-acpi_db_display_method_info (
-	acpi_parse_object       *start_op)
-{
-	acpi_walk_state         *walk_state;
-	acpi_operand_object     *obj_desc;
-	acpi_namespace_node     *node;
-	acpi_parse_object       *root_op;
-	acpi_parse_object       *op;
-	const acpi_opcode_info  *op_info;
-	u32                     num_ops = 0;
-	u32                     num_operands = 0;
-	u32                     num_operators = 0;
-	u32                     num_remaining_ops = 0;
-	u32                     num_remaining_operands = 0;
-	u32                     num_remaining_operators = 0;
-	u32                     num_args;
-	u32                     concurrency;
-	u8                      count_remaining = FALSE;
-
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	obj_desc = walk_state->method_desc;
-	node    = walk_state->method_node;
-
-	num_args    = obj_desc->method.param_count;
-	concurrency = obj_desc->method.concurrency;
-
-	acpi_os_printf ("Currently executing control method is [%4.4s]\n", node->name.ascii);
-	acpi_os_printf ("%X arguments, max concurrency = %X\n", num_args, concurrency);
-
-
-	root_op = start_op;
-	while (root_op->common.parent) {
-		root_op = root_op->common.parent;
-	}
-
-	op = root_op;
-
-	while (op) {
-		if (op == start_op) {
-			count_remaining = TRUE;
-		}
-
-		num_ops++;
-		if (count_remaining) {
-			num_remaining_ops++;
-		}
-
-		/* Decode the opcode */
-
-		op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
-		switch (op_info->class) {
-		case AML_CLASS_ARGUMENT:
-			if (count_remaining) {
-				num_remaining_operands++;
-			}
-
-			num_operands++;
-			break;
-
-		case AML_CLASS_UNKNOWN:
-			/* Bad opcode or ASCII character */
-
-			continue;
-
-		default:
-			if (count_remaining) {
-				num_remaining_operators++;
-			}
-
-			num_operators++;
-			break;
-		}
-
-		op = acpi_ps_get_depth_next (start_op, op);
-	}
-
-	acpi_os_printf ("Method contains:     %X AML Opcodes - %X Operators, %X Operands\n",
-			 num_ops, num_operators, num_operands);
-
-	acpi_os_printf ("Remaining to execute: %X AML Opcodes - %X Operators, %X Operands\n",
-			 num_remaining_ops, num_remaining_operators, num_remaining_operands);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_locals
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display all locals for the currently running control method
- *
- ******************************************************************************/
-
-void
-acpi_db_display_locals (void)
-{
-	u32                     i;
-	acpi_walk_state         *walk_state;
-	acpi_operand_object     *obj_desc;
-	acpi_namespace_node     *node;
-
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	obj_desc = walk_state->method_desc;
-	node = walk_state->method_node;
-	acpi_os_printf ("Local Variables for method [%4.4s]:\n", node->name.ascii);
-
-	for (i = 0; i < MTH_NUM_LOCALS; i++) {
-		obj_desc = walk_state->local_variables[i].object;
-		acpi_os_printf ("Local%d: ", i);
-		acpi_db_display_internal_object (obj_desc, walk_state);
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_arguments
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display all arguments for the currently running control method
- *
- ******************************************************************************/
-
-void
-acpi_db_display_arguments (void)
-{
-	u32                     i;
-	acpi_walk_state         *walk_state;
-	acpi_operand_object     *obj_desc;
-	u32                     num_args;
-	u32                     concurrency;
-	acpi_namespace_node     *node;
-
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	obj_desc = walk_state->method_desc;
-	node    = walk_state->method_node;
-
-	num_args    = obj_desc->method.param_count;
-	concurrency = obj_desc->method.concurrency;
-
-	acpi_os_printf ("Method [%4.4s] has %X arguments, max concurrency = %X\n",
-			node->name.ascii, num_args, concurrency);
-
-	for (i = 0; i < num_args; i++) {
-		obj_desc = walk_state->arguments[i].object;
-		acpi_os_printf ("Arg%d: ", i);
-		acpi_db_display_internal_object (obj_desc, walk_state);
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_results
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display current contents of a method result stack
- *
- ******************************************************************************/
-
-void
-acpi_db_display_results (void)
-{
-	u32                     i;
-	acpi_walk_state         *walk_state;
-	acpi_operand_object     *obj_desc;
-	u32                     num_results = 0;
-	acpi_namespace_node     *node;
-
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	obj_desc = walk_state->method_desc;
-	node = walk_state->method_node;
-
-	if (walk_state->results) {
-		num_results = walk_state->results->results.num_results;
-	}
-
-	acpi_os_printf ("Method [%4.4s] has %X stacked result objects\n",
-		node->name.ascii, num_results);
-
-	for (i = 0; i < num_results; i++) {
-		obj_desc = walk_state->results->results.obj_desc[i];
-		acpi_os_printf ("Result%d: ", i);
-		acpi_db_display_internal_object (obj_desc, walk_state);
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_calling_tree
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display current calling tree of nested control methods
- *
- ******************************************************************************/
-
-void
-acpi_db_display_calling_tree (void)
-{
-	acpi_walk_state         *walk_state;
-	acpi_namespace_node     *node;
-
-
-	walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
-	if (!walk_state) {
-		acpi_os_printf ("There is no method currently executing\n");
-		return;
-	}
-
-	node = walk_state->method_node;
-	acpi_os_printf ("Current Control Method Call Tree\n");
-
-	while (walk_state) {
-		node = walk_state->method_node;
-
-		acpi_os_printf ("  [%4.4s]\n", node->name.ascii);
-
-		walk_state = walk_state->next;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_result_object
- *
- * PARAMETERS:  Obj_desc        - Object to be displayed
- *              Walk_state      - Current walk state
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display the result of an AML opcode
- *
- * Note: Curently only displays the result object if we are single stepping.
- * However, this output may be useful in other contexts and could be enabled
- * to do so if needed.
- *
- ******************************************************************************/
-
-void
-acpi_db_display_result_object (
-	acpi_operand_object     *obj_desc,
-	acpi_walk_state         *walk_state)
-{
-
-	/* Only display if single stepping */
-
-	if (!acpi_gbl_cm_single_step) {
-		return;
-	}
-
-	acpi_os_printf ("Result_obj: ");
-	acpi_db_display_internal_object (obj_desc, walk_state);
-	acpi_os_printf ("\n");
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_argument_object
- *
- * PARAMETERS:  Obj_desc        - Object to be displayed
- *              Walk_state      - Current walk state
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display the result of an AML opcode
- *
- ******************************************************************************/
-
-void
-acpi_db_display_argument_object (
-	acpi_operand_object     *obj_desc,
-	acpi_walk_state         *walk_state)
-{
-
-	if (!acpi_gbl_cm_single_step) {
-		return;
-	}
-
-	acpi_os_printf ("Arg_obj: ");
-	acpi_db_display_internal_object (obj_desc, walk_state);
-}
-
-#endif /* ACPI_DEBUGGER */
-
diff -Nru a/drivers/acpi/debugger/dbexec.c b/drivers/acpi/debugger/dbexec.c
--- a/drivers/acpi/debugger/dbexec.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,405 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbexec - debugger control method execution
- *              $Revision: 44 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acdebug.h"
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbexec")
-
-
-static acpi_db_method_info  acpi_gbl_db_method_info;
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_execute_method
- *
- * PARAMETERS:  Info            - Valid info segment
- *              Return_obj      - Where to put return object
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Execute a control method.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_execute_method (
-	acpi_db_method_info     *info,
-	acpi_buffer             *return_obj)
-{
-	acpi_status             status;
-	acpi_object_list        param_objects;
-	acpi_object             params[MTH_NUM_ARGS];
-	u32                     i;
-
-
-	if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
-		acpi_os_printf ("Warning: debug output is not enabled!\n");
-	}
-
-	/* Are there arguments to the method? */
-
-	if (info->args && info->args[0]) {
-		for (i = 0; info->args[i] && i < MTH_NUM_ARGS; i++) {
-			params[i].type              = ACPI_TYPE_INTEGER;
-			params[i].integer.value     = ACPI_STRTOUL (info->args[i], NULL, 16);
-		}
-
-		param_objects.pointer       = params;
-		param_objects.count         = i;
-	}
-	else {
-		/* Setup default parameters */
-
-		params[0].type              = ACPI_TYPE_INTEGER;
-		params[0].integer.value     = 0x01020304;
-
-		params[1].type              = ACPI_TYPE_STRING;
-		params[1].string.length     = 12;
-		params[1].string.pointer    = "AML Debugger";
-
-		param_objects.pointer       = params;
-		param_objects.count         = 2;
-	}
-
-	/* Prepare for a return object of arbitrary size */
-
-	return_obj->pointer          = acpi_gbl_db_buffer;
-	return_obj->length           = ACPI_DEBUG_BUFFER_SIZE;
-
-	/* Do the actual method execution */
-
-	status = acpi_evaluate_object (NULL, info->pathname, &param_objects, return_obj);
-
-	acpi_gbl_cm_single_step = FALSE;
-	acpi_gbl_method_executing = FALSE;
-
-	return (status);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_execute_setup
- *
- * PARAMETERS:  Info            - Valid method info
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Setup info segment prior to method execution
- *
- ******************************************************************************/
-
-void
-acpi_db_execute_setup (
-	acpi_db_method_info     *info)
-{
-
-	/* Catenate the current scope to the supplied name */
-
-	info->pathname[0] = 0;
-	if ((info->name[0] != '\\') &&
-		(info->name[0] != '/')) {
-		ACPI_STRCAT (info->pathname, acpi_gbl_db_scope_buf);
-	}
-
-	ACPI_STRCAT (info->pathname, info->name);
-	acpi_db_prep_namestring (info->pathname);
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-	acpi_os_printf ("Executing %s\n", info->pathname);
-
-	if (info->flags & EX_SINGLE_STEP) {
-		acpi_gbl_cm_single_step = TRUE;
-		acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-	}
-
-	else {
-		/* No single step, allow redirection to a file */
-
-		acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_get_outstanding_allocations
- *
- * PARAMETERS:  None
- *
- * RETURN:      Current global allocation count minus cache entries
- *
- * DESCRIPTION: Determine the current number of "outstanding" allocations --
- *              those allocations that have not been freed and also are not
- *              in one of the various object caches.
- *
- ******************************************************************************/
-
-u32
-acpi_db_get_outstanding_allocations (
-	void)
-{
-	u32                     outstanding = 0;
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-	u32                     i;
-
-
-	for (i = ACPI_MEM_LIST_FIRST_CACHE_LIST; i < ACPI_NUM_MEM_LISTS; i++) {
-		outstanding += (acpi_gbl_memory_lists[i].total_allocated -
-				  acpi_gbl_memory_lists[i].total_freed -
-				  acpi_gbl_memory_lists[i].cache_depth);
-	}
-#endif
-
-	return (outstanding);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_execute
- *
- * PARAMETERS:  Name                - Name of method to execute
- *              Args                - Parameters to the method
- *              Flags               - single step/no single step
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Execute a control method.  Name is relative to the current
- *              scope.
- *
- ******************************************************************************/
-
-void
-acpi_db_execute (
-	NATIVE_CHAR             *name,
-	NATIVE_CHAR             **args,
-	u32                     flags)
-{
-	acpi_status             status;
-	acpi_buffer             return_obj;
-
-
-#ifdef ACPI_DEBUG_OUTPUT
-	u32                     previous_allocations;
-	u32                     allocations;
-
-
-	/* Memory allocation tracking */
-
-	previous_allocations = acpi_db_get_outstanding_allocations ();
-#endif
-
-	acpi_gbl_db_method_info.name = name;
-	acpi_gbl_db_method_info.args = args;
-	acpi_gbl_db_method_info.flags = flags;
-
-	return_obj.pointer = NULL;
-	return_obj.length = ACPI_ALLOCATE_BUFFER;
-
-	acpi_db_execute_setup (&acpi_gbl_db_method_info);
-	status = acpi_db_execute_method (&acpi_gbl_db_method_info, &return_obj);
-
-	/*
-	 * Allow any handlers in separate threads to complete.
-	 * (Such as Notify handlers invoked from AML executed above).
-	 */
-	acpi_os_sleep (0, 10);
-
-
-#ifdef ACPI_DEBUG_OUTPUT
-
-	/* Memory allocation tracking */
-
-	allocations = acpi_db_get_outstanding_allocations () - previous_allocations;
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-
-	if (allocations > 0) {
-		acpi_os_printf ("Outstanding: %ld allocations after execution\n",
-				  allocations);
-	}
-#endif
-
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Execution of %s failed with status %s\n",
-			acpi_gbl_db_method_info.pathname, acpi_format_exception (status));
-	}
-
-	else {
-		/* Display a return object, if any */
-
-		if (return_obj.length) {
-			acpi_os_printf ("Execution of %s returned object %p Buflen %X\n",
-				acpi_gbl_db_method_info.pathname, return_obj.pointer, return_obj.length);
-			acpi_db_dump_object (return_obj.pointer, 1);
-		}
-		else {
-			acpi_os_printf ("No return object from execution of %s\n",
-				acpi_gbl_db_method_info.pathname);
-		}
-	}
-
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_method_thread
- *
- * PARAMETERS:  Context             - Execution info segment
- *
- * RETURN:      None
- *
- * DESCRIPTION: Debugger execute thread.  Waits for a command line, then
- *              simply dispatches it.
- *
- ******************************************************************************/
-
-void ACPI_SYSTEM_XFACE
-acpi_db_method_thread (
-	void                    *context)
-{
-	acpi_status             status;
-	acpi_db_method_info     *info = context;
-	u32                     i;
-	acpi_buffer             return_obj;
-
-
-	for (i = 0; i < info->num_loops; i++) {
-		status = acpi_db_execute_method (info, &return_obj);
-		if (ACPI_SUCCESS (status)) {
-			if (return_obj.length) {
-				acpi_os_printf ("Execution of %s returned object %p Buflen %X\n",
-					info->pathname, return_obj.pointer, return_obj.length);
-				acpi_db_dump_object (return_obj.pointer, 1);
-			}
-		}
-	}
-
-	/* Signal our completion */
-
-	status = acpi_os_signal_semaphore (info->thread_gate, 1);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not signal debugger semaphore\n");
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_create_execution_threads
- *
- * PARAMETERS:  Num_threads_arg         - Number of threads to create
- *              Num_loops_arg           - Loop count for the thread(s)
- *              Method_name_arg         - Control method to execute
- *
- * RETURN:      None
- *
- * DESCRIPTION: Create threads to execute method(s)
- *
- ******************************************************************************/
-
-void
-acpi_db_create_execution_threads (
-	NATIVE_CHAR             *num_threads_arg,
-	NATIVE_CHAR             *num_loops_arg,
-	NATIVE_CHAR             *method_name_arg)
-{
-	acpi_status             status;
-	u32                     num_threads;
-	u32                     num_loops;
-	u32                     i;
-	acpi_handle             thread_gate;
-
-
-	/* Get the arguments */
-
-	num_threads = ACPI_STRTOUL (num_threads_arg, NULL, 0);
-	num_loops  = ACPI_STRTOUL (num_loops_arg, NULL, 0);
-
-	if (!num_threads || !num_loops) {
-		acpi_os_printf ("Bad argument: Threads %X, Loops %X\n", num_threads, num_loops);
-		return;
-	}
-
-	/* Create the synchronization semaphore */
-
-	status = acpi_os_create_semaphore (1, 0, &thread_gate);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not create semaphore, %s\n", acpi_format_exception (status));
-		return;
-	}
-
-	/* Setup the context to be passed to each thread */
-
-	acpi_gbl_db_method_info.name = method_name_arg;
-	acpi_gbl_db_method_info.args = NULL;
-	acpi_gbl_db_method_info.flags = 0;
-	acpi_gbl_db_method_info.num_loops = num_loops;
-	acpi_gbl_db_method_info.thread_gate = thread_gate;
-
-	acpi_db_execute_setup (&acpi_gbl_db_method_info);
-
-	/* Create the threads */
-
-	acpi_os_printf ("Creating %X threads to execute %X times each\n", num_threads, num_loops);
-
-	for (i = 0; i < (num_threads); i++) {
-		status = acpi_os_queue_for_execution (OSD_PRIORITY_MED, acpi_db_method_thread, &acpi_gbl_db_method_info);
-		if (ACPI_FAILURE (status)) {
-			break;
-		}
-	}
-
-	/* Wait for all threads to complete */
-
-	i = num_threads;
-	while (i)   /* Brain damage for OSD implementations that only support wait of 1 unit */ {
-		status = acpi_os_wait_semaphore (thread_gate, 1, WAIT_FOREVER);
-		i--;
-	}
-
-	/* Cleanup and exit */
-
-	(void) acpi_os_delete_semaphore (thread_gate);
-
-	acpi_db_set_output_destination (ACPI_DB_DUPLICATE_OUTPUT);
-	acpi_os_printf ("All threads (%X) have completed\n", num_threads);
-	acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-}
-
-
-#endif /* ACPI_DEBUGGER */
-
-
diff -Nru a/drivers/acpi/debugger/dbfileio.c b/drivers/acpi/debugger/dbfileio.c
--- a/drivers/acpi/debugger/dbfileio.c	Sun Sep 15 19:20:00 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,399 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbfileio - Debugger file I/O commands.  These can't usually
- *              be used when running the debugger in Ring 0 (Kernel mode)
- *              $Revision: 68 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acdebug.h"
-#include "acnamesp.h"
-#include "actables.h"
-
-#if (defined ACPI_DEBUGGER || defined ACPI_DISASSEMBLER)
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbfileio")
-
-
-/*
- * NOTE: this is here for lack of a better place.  It is used in all
- * flavors of the debugger, need LCD file
- */
-#ifdef ACPI_APPLICATION
-#include <stdio.h>
-FILE                        *acpi_gbl_debug_file = NULL;
-#endif
-
-
-acpi_table_header           *acpi_gbl_db_table_ptr = NULL;
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_match_argument
- *
- * PARAMETERS:  User_argument           - User command line
- *              Arguments               - Array of commands to match against
- *
- * RETURN:      Index into command array or ACPI_TYPE_NOT_FOUND if not found
- *
- * DESCRIPTION: Search command array for a command match
- *
- ******************************************************************************/
-
-acpi_object_type
-acpi_db_match_argument (
-	NATIVE_CHAR             *user_argument,
-	ARGUMENT_INFO           *arguments)
-{
-	u32                     i;
-
-
-	if (!user_argument || user_argument[0] == 0) {
-		return (ACPI_TYPE_NOT_FOUND);
-	}
-
-	for (i = 0; arguments[i].name; i++) {
-		if (ACPI_STRSTR (arguments[i].name, user_argument) == arguments[i].name) {
-			return (i);
-		}
-	}
-
-	/* Argument not recognized */
-
-	return (ACPI_TYPE_NOT_FOUND);
-}
-
-
-#ifdef ACPI_DEBUGGER
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_close_debug_file
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: If open, close the current debug output file
- *
- ******************************************************************************/
-
-void
-acpi_db_close_debug_file (
-	void)
-{
-
-#ifdef ACPI_APPLICATION
-
-	if (acpi_gbl_debug_file) {
-	   fclose (acpi_gbl_debug_file);
-	   acpi_gbl_debug_file = NULL;
-	   acpi_gbl_db_output_to_file = FALSE;
-	   acpi_os_printf ("Debug output file %s closed\n", acpi_gbl_db_debug_filename);
-	}
-#endif
-
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_open_debug_file
- *
- * PARAMETERS:  Name                - Filename to open
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Open a file where debug output will be directed.
- *
- ******************************************************************************/
-
-void
-acpi_db_open_debug_file (
-	NATIVE_CHAR             *name)
-{
-
-#ifdef ACPI_APPLICATION
-
-	acpi_db_close_debug_file ();
-	acpi_gbl_debug_file = fopen (name, "w+");
-	if (acpi_gbl_debug_file) {
-		acpi_os_printf ("Debug output file %s opened\n", name);
-		ACPI_STRCPY (acpi_gbl_db_debug_filename, name);
-		acpi_gbl_db_output_to_file = TRUE;
-	}
-	else {
-		acpi_os_printf ("Could not open debug file %s\n", name);
-	}
-
-#endif
-}
-#endif
-
-
-#ifdef ACPI_APPLICATION
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_load_table
- *
- * PARAMETERS:  fp              - File that contains table
- *              Table_ptr       - Return value, buffer with table
- *              Table_lenght    - Return value, length of table
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load the DSDT from the file pointer
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_db_load_table(
-	FILE                    *fp,
-	acpi_table_header       **table_ptr,
-	u32                     *table_length)
-{
-	acpi_table_header       table_header;
-	u8                      *aml_start;
-	u32                     aml_length;
-	u32                     actual;
-	acpi_status             status;
-
-
-	/* Read the table header */
-
-	if (fread (&table_header, 1, sizeof (table_header), fp) != sizeof (acpi_table_header)) {
-		acpi_os_printf ("Couldn't read the table header\n");
-		return (AE_BAD_SIGNATURE);
-	}
-
-
-	/* Validate the table header/length */
-
-	status = acpi_tb_validate_table_header (&table_header);
-	if ((ACPI_FAILURE (status)) ||
-		(table_header.length > 0x800000)) /* 8 Mbyte should be enough */ {
-		acpi_os_printf ("Table header is invalid!\n");
-		return (AE_ERROR);
-	}
-
-
-	/* We only support a limited number of table types */
-
-	if (ACPI_STRNCMP ((char *) table_header.signature, DSDT_SIG, 4) &&
-		ACPI_STRNCMP ((char *) table_header.signature, PSDT_SIG, 4) &&
-		ACPI_STRNCMP ((char *) table_header.signature, SSDT_SIG, 4)) {
-		acpi_os_printf ("Table signature is invalid\n");
-		ACPI_DUMP_BUFFER (&table_header, sizeof (acpi_table_header));
-		return (AE_ERROR);
-	}
-
-	/* Allocate a buffer for the table */
-
-	*table_length = table_header.length;
-	*table_ptr = acpi_os_allocate ((size_t) *table_length);
-	if (!*table_ptr) {
-		acpi_os_printf ("Could not allocate memory for ACPI table %4.4s (size=%X)\n",
-				 table_header.signature, table_header.length);
-		return (AE_NO_MEMORY);
-	}
-
-
-	aml_start = (u8 *) *table_ptr + sizeof (table_header);
-	aml_length = *table_length - sizeof (table_header);
-
-	/* Copy the header to the buffer */
-
-	ACPI_MEMCPY (*table_ptr, &table_header, sizeof (table_header));
-
-	/* Get the rest of the table */
-
-	actual = fread (aml_start, 1, (size_t) aml_length, fp);
-	if (actual == aml_length) {
-		return (AE_OK);
-	}
-
-	if (actual > 0) {
-		acpi_os_printf ("Warning - reading table, asked for %X got %X\n", aml_length, actual);
-		return (AE_OK);
-	}
-
-
-	acpi_os_printf ("Error - could not read the table file\n");
-	acpi_os_free (*table_ptr);
-	*table_ptr = NULL;
-	*table_length = 0;
-
-	return (AE_ERROR);
-}
-#endif
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Ae_local_load_table
- *
- * PARAMETERS:  Table_ptr       - pointer to a buffer containing the entire
- *                                table to be loaded
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This function is called to load a table from the caller's
- *              buffer.  The buffer must contain an entire ACPI Table including
- *              a valid header.  The header fields will be verified, and if it
- *              is determined that the table is invalid, the call will fail.
- *
- *              If the call fails an appropriate status will be returned.
- *
- ******************************************************************************/
-
-acpi_status
-ae_local_load_table (
-	acpi_table_header       *table_ptr)
-{
-	acpi_status             status;
-	acpi_table_desc         table_info;
-
-
-	ACPI_FUNCTION_TRACE ("Ae_local_load_table");
-
-	if (!table_ptr) {
-		return_ACPI_STATUS (AE_BAD_PARAMETER);
-	}
-
-	table_info.pointer = table_ptr;
-	status = acpi_tb_recognize_table (&table_info, ACPI_TABLE_SECONDARY);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
-	}
-
-	/* Install the new table into the local data structures */
-
-	status = acpi_tb_install_table (&table_info);
-	if (ACPI_FAILURE (status)) {
-		/* Free table allocated by Acpi_tb_get_table */
-
-		acpi_tb_delete_single_table (&table_info);
-		return_ACPI_STATUS (status);
-	}
-
-
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
-	status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node);
-	if (ACPI_FAILURE (status)) {
-		/* Uninstall table and free the buffer */
-
-		acpi_tb_delete_acpi_table (ACPI_TABLE_DSDT);
-		return_ACPI_STATUS (status);
-	}
-#endif
-
-	return_ACPI_STATUS (status);
-}
-
-
-#ifdef ACPI_APPLICATION
-acpi_status
-acpi_db_get_acpi_table (
-	NATIVE_CHAR             *filename)
-{
-	FILE                    *fp;
-	u32                     table_length;
-	acpi_status             status;
-
-	/* Open the file */
-
-	fp = fopen (filename, "rb");
-	if (!fp) {
-		acpi_os_printf ("Could not open file %s\n", filename);
-		return (AE_ERROR);
-	}
-
-
-	/* Get the entire file */
-
-	fprintf (stderr, "Loading Acpi table from file %s\n", filename);
-	status = acpi_db_load_table (fp, &acpi_gbl_db_table_ptr, &table_length);
-	fclose(fp);
-
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Couldn't get table from the file\n");
-		return (status);
-	}
-
-	return (AE_OK);
- }
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_load_acpi_table
- *
- * PARAMETERS:  Filname         - File where table is located
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load an ACPI table from a file
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_load_acpi_table (
-	NATIVE_CHAR             *filename) {
-#ifdef ACPI_APPLICATION
-	acpi_status             status;
-
-
-	status = acpi_db_get_acpi_table (filename);
-	if (ACPI_FAILURE (status)) {
-		return (status);
-	}
-
-   /* Attempt to recognize and install the table */
-
-	status = ae_local_load_table (acpi_gbl_db_table_ptr);
-	if (ACPI_FAILURE (status)) {
-		if (status == AE_ALREADY_EXISTS) {
-			acpi_os_printf ("Table %4.4s is already installed\n",
-					  acpi_gbl_db_table_ptr->signature);
-		}
-		else {
-			acpi_os_printf ("Could not install table, %s\n",
-					  acpi_format_exception (status));
-		}
-
-		return (status);
-	}
-
-	fprintf (stderr, "Acpi table [%4.4s] successfully installed and loaded\n",
-			  acpi_gbl_db_table_ptr->signature);
-
-	acpi_gbl_acpi_hardware_present = FALSE;
-
-#endif  /* ACPI_APPLICATION */
-	return (AE_OK);
-}
-
-
-#endif  /* ACPI_DEBUGGER */
-
diff -Nru a/drivers/acpi/debugger/dbhistry.c b/drivers/acpi/debugger/dbhistry.c
--- a/drivers/acpi/debugger/dbhistry.c	Sun Sep 15 19:19:56 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,189 +0,0 @@
-/******************************************************************************
- *
- * Module Name: dbhistry - debugger HISTORY command
- *              $Revision: 25 $
- *
- *****************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acdebug.h"
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbhistry")
-
-
-#define HI_NO_HISTORY       0
-#define HI_RECORD_HISTORY   1
-#define HISTORY_SIZE        20
-
-
-typedef struct history_info
-{
-	NATIVE_CHAR             command[80];
-	u32                     cmd_num;
-
-} HISTORY_INFO;
-
-
-static HISTORY_INFO         acpi_gbl_history_buffer[HISTORY_SIZE];
-static u16                  acpi_gbl_lo_history = 0;
-static u16                  acpi_gbl_num_history = 0;
-static u16                  acpi_gbl_next_history_index = 0;
-static u32                  acpi_gbl_next_cmd_num = 1;
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_add_to_history
- *
- * PARAMETERS:  Command_line    - Command to add
- *
- * RETURN:      None
- *
- * DESCRIPTION: Add a command line to the history buffer.
- *
- ******************************************************************************/
-
-void
-acpi_db_add_to_history (
-	NATIVE_CHAR             *command_line)
-{
-
-	/* Put command into the next available slot */
-
-	ACPI_STRCPY (acpi_gbl_history_buffer[acpi_gbl_next_history_index].command, command_line);
-
-	acpi_gbl_history_buffer[acpi_gbl_next_history_index].cmd_num = acpi_gbl_next_cmd_num;
-
-	/* Adjust indexes */
-
-	if ((acpi_gbl_num_history == HISTORY_SIZE) &&
-		(acpi_gbl_next_history_index == acpi_gbl_lo_history)) {
-		acpi_gbl_lo_history++;
-		if (acpi_gbl_lo_history >= HISTORY_SIZE) {
-			acpi_gbl_lo_history = 0;
-		}
-	}
-
-	acpi_gbl_next_history_index++;
-	if (acpi_gbl_next_history_index >= HISTORY_SIZE) {
-		acpi_gbl_next_history_index = 0;
-	}
-
-	acpi_gbl_next_cmd_num++;
-	if (acpi_gbl_num_history < HISTORY_SIZE) {
-		acpi_gbl_num_history++;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_history
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Display the contents of the history buffer
- *
- ******************************************************************************/
-
-void
-acpi_db_display_history (void)
-{
-	NATIVE_UINT             i;
-	u16                     history_index;
-
-
-	history_index = acpi_gbl_lo_history;
-
-	/* Dump entire history buffer */
-
-	for (i = 0; i < acpi_gbl_num_history; i++) {
-		acpi_os_printf ("%ld %s\n", acpi_gbl_history_buffer[history_index].cmd_num,
-				 acpi_gbl_history_buffer[history_index].command);
-
-		history_index++;
-		if (history_index >= HISTORY_SIZE) {
-			history_index = 0;
-		}
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_get_from_history
- *
- * PARAMETERS:  Command_num_arg         - String containing the number of the
- *                                        command to be retrieved
- *
- * RETURN:      None
- *
- * DESCRIPTION: Get a command from the history buffer
- *
- ******************************************************************************/
-
-NATIVE_CHAR *
-acpi_db_get_from_history (
-	NATIVE_CHAR             *command_num_arg)
-{
-	NATIVE_UINT             i;
-	u16                     history_index;
-	u32                     cmd_num;
-
-
-	if (command_num_arg == NULL) {
-		cmd_num = acpi_gbl_next_cmd_num - 1;
-	}
-
-	else {
-		cmd_num = ACPI_STRTOUL (command_num_arg, NULL, 0);
-	}
-
-	/* Search history buffer */
-
-	history_index = acpi_gbl_lo_history;
-	for (i = 0; i < acpi_gbl_num_history; i++) {
-		if (acpi_gbl_history_buffer[history_index].cmd_num == cmd_num) {
-			/* Found the commnad, return it */
-
-			return (acpi_gbl_history_buffer[history_index].command);
-		}
-
-
-		history_index++;
-		if (history_index >= HISTORY_SIZE) {
-			history_index = 0;
-		}
-	}
-
-	acpi_os_printf ("Invalid history number: %d\n", history_index);
-	return (NULL);
-}
-
-
-#endif /* ACPI_DEBUGGER */
-
diff -Nru a/drivers/acpi/debugger/dbinput.c b/drivers/acpi/debugger/dbinput.c
--- a/drivers/acpi/debugger/dbinput.c	Sun Sep 15 19:19:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,892 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbinput - user front-end to the AML debugger
- *              $Revision: 87 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acdebug.h"
-
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbinput")
-
-
-/*
- * Top-level debugger commands.
- *
- * This list of commands must match the string table below it
- */
-enum acpi_ex_debugger_commands
-{
-	CMD_NOT_FOUND = 0,
-	CMD_NULL,
-	CMD_ALLOCATIONS,
-	CMD_ARGS,
-	CMD_ARGUMENTS,
-	CMD_BREAKPOINT,
-	CMD_CALL,
-	CMD_CLOSE,
-	CMD_DEBUG,
-	CMD_DUMP,
-	CMD_ENABLEACPI,
-	CMD_EVENT,
-	CMD_EXECUTE,
-	CMD_EXIT,
-	CMD_FIND,
-	CMD_GO,
-	CMD_HELP,
-	CMD_HELP2,
-	CMD_HISTORY,
-	CMD_HISTORY_EXE,
-	CMD_HISTORY_LAST,
-	CMD_INFORMATION,
-	CMD_INTEGRITY,
-	CMD_INTO,
-	CMD_LEVEL,
-	CMD_LIST,
-	CMD_LOAD,
-	CMD_LOCALS,
-	CMD_LOCKS,
-	CMD_METHODS,
-	CMD_NAMESPACE,
-	CMD_NOTIFY,
-	CMD_OBJECT,
-	CMD_OPEN,
-	CMD_OWNER,
-	CMD_PREFIX,
-	CMD_QUIT,
-	CMD_REFERENCES,
-	CMD_RESOURCES,
-	CMD_RESULTS,
-	CMD_SET,
-	CMD_STATS,
-	CMD_STOP,
-	CMD_TABLES,
-	CMD_TERMINATE,
-	CMD_THREADS,
-	CMD_TREE,
-	CMD_UNLOAD
-};
-
-#define CMD_FIRST_VALID     2
-
-
-static const COMMAND_INFO       acpi_gbl_db_commands[] =
-{ {"<NOT FOUND>",  0},
-	{"<NULL>",       0},
-	{"ALLOCATIONS",  0},
-	{"ARGS",         0},
-	{"ARGUMENTS",    0},
-	{"BREAKPOINT",   1},
-	{"CALL",         0},
-	{"CLOSE",        0},
-	{"DEBUG",        1},
-	{"DUMP",         1},
-	{"ENABLEACPI",   0},
-	{"EVENT",        1},
-	{"EXECUTE",      1},
-	{"EXIT",         0},
-	{"FIND",         1},
-	{"GO",           0},
-	{"HELP",         0},
-	{"?",            0},
-	{"HISTORY",      0},
-	{"!",            1},
-	{"!!",           0},
-	{"INFORMATION",  0},
-	{"INTEGRITY",    0},
-	{"INTO",         0},
-	{"LEVEL",        0},
-	{"LIST",         0},
-	{"LOAD",         1},
-	{"LOCALS",       0},
-	{"LOCKS",        0},
-	{"METHODS",      0},
-	{"NAMESPACE",    0},
-	{"NOTIFY",       2},
-	{"OBJECT",       1},
-	{"OPEN",         1},
-	{"OWNER",        1},
-	{"PREFIX",       0},
-	{"QUIT",         0},
-	{"REFERENCES",   1},
-	{"RESOURCES",    1},
-	{"RESULTS",      0},
-	{"SET",          3},
-	{"STATS",        0},
-	{"STOP",         0},
-	{"TABLES",       0},
-	{"TERMINATE",    0},
-	{"THREADS",      3},
-	{"TREE",         0},
-	{"UNLOAD",       1},
-	{NULL,           0}
-};
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_help
- *
- * PARAMETERS:  Help_type       - Subcommand (optional)
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print a usage message.
- *
- ******************************************************************************/
-
-void
-acpi_db_display_help (
-	NATIVE_CHAR             *help_type)
-{
-
-
-	/* No parameter, just give the overview */
-
-	if (!help_type)
-	{
-		acpi_os_printf ("ACPI CA Debugger Commands\n\n");
-		acpi_os_printf ("The following classes of commands are available. Help is available for\n");
-		acpi_os_printf ("each class by entering \"Help <Class_name>\"\n\n");
-		acpi_os_printf ("  [GENERAL]       General-Purpose Commands\n");
-		acpi_os_printf ("  [NAMESPACE]     Namespace Access Commands\n");
-		acpi_os_printf ("  [METHOD]        Control Method Execution Commands\n");
-		acpi_os_printf ("  [FILE]          File I/O Commands\n");
-		return;
-
-	}
-
-	/*
-	 * Parameter is the command class
-	 *
-	 * The idea here is to keep each class of commands smaller than a screenful
-	 */
-	switch (help_type[0])
-	{
-	case 'G':
-		acpi_os_printf ("\nGeneral-Purpose Commands\n\n");
-		acpi_os_printf ("Allocations                       Display list of current memory allocations\n");
-		acpi_os_printf ("Dump <Address>|<Namepath>\n");
-		acpi_os_printf ("   [Byte|Word|Dword|Qword]        Display ACPI objects or memory\n");
-		acpi_os_printf ("Enable_acpi                       Enable ACPI (hardware) mode\n");
-		acpi_os_printf ("Help                              This help screen\n");
-		acpi_os_printf ("History                           Display command history buffer\n");
-		acpi_os_printf ("Level [<Debug_level>] [console]   Get/Set debug level for file or console\n");
-		acpi_os_printf ("Locks                             Current status of internal mutexes\n");
-		acpi_os_printf ("Quit or Exit                      Exit this command\n");
-		acpi_os_printf ("Stats [Allocations|Memory|Misc\n");
-		acpi_os_printf ("     |Objects|Tables]             Display namespace and memory statistics\n");
-		acpi_os_printf ("Tables                            Display info about loaded ACPI tables\n");
-		acpi_os_printf ("Unload <Table_sig> [Instance]     Unload an ACPI table\n");
-		acpi_os_printf ("! <Command_number>                Execute command from history buffer\n");
-		acpi_os_printf ("!!                                Execute last command again\n");
-		return;
-
-	case 'N':
-		acpi_os_printf ("\nNamespace Access Commands\n\n");
-		acpi_os_printf ("Debug <Namepath> [Arguments]      Single Step a control method\n");
-		acpi_os_printf ("Event <F|G> <Value>               Generate Acpi_event (Fixed/GPE)\n");
-		acpi_os_printf ("Execute <Namepath> [Arguments]    Execute control method\n");
-		acpi_os_printf ("Find <Name> (? is wildcard)       Find ACPI name(s) with wildcards\n");
-		acpi_os_printf ("Method                            Display list of loaded control methods\n");
-		acpi_os_printf ("Namespace [<Addr>|<Path>] [Depth] Display loaded namespace tree/subtree\n");
-		acpi_os_printf ("Notify <Name_path> <Value>        Send a notification\n");
-		acpi_os_printf ("Objects <Object_type>             Display all objects of the given type\n");
-		acpi_os_printf ("Owner <Owner_id> [Depth]          Display loaded namespace by object owner\n");
-		acpi_os_printf ("Prefix [<Name_path>]              Set or Get current execution prefix\n");
-		acpi_os_printf ("References <Addr>                 Find all references to object at addr\n");
-		acpi_os_printf ("Resources xxx                     Get and display resources\n");
-		acpi_os_printf ("Terminate                         Delete namespace and all internal objects\n");
-		acpi_os_printf ("Thread <Threads><Loops><Name_path> Spawn threads to execute method(s)\n");
-		return;
-
-	case 'M':
-		acpi_os_printf ("\nControl Method Execution Commands\n\n");
-		acpi_os_printf ("Arguments (or Args)               Display method arguments\n");
-		acpi_os_printf ("Breakpoint <Aml_offset>           Set an AML execution breakpoint\n");
-		acpi_os_printf ("Call                              Run to next control method invocation\n");
-		acpi_os_printf ("Go                                Allow method to run to completion\n");
-		acpi_os_printf ("Information                       Display info about the current method\n");
-		acpi_os_printf ("Into                              Step into (not over) a method call\n");
-		acpi_os_printf ("List [# of Aml Opcodes]           Display method ASL statements\n");
-		acpi_os_printf ("Locals                            Display method local variables\n");
-		acpi_os_printf ("Results                           Display method result stack\n");
-		acpi_os_printf ("Set <A|L> <#> <Value>             Set method data (Arguments/Locals)\n");
-		acpi_os_printf ("Stop                              Terminate control method\n");
-		acpi_os_printf ("Tree                              Display control method calling tree\n");
-		acpi_os_printf ("<Enter>                           Single step next AML opcode (over calls)\n");
-		return;
-
-	case 'F':
-		acpi_os_printf ("\nFile I/O Commands\n\n");
-		acpi_os_printf ("Close                             Close debug output file\n");
-		acpi_os_printf ("Open <Output Filename>            Open a file for debug output\n");
-		acpi_os_printf ("Load <Input Filename>             Load ACPI table from a file\n");
-		return;
-
-	default:
-		acpi_os_printf ("Unrecognized Command Class: %X\n", help_type);
-		return;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_get_next_token
- *
- * PARAMETERS:  String          - Command buffer
- *              Next            - Return value, end of next token
- *
- * RETURN:      Pointer to the start of the next token.
- *
- * DESCRIPTION: Command line parsing.  Get the next token on the command line
- *
- ******************************************************************************/
-
-NATIVE_CHAR *
-acpi_db_get_next_token (
-	NATIVE_CHAR             *string,
-	NATIVE_CHAR             **next)
-{
-	NATIVE_CHAR             *start;
-
-
-	/* At end of buffer? */
-
-	if (!string || !(*string))
-	{
-		return (NULL);
-	}
-
-	/* Get rid of any spaces at the beginning */
-
-	if (*string == ' ')
-	{
-		while (*string && (*string == ' '))
-		{
-			string++;
-		}
-
-		if (!(*string))
-		{
-			return (NULL);
-		}
-	}
-
-	start = string;
-
-	/* Find end of token */
-
-	while (*string && (*string != ' '))
-	{
-		string++;
-	}
-
-	if (!(*string))
-	{
-		*next = NULL;
-	}
-	else
-	{
-		*string = 0;
-		*next = string + 1;
-	}
-
-	return (start);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_get_line
- *
- * PARAMETERS:  Input_buffer        - Command line buffer
- *
- * RETURN:      None
- *
- * DESCRIPTION: Get the next command line from the user.  Gets entire line
- *              up to the next newline
- *
- ******************************************************************************/
-
-u32
-acpi_db_get_line (
-	NATIVE_CHAR             *input_buffer)
-{
-	u32                     i;
-	u32                     count;
-	NATIVE_CHAR             *next;
-	NATIVE_CHAR             *this;
-
-
-	ACPI_STRCPY (acpi_gbl_db_parsed_buf, input_buffer);
-	ACPI_STRUPR (acpi_gbl_db_parsed_buf);
-
-	this = acpi_gbl_db_parsed_buf;
-	for (i = 0; i < ACPI_DEBUGGER_MAX_ARGS; i++)
-	{
-		acpi_gbl_db_args[i] = acpi_db_get_next_token (this, &next);
-		if (!acpi_gbl_db_args[i])
-		{
-			break;
-		}
-
-		this = next;
-	}
-
-	/* Uppercase the actual command */
-
-	if (acpi_gbl_db_args[0])
-	{
-		ACPI_STRUPR (acpi_gbl_db_args[0]);
-	}
-
-	count = i;
-	if (count)
-	{
-		count--;  /* Number of args only */
-	}
-
-	return (count);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_match_command
- *
- * PARAMETERS:  User_command            - User command line
- *
- * RETURN:      Index into command array, -1 if not found
- *
- * DESCRIPTION: Search command array for a command match
- *
- ******************************************************************************/
-
-u32
-acpi_db_match_command (
-	NATIVE_CHAR             *user_command)
-{
-	u32                     i;
-
-
-	if (!user_command || user_command[0] == 0)
-	{
-		return (CMD_NULL);
-	}
-
-	for (i = CMD_FIRST_VALID; acpi_gbl_db_commands[i].name; i++)
-	{
-		if (ACPI_STRSTR (acpi_gbl_db_commands[i].name, user_command) ==
-				   acpi_gbl_db_commands[i].name)
-		{
-			return (i);
-		}
-	}
-
-	/* Command not recognized */
-
-	return (CMD_NOT_FOUND);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_command_dispatch
- *
- * PARAMETERS:  Input_buffer        - Command line buffer
- *              Walk_state          - Current walk
- *              Op                  - Current (executing) parse op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Command dispatcher.  Called from two places:
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_command_dispatch (
-	NATIVE_CHAR             *input_buffer,
-	acpi_walk_state         *walk_state,
-	acpi_parse_object       *op)
-{
-	u32                     temp;
-	u32                     command_index;
-	u32                     param_count;
-	NATIVE_CHAR             *command_line;
-	acpi_status             status = AE_CTRL_TRUE;
-
-
-	/* If Acpi_terminate has been called, terminate this thread */
-
-	if (acpi_gbl_db_terminate_threads)
-	{
-		return (AE_CTRL_TERMINATE);
-	}
-
-	param_count = acpi_db_get_line (input_buffer);
-	command_index = acpi_db_match_command (acpi_gbl_db_args[0]);
-	temp = 0;
-
-	/* Verify that we have the minimum number of params */
-
-	if (param_count < acpi_gbl_db_commands[command_index].min_args)
-	{
-		acpi_os_printf ("%d parameters entered, [%s] requires %d parameters\n",
-				  param_count, acpi_gbl_db_commands[command_index].name, acpi_gbl_db_commands[command_index].min_args);
-		return (AE_CTRL_TRUE);
-	}
-
-	/* Decode and dispatch the command */
-
-	switch (command_index)
-	{
-	case CMD_NULL:
-		if (op)
-		{
-			return (AE_OK);
-		}
-		break;
-
-	case CMD_ALLOCATIONS:
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-		acpi_ut_dump_allocations ((u32) -1, NULL);
-#endif
-		break;
-
-	case CMD_ARGS:
-	case CMD_ARGUMENTS:
-		acpi_db_display_arguments ();
-		break;
-
-	case CMD_BREAKPOINT:
-		acpi_db_set_method_breakpoint (acpi_gbl_db_args[1], walk_state, op);
-		break;
-
-	case CMD_CALL:
-		acpi_db_set_method_call_breakpoint (op);
-		status = AE_OK;
-		break;
-
-	case CMD_CLOSE:
-		acpi_db_close_debug_file ();
-		break;
-
-	case CMD_DEBUG:
-		acpi_db_execute (acpi_gbl_db_args[1], &acpi_gbl_db_args[2], EX_SINGLE_STEP);
-		break;
-
-	case CMD_DUMP:
-		acpi_db_decode_and_display_object (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
-		break;
-
-	case CMD_ENABLEACPI:
-		status = acpi_enable();
-		if (ACPI_FAILURE(status))
-		{
-			acpi_os_printf("Acpi_enable failed (Status=%X)\n", status);
-			return (status);
-		}
-		break;
-
-	case CMD_EVENT:
-		acpi_os_printf ("Event command not implemented\n");
-		break;
-
-	case CMD_EXECUTE:
-		acpi_db_execute (acpi_gbl_db_args[1], &acpi_gbl_db_args[2], EX_NO_SINGLE_STEP);
-		break;
-
-	case CMD_FIND:
-		status = acpi_db_find_name_in_namespace (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_GO:
-		acpi_gbl_cm_single_step = FALSE;
-		return (AE_OK);
-
-	case CMD_HELP:
-	case CMD_HELP2:
-		acpi_db_display_help (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_HISTORY:
-		acpi_db_display_history ();
-		break;
-
-	case CMD_HISTORY_EXE:
-		command_line = acpi_db_get_from_history (acpi_gbl_db_args[1]);
-		if (!command_line)
-		{
-			return (AE_CTRL_TRUE);
-		}
-
-		status = acpi_db_command_dispatch (command_line, walk_state, op);
-		if (ACPI_SUCCESS (status))
-		{
-			status = AE_CTRL_TRUE;
-		}
-		return (status);
-
-	case CMD_HISTORY_LAST:
-		command_line = acpi_db_get_from_history (NULL);
-		if (!command_line)
-		{
-			return (AE_CTRL_TRUE);
-		}
-
-		status = acpi_db_command_dispatch (command_line, walk_state, op);
-		if (ACPI_SUCCESS (status))
-		{
-			status = AE_CTRL_TRUE;
-		}
-		return (status);
-
-	case CMD_INFORMATION:
-		acpi_db_display_method_info (op);
-		break;
-
-	case CMD_INTEGRITY:
-		acpi_db_check_integrity ();
-		break;
-
-	case CMD_INTO:
-		if (op)
-		{
-			acpi_gbl_cm_single_step = TRUE;
-			return (AE_OK);
-		}
-		break;
-
-	case CMD_LEVEL:
-		if (param_count == 0)
-		{
-			acpi_os_printf ("Current debug level for file output is:  %8.8lX\n", acpi_gbl_db_debug_level);
-			acpi_os_printf ("Current debug level for console output is: %8.8lX\n", acpi_gbl_db_console_debug_level);
-		}
-		else if (param_count == 2)
-		{
-			temp = acpi_gbl_db_console_debug_level;
-			acpi_gbl_db_console_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16);
-			acpi_os_printf ("Debug Level for console output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_console_debug_level);
-		}
-		else
-		{
-			temp = acpi_gbl_db_debug_level;
-			acpi_gbl_db_debug_level = ACPI_STRTOUL (acpi_gbl_db_args[1], NULL, 16);
-			acpi_os_printf ("Debug Level for file output was %8.8lX, now %8.8lX\n", temp, acpi_gbl_db_debug_level);
-		}
-		break;
-
-	case CMD_LIST:
-		acpi_db_disassemble_aml (acpi_gbl_db_args[1], op);
-		break;
-
-	case CMD_LOAD:
-		status = acpi_db_load_acpi_table (acpi_gbl_db_args[1]);
-		if (ACPI_FAILURE (status))
-		{
-			return (status);
-		}
-		break;
-
-	case CMD_LOCKS:
-		acpi_db_display_locks ();
-		break;
-
-	case CMD_LOCALS:
-		acpi_db_display_locals ();
-		break;
-
-	case CMD_METHODS:
-		status = acpi_db_display_objects ("METHOD", acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_NAMESPACE:
-		acpi_db_dump_namespace (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
-		break;
-
-	case CMD_NOTIFY:
-		temp = ACPI_STRTOUL (acpi_gbl_db_args[2], NULL, 0);
-		acpi_db_send_notify (acpi_gbl_db_args[1], temp);
-		break;
-
-	case CMD_OBJECT:
-		ACPI_STRUPR (acpi_gbl_db_args[1]);
-		status = acpi_db_display_objects (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
-		break;
-
-	case CMD_OPEN:
-		acpi_db_open_debug_file (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_OWNER:
-		acpi_db_dump_namespace_by_owner (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
-		break;
-
-	case CMD_PREFIX:
-		acpi_db_set_scope (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_REFERENCES:
-		acpi_db_find_references (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_RESOURCES:
-		acpi_db_display_resources (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_RESULTS:
-		acpi_db_display_results ();
-		break;
-
-	case CMD_SET:
-		acpi_db_set_method_data (acpi_gbl_db_args[1], acpi_gbl_db_args[2], acpi_gbl_db_args[3]);
-		break;
-
-	case CMD_STATS:
-		status = acpi_db_display_statistics (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_STOP:
-		return (AE_NOT_IMPLEMENTED);
-
-	case CMD_TABLES:
-		acpi_db_display_table_info (acpi_gbl_db_args[1]);
-		break;
-
-	case CMD_TERMINATE:
-		acpi_db_set_output_destination (ACPI_DB_REDIRECTABLE_OUTPUT);
-		acpi_ut_subsystem_shutdown ();
-
-		/* TBD: [Restructure] Need some way to re-initialize without re-creating the semaphores! */
-
-		/*  Acpi_initialize (NULL); */
-		break;
-
-	case CMD_THREADS:
-		acpi_db_create_execution_threads (acpi_gbl_db_args[1], acpi_gbl_db_args[2], acpi_gbl_db_args[3]);
-		break;
-
-	case CMD_TREE:
-		acpi_db_display_calling_tree ();
-		break;
-
-	case CMD_UNLOAD:
-		acpi_db_unload_acpi_table (acpi_gbl_db_args[1], acpi_gbl_db_args[2]);
-		break;
-
-	case CMD_EXIT:
-	case CMD_QUIT:
-		if (op)
-		{
-			acpi_os_printf ("Method execution terminated\n");
-			return (AE_CTRL_TERMINATE);
-		}
-
-		if (!acpi_gbl_db_output_to_file)
-		{
-			acpi_dbg_level = DEBUG_DEFAULT;
-		}
-
-		/* Shutdown */
-
-		/* Acpi_ut_subsystem_shutdown (); */
-		acpi_db_close_debug_file ();
-
-		acpi_gbl_db_terminate_threads = TRUE;
-
-		return (AE_CTRL_TERMINATE);
-
-	case CMD_NOT_FOUND:
-	default:
-		acpi_os_printf ("Unknown Command\n");
-		return (AE_CTRL_TRUE);
-	}
-
-
-	/* Add all commands that come here to the history buffer */
-
-	acpi_db_add_to_history (input_buffer);
-	return (status);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_execute_thread
- *
- * PARAMETERS:  Context         - Not used
- *
- * RETURN:      None
- *
- * DESCRIPTION: Debugger execute thread.  Waits for a command line, then
- *              simply dispatches it.
- *
- ******************************************************************************/
-
-void ACPI_SYSTEM_XFACE
-acpi_db_execute_thread (
-	void                    *context)
-{
-	acpi_status             status = AE_OK;
-	acpi_status             Mstatus;
-
-
-	while (status != AE_CTRL_TERMINATE)
-	{
-		acpi_gbl_method_executing = FALSE;
-		acpi_gbl_step_to_next_call = FALSE;
-
-		Mstatus = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
-		if (ACPI_FAILURE (Mstatus))
-		{
-			return;
-		}
-
-		status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL);
-
-		Mstatus = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
-		if (ACPI_FAILURE (Mstatus))
-		{
-			return;
-		}
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_single_thread
- *
- * PARAMETERS:  None
- *
- * RETURN:      None
- *
- * DESCRIPTION: Debugger execute thread.  Waits for a command line, then
- *              simply dispatches it.
- *
- ******************************************************************************/
-
-void
-acpi_db_single_thread (
-	void)
-{
-
-	acpi_gbl_method_executing = FALSE;
-	acpi_gbl_step_to_next_call = FALSE;
-
-	(void) acpi_db_command_dispatch (acpi_gbl_db_line_buf, NULL, NULL);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_user_commands
- *
- * PARAMETERS:  Prompt              - User prompt (depends on mode)
- *              Op                  - Current executing parse op
- *
- * RETURN:      None
- *
- * DESCRIPTION: Command line execution for the AML debugger.  Commands are
- *              matched and dispatched here.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_user_commands (
-	NATIVE_CHAR             prompt,
-	acpi_parse_object       *op)
-{
-	acpi_status             status = AE_OK;
-
-
-	/* TBD: [Restructure] Need a separate command line buffer for step mode */
-
-	while (!acpi_gbl_db_terminate_threads)
-	{
-		/* Force output to console until a command is entered */
-
-		acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-
-		/* Different prompt if method is executing */
-
-		if (!acpi_gbl_method_executing)
-		{
-			acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-		}
-		else
-		{
-			acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
-		}
-
-		/* Get the user input line */
-
-		(void) acpi_os_get_line (acpi_gbl_db_line_buf);
-
-		/* Check for single or multithreaded debug */
-
-		if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED)
-		{
-			/*
-			 * Signal the debug thread that we have a command to execute,
-			 * and wait for the command to complete.
-			 */
-			status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_READY);
-			if (ACPI_FAILURE (status))
-			{
-				return (status);
-			}
-
-			status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
-			if (ACPI_FAILURE (status))
-			{
-				return (status);
-			}
-		}
-		else
-		{
-			/* Just call to the command line interpreter */
-
-			acpi_db_single_thread ();
-		}
-	}
-
-	/*
-	 * Only this thread (the original thread) should actually terminate the subsystem,
-	 * because all the semaphores are deleted during termination
-	 */
-	status = acpi_terminate ();
-	return (status);
-}
-
-
-#endif  /* ACPI_DEBUGGER */
-
diff -Nru a/drivers/acpi/debugger/dbstats.c b/drivers/acpi/debugger/dbstats.c
--- a/drivers/acpi/debugger/dbstats.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,459 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbstats - Generation and display of ACPI table statistics
- *              $Revision: 61 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include <acpi.h>
-#include <acdebug.h>
-#include <acnamesp.h>
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbstats")
-
-/*
- * Statistics subcommands
- */
-static ARGUMENT_INFO        acpi_db_stat_types [] =
-{ {"ALLOCATIONS"},
-	{"OBJECTS"},
-	{"MEMORY"},
-	{"MISC"},
-	{"TABLES"},
-	{"SIZES"},
-	{"STACK"},
-	{NULL}           /* Must be null terminated */
-};
-
-#define CMD_STAT_ALLOCATIONS     0
-#define CMD_STAT_OBJECTS         1
-#define CMD_STAT_MEMORY          2
-#define CMD_STAT_MISC            3
-#define CMD_STAT_TABLES          4
-#define CMD_STAT_SIZES           5
-#define CMD_STAT_STACK           6
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_enumerate_object
- *
- * PARAMETERS:  Obj_desc            - Object to be counted
- *
- * RETURN:      None
- *
- * DESCRIPTION: Add this object to the global counts, by object type.
- *              Limited recursion handles subobjects and packages, and this
- *              is probably acceptable within the AML debugger only.
- *
- ******************************************************************************/
-
-void
-acpi_db_enumerate_object (
-	acpi_operand_object     *obj_desc)
-{
-	u32                     i;
-
-
-	if (!obj_desc)
-	{
-		return;
-	}
-
-
-	/* Enumerate this object first */
-
-	acpi_gbl_num_objects++;
-
-	if (ACPI_GET_OBJECT_TYPE (obj_desc) > INTERNAL_TYPE_NODE_MAX)
-	{
-		acpi_gbl_obj_type_count_misc++;
-	}
-	else
-	{
-		acpi_gbl_obj_type_count [ACPI_GET_OBJECT_TYPE (obj_desc)]++;
-	}
-
-	/* Count the sub-objects */
-
-	switch (ACPI_GET_OBJECT_TYPE (obj_desc))
-	{
-	case ACPI_TYPE_PACKAGE:
-		for (i = 0; i < obj_desc->package.count; i++)
-		{
-			acpi_db_enumerate_object (obj_desc->package.elements[i]);
-		}
-		break;
-
-	case ACPI_TYPE_DEVICE:
-		acpi_db_enumerate_object (obj_desc->device.sys_handler);
-		acpi_db_enumerate_object (obj_desc->device.drv_handler);
-		acpi_db_enumerate_object (obj_desc->device.addr_handler);
-		break;
-
-	case ACPI_TYPE_BUFFER_FIELD:
-		if (acpi_ns_get_secondary_object (obj_desc))
-		{
-			acpi_gbl_obj_type_count [ACPI_TYPE_BUFFER_FIELD]++;
-		}
-		break;
-
-	case ACPI_TYPE_REGION:
-		acpi_gbl_obj_type_count [INTERNAL_TYPE_REGION_FIELD ]++;
-		acpi_db_enumerate_object (obj_desc->region.addr_handler);
-		break;
-
-	case ACPI_TYPE_POWER:
-		acpi_db_enumerate_object (obj_desc->power_resource.sys_handler);
-		acpi_db_enumerate_object (obj_desc->power_resource.drv_handler);
-		break;
-
-	case ACPI_TYPE_PROCESSOR:
-		acpi_db_enumerate_object (obj_desc->processor.sys_handler);
-		acpi_db_enumerate_object (obj_desc->processor.drv_handler);
-		acpi_db_enumerate_object (obj_desc->processor.addr_handler);
-		break;
-
-	case ACPI_TYPE_THERMAL:
-		acpi_db_enumerate_object (obj_desc->thermal_zone.sys_handler);
-		acpi_db_enumerate_object (obj_desc->thermal_zone.drv_handler);
-		acpi_db_enumerate_object (obj_desc->thermal_zone.addr_handler);
-		break;
-
-	default:
-		break;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_classify_one_object
- *
- * PARAMETERS:  Callback for Walk_namespace
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
- *              the parent namespace node.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_classify_one_object (
-	acpi_handle             obj_handle,
-	u32                     nesting_level,
-	void                    *context,
-	void                    **return_value)
-{
-	acpi_namespace_node     *node;
-	acpi_operand_object     *obj_desc;
-	u32                     type;
-
-
-	acpi_gbl_num_nodes++;
-
-	node = (acpi_namespace_node *) obj_handle;
-	obj_desc = acpi_ns_get_attached_object (node);
-
-	acpi_db_enumerate_object (obj_desc);
-
-	type = node->type;
-	if (type > INTERNAL_TYPE_NODE_MAX)
-	{
-		acpi_gbl_node_type_count_misc++;
-	}
-
-	else
-	{
-		acpi_gbl_node_type_count [type]++;
-	}
-
-	return AE_OK;
-
-
-	/* TBD: These need to be counted during the initial parsing phase */
-	/*
-	if (Acpi_ps_is_named_op (Op->Opcode))
-	{
-		Num_nodes++;
-	}
-
-	if (Is_method)
-	{
-		Num_method_elements++;
-	}
-
-	Num_grammar_elements++;
-	Op = Acpi_ps_get_depth_next (Root, Op);
-
-	Size_of_parse_tree          = (Num_grammar_elements - Num_method_elements) * (u32) sizeof (acpi_parse_object);
-	Size_of_method_trees        = Num_method_elements * (u32) sizeof (acpi_parse_object);
-	Size_of_node_entries        = Num_nodes * (u32) sizeof (acpi_namespace_node);
-	Size_of_acpi_objects        = Num_nodes * (u32) sizeof (acpi_operand_object);
-
-	*/
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_count_namespace_objects
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Count and classify the entire namespace, including all
- *              namespace nodes and attached objects.
- *
- ******************************************************************************/
-
-void
-acpi_db_count_namespace_objects (
-	void)
-{
-	u32                     i;
-
-
-	acpi_gbl_num_nodes = 0;
-	acpi_gbl_num_objects = 0;
-
-	acpi_gbl_obj_type_count_misc = 0;
-	for (i = 0; i < (INTERNAL_TYPE_NODE_MAX -1); i++)
-	{
-		acpi_gbl_obj_type_count [i] = 0;
-		acpi_gbl_node_type_count [i] = 0;
-	}
-
-	(void) acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			   FALSE, acpi_db_classify_one_object, NULL, NULL);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_display_statistics
- *
- * PARAMETERS:  Type_arg        - Subcommand
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Display various statistics
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_display_statistics (
-	NATIVE_CHAR             *type_arg)
-{
-	u32                     i;
-	u32                     type;
-	u32                     size;
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-	u32                     outstanding;
-#endif
-
-
-	if (!acpi_gbl_DSDT)
-	{
-		acpi_os_printf ("*** Warning: There is no DSDT loaded\n");
-	}
-
-	if (!type_arg)
-	{
-		acpi_os_printf ("The following subcommands are available:\n  ALLOCATIONS, OBJECTS, MEMORY, MISC, SIZES, TABLES\n");
-		return (AE_OK);
-	}
-
-	ACPI_STRUPR (type_arg);
-	type = acpi_db_match_argument (type_arg, acpi_db_stat_types);
-	if (type == (u32) -1)
-	{
-		acpi_os_printf ("Invalid or unsupported argument\n");
-		return (AE_OK);
-	}
-
-
-	switch (type)
-	{
-	case CMD_STAT_ALLOCATIONS:
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-		acpi_ut_dump_allocation_info ();
-#endif
-		break;
-
-	case CMD_STAT_TABLES:
-
-		acpi_os_printf ("ACPI Table Information:\n\n");
-		if (acpi_gbl_DSDT)
-		{
-			acpi_os_printf ("DSDT Length:................% 7ld (%X)\n", acpi_gbl_DSDT->length, acpi_gbl_DSDT->length);
-		}
-		break;
-
-	case CMD_STAT_OBJECTS:
-
-		acpi_db_count_namespace_objects ();
-
-		acpi_os_printf ("\nObjects defined in the current namespace:\n\n");
-
-		acpi_os_printf ("%16.16s % 10.10s % 10.10s\n", "ACPI_TYPE", "NODES", "OBJECTS");
-
-		for (i = 0; i < INTERNAL_TYPE_NODE_MAX; i++)
-		{
-			acpi_os_printf ("%16.16s % 10ld% 10ld\n", acpi_ut_get_type_name (i),
-				acpi_gbl_node_type_count [i], acpi_gbl_obj_type_count [i]);
-		}
-		acpi_os_printf ("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
-			acpi_gbl_node_type_count_misc, acpi_gbl_obj_type_count_misc);
-
-		acpi_os_printf ("%16.16s % 10ld% 10ld\n", "TOTALS:",
-			acpi_gbl_num_nodes, acpi_gbl_num_objects);
-		break;
-
-	case CMD_STAT_MEMORY:
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-		acpi_os_printf ("\n----Object and Cache Statistics---------------------------------------------\n");
-
-		for (i = 0; i < ACPI_NUM_MEM_LISTS; i++)
-		{
-			acpi_os_printf ("\n%s\n", acpi_gbl_memory_lists[i].list_name);
-
-			if (acpi_gbl_memory_lists[i].max_cache_depth > 0)
-			{
-				acpi_os_printf ("  Cache: [Depth Max Avail Size]         % 7d % 7d % 7d % 7d B\n",
-						acpi_gbl_memory_lists[i].cache_depth,
-						acpi_gbl_memory_lists[i].max_cache_depth,
-						acpi_gbl_memory_lists[i].max_cache_depth - acpi_gbl_memory_lists[i].cache_depth,
-						(acpi_gbl_memory_lists[i].cache_depth * acpi_gbl_memory_lists[i].object_size));
-
-				acpi_os_printf ("  Cache: [Requests Hits Misses Obj_size] % 7d % 7d % 7d % 7d B\n",
-						acpi_gbl_memory_lists[i].cache_requests,
-						acpi_gbl_memory_lists[i].cache_hits,
-						acpi_gbl_memory_lists[i].cache_requests - acpi_gbl_memory_lists[i].cache_hits,
-						acpi_gbl_memory_lists[i].object_size);
-			}
-
-			outstanding = acpi_gbl_memory_lists[i].total_allocated -
-					  acpi_gbl_memory_lists[i].total_freed -
-					  acpi_gbl_memory_lists[i].cache_depth;
-
-			if (acpi_gbl_memory_lists[i].object_size)
-			{
-				size = ACPI_ROUND_UP_TO_1K (outstanding * acpi_gbl_memory_lists[i].object_size);
-			}
-			else
-			{
-				size = ACPI_ROUND_UP_TO_1K (acpi_gbl_memory_lists[i].current_total_size);
-			}
-
-			acpi_os_printf ("  Mem:   [Alloc Free Outstanding Size]  % 7d % 7d % 7d % 7d Kb\n",
-					acpi_gbl_memory_lists[i].total_allocated,
-					acpi_gbl_memory_lists[i].total_freed,
-					outstanding, size);
-		}
-#endif
-
-		break;
-
-	case CMD_STAT_MISC:
-
-		acpi_os_printf ("\nMiscellaneous Statistics:\n\n");
-		acpi_os_printf ("Calls to Acpi_ps_find:.. ........% 7ld\n", acpi_gbl_ps_find_count);
-		acpi_os_printf ("Calls to Acpi_ns_lookup:..........% 7ld\n", acpi_gbl_ns_lookup_count);
-
-		acpi_os_printf ("\n");
-
-		acpi_os_printf ("Mutex usage:\n\n");
-		for (i = 0; i < NUM_MTX; i++)
-		{
-			acpi_os_printf ("%-28s:     % 7ld\n", acpi_ut_get_mutex_name (i), acpi_gbl_acpi_mutex_info[i].use_count);
-		}
-		break;
-
-
-	case CMD_STAT_SIZES:
-
-		acpi_os_printf ("\nInternal object sizes:\n\n");
-
-		acpi_os_printf ("Common         %3d\n", sizeof (ACPI_OBJECT_COMMON));
-		acpi_os_printf ("Number         %3d\n", sizeof (ACPI_OBJECT_INTEGER));
-		acpi_os_printf ("String         %3d\n", sizeof (ACPI_OBJECT_STRING));
-		acpi_os_printf ("Buffer         %3d\n", sizeof (ACPI_OBJECT_BUFFER));
-		acpi_os_printf ("Package        %3d\n", sizeof (ACPI_OBJECT_PACKAGE));
-		acpi_os_printf ("Buffer_field   %3d\n", sizeof (ACPI_OBJECT_BUFFER_FIELD));
-		acpi_os_printf ("Device         %3d\n", sizeof (ACPI_OBJECT_DEVICE));
-		acpi_os_printf ("Event          %3d\n", sizeof (ACPI_OBJECT_EVENT));
-		acpi_os_printf ("Method         %3d\n", sizeof (ACPI_OBJECT_METHOD));
-		acpi_os_printf ("Mutex          %3d\n", sizeof (ACPI_OBJECT_MUTEX));
-		acpi_os_printf ("Region         %3d\n", sizeof (ACPI_OBJECT_REGION));
-		acpi_os_printf ("Power_resource %3d\n", sizeof (ACPI_OBJECT_POWER_RESOURCE));
-		acpi_os_printf ("Processor      %3d\n", sizeof (ACPI_OBJECT_PROCESSOR));
-		acpi_os_printf ("Thermal_zone   %3d\n", sizeof (ACPI_OBJECT_THERMAL_ZONE));
-		acpi_os_printf ("Region_field   %3d\n", sizeof (ACPI_OBJECT_REGION_FIELD));
-		acpi_os_printf ("Bank_field     %3d\n", sizeof (ACPI_OBJECT_BANK_FIELD));
-		acpi_os_printf ("Index_field    %3d\n", sizeof (ACPI_OBJECT_INDEX_FIELD));
-		acpi_os_printf ("Reference      %3d\n", sizeof (ACPI_OBJECT_REFERENCE));
-		acpi_os_printf ("Notify_handler %3d\n", sizeof (ACPI_OBJECT_NOTIFY_HANDLER));
-		acpi_os_printf ("Addr_handler   %3d\n", sizeof (ACPI_OBJECT_ADDR_HANDLER));
-		acpi_os_printf ("Extra          %3d\n", sizeof (ACPI_OBJECT_EXTRA));
-		acpi_os_printf ("Data           %3d\n", sizeof (ACPI_OBJECT_DATA));
-
-		acpi_os_printf ("\n");
-
-		acpi_os_printf ("Parse_object   %3d\n", sizeof (ACPI_PARSE_OBJ_COMMON));
-		acpi_os_printf ("Parse_object_named %3d\n", sizeof (ACPI_PARSE_OBJ_NAMED));
-		acpi_os_printf ("Parse_object_asl %3d\n", sizeof (ACPI_PARSE_OBJ_ASL));
-		acpi_os_printf ("Operand_object %3d\n", sizeof (acpi_operand_object));
-		acpi_os_printf ("Namespace_node %3d\n", sizeof (acpi_namespace_node));
-
-		break;
-
-
-	case CMD_STAT_STACK:
-#if defined(ACPI_DEBUG_OUTPUT)
-
-		size = (u32) (acpi_gbl_entry_stack_pointer - acpi_gbl_lowest_stack_pointer);
-
-		acpi_os_printf ("\nSubsystem Stack Usage:\n\n");
-		acpi_os_printf ("Entry Stack Pointer        %X\n", acpi_gbl_entry_stack_pointer);
-		acpi_os_printf ("Lowest Stack Pointer       %X\n", acpi_gbl_lowest_stack_pointer);
-		acpi_os_printf ("Stack Use                  %X (%d)\n", size, size);
-		acpi_os_printf ("Deepest Procedure Nesting  %d\n", acpi_gbl_deepest_nesting);
-#endif
-		break;
-
-	default:
-		break;
-	}
-
-	acpi_os_printf ("\n");
-	return (AE_OK);
-}
-
-
-#endif /* ACPI_DEBUGGER  */
diff -Nru a/drivers/acpi/debugger/dbutils.c b/drivers/acpi/debugger/dbutils.c
--- a/drivers/acpi/debugger/dbutils.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,380 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbutils - AML debugger utilities
- *              $Revision: 56 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "acparser.h"
-#include "amlcode.h"
-#include "acnamesp.h"
-#include "acdebug.h"
-#include "acdispat.h"
-
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbutils")
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_set_output_destination
- *
- * PARAMETERS:  Output_flags        - Current flags word
- *
- * RETURN:      None
- *
- * DESCRIPTION: Set the current destination for debugger output.  Alos sets
- *              the debug output level accordingly.
- *
- ******************************************************************************/
-
-void
-acpi_db_set_output_destination (
-	u32                     output_flags)
-{
-
-	acpi_gbl_db_output_flags = (u8) output_flags;
-
-	if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) && acpi_gbl_db_output_to_file) {
-		acpi_dbg_level = acpi_gbl_db_debug_level;
-	}
-	else {
-		acpi_dbg_level = acpi_gbl_db_console_debug_level;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_dump_buffer
- *
- * PARAMETERS:  Address             - Pointer to the buffer
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print a portion of a buffer
- *
- ******************************************************************************/
-
-void
-acpi_db_dump_buffer (
-	u32                     address)
-{
-
-	acpi_os_printf ("\nLocation %X:\n", address);
-
-	acpi_dbg_level |= ACPI_LV_TABLES;
-	acpi_ut_dump_buffer (ACPI_TO_POINTER (address), 64, DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_dump_object
- *
- * PARAMETERS:  Obj_desc        - External ACPI object to dump
- *              Level           - Nesting level.
- *
- * RETURN:      None
- *
- * DESCRIPTION: Dump the contents of an ACPI external object
- *
- ******************************************************************************/
-
-void
-acpi_db_dump_object (
-	acpi_object             *obj_desc,
-	u32                     level)
-{
-	u32                     i;
-
-
-	if (!obj_desc) {
-		acpi_os_printf ("[Null Object]\n");
-		return;
-	}
-
-	for (i = 0; i < level; i++) {
-		acpi_os_printf (" ");
-	}
-
-	switch (obj_desc->type) {
-	case ACPI_TYPE_ANY:
-
-		acpi_os_printf ("[Object Reference] = %p\n", obj_desc->reference.handle);
-		break;
-
-
-	case ACPI_TYPE_INTEGER:
-
-		acpi_os_printf ("[Integer] = %8.8X%8.8X\n",
-				 ACPI_HIDWORD (obj_desc->integer.value),
-				 ACPI_LODWORD (obj_desc->integer.value));
-		break;
-
-
-	case ACPI_TYPE_STRING:
-
-		acpi_os_printf ("[String] Value: ");
-		for (i = 0; i < obj_desc->string.length; i++) {
-			acpi_os_printf ("%c", obj_desc->string.pointer[i]);
-		}
-		acpi_os_printf ("\n");
-		break;
-
-
-	case ACPI_TYPE_BUFFER:
-
-		acpi_os_printf ("[Buffer] Length %.2X = ", obj_desc->buffer.length);
-		acpi_ut_dump_buffer ((u8 *) obj_desc->buffer.pointer, obj_desc->buffer.length, DB_DWORD_DISPLAY, _COMPONENT);
-		break;
-
-
-	case ACPI_TYPE_PACKAGE:
-
-		acpi_os_printf ("[Package] Contains %d Elements: \n", obj_desc->package.count);
-
-		for (i = 0; i < obj_desc->package.count; i++) {
-			acpi_db_dump_object (&obj_desc->package.elements[i], level+1);
-		}
-		break;
-
-
-	case INTERNAL_TYPE_REFERENCE:
-
-		acpi_os_printf ("[Object Reference] = %p\n", obj_desc->reference.handle);
-		break;
-
-
-	case ACPI_TYPE_PROCESSOR:
-
-		acpi_os_printf ("[Processor]\n");
-		break;
-
-
-	case ACPI_TYPE_POWER:
-
-		acpi_os_printf ("[Power Resource]\n");
-		break;
-
-
-	default:
-
-		acpi_os_printf ("[Unknown Type] %X \n", obj_desc->type);
-		break;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_prep_namestring
- *
- * PARAMETERS:  Name            - String to prepare
- *
- * RETURN:      None
- *
- * DESCRIPTION: Translate all forward slashes and dots to backslashes.
- *
- ******************************************************************************/
-
-void
-acpi_db_prep_namestring (
-	NATIVE_CHAR             *name)
-{
-
-
-	if (!name) {
-		return;
-	}
-
-	ACPI_STRUPR (name);
-
-	/* Convert a leading forward slash to a backslash */
-
-	if (*name == '/') {
-		*name = '\\';
-	}
-
-	/* Ignore a leading backslash, this is the root prefix */
-
-	if (*name == '\\') {
-		name++;
-	}
-
-	/* Convert all slash path separators to dots */
-
-	while (*name) {
-		if ((*name == '/') ||
-			(*name == '\\')) {
-			*name = '.';
-		}
-
-		name++;
-	}
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_second_pass_parse
- *
- * PARAMETERS:  Root            - Root of the parse tree
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Second pass parse of the ACPI tables.  We need to wait until
- *              second pass to parse the control methods
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_second_pass_parse (
-	acpi_parse_object       *root)
-{
-	acpi_parse_object       *op = root;
-	acpi_parse_object       *method;
-	acpi_parse_object       *search_op;
-	acpi_parse_object       *start_op;
-	acpi_status             status = AE_OK;
-	u32                     base_aml_offset;
-	acpi_walk_state         *walk_state;
-
-
-	ACPI_FUNCTION_ENTRY ();
-
-
-	acpi_os_printf ("Pass two parse ....\n");
-
-	while (op) {
-		if (op->common.aml_opcode == AML_METHOD_OP) {
-			method = op;
-
-			/* Create a new walk state for the parse */
-
-			walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT,
-					   NULL, NULL, NULL);
-			if (!walk_state) {
-				return (AE_NO_MEMORY);
-			}
-
-			/* Init the Walk State */
-
-			walk_state->parser_state.aml        =
-			walk_state->parser_state.aml_start  = method->named.data;
-			walk_state->parser_state.aml_end    =
-			walk_state->parser_state.pkg_end    = method->named.data + method->named.length;
-			walk_state->parser_state.start_scope = op;
-
-			walk_state->descending_callback     = acpi_ds_load1_begin_op;
-			walk_state->ascending_callback      = acpi_ds_load1_end_op;
-
-			/* Perform the AML parse */
-
-			status = acpi_ps_parse_aml (walk_state);
-
-			base_aml_offset = (method->common.value.arg)->common.aml_offset + 1;
-			start_op = (method->common.value.arg)->common.next;
-			search_op = start_op;
-
-			while (search_op) {
-				search_op->common.aml_offset += base_aml_offset;
-				search_op = acpi_ps_get_depth_next (start_op, search_op);
-			}
-		}
-
-		if (op->common.aml_opcode == AML_REGION_OP) {
-			/* TBD: [Investigate] this isn't quite the right thing to do! */
-			/*
-			 *
-			 * Method = (ACPI_DEFERRED_OP *) Op;
-			 * Status = Acpi_ps_parse_aml (Op, Method->Body, Method->Body_length);
-			 */
-		}
-
-		if (ACPI_FAILURE (status)) {
-			break;
-		}
-
-		op = acpi_ps_get_depth_next (root, op);
-	}
-
-	return (status);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_local_ns_lookup
- *
- * PARAMETERS:  Name            - Name to lookup
- *
- * RETURN:      Pointer to a namespace node
- *
- * DESCRIPTION: Lookup a name in the ACPI namespace
- *
- * Note: Currently begins search from the root.  Could be enhanced to use
- * the current prefix (scope) node as the search beginning point.
- *
- ******************************************************************************/
-
-acpi_namespace_node *
-acpi_db_local_ns_lookup (
-	NATIVE_CHAR             *name)
-{
-	NATIVE_CHAR             *internal_path;
-	acpi_status             status;
-	acpi_namespace_node     *node = NULL;
-
-
-	acpi_db_prep_namestring (name);
-
-	/* Build an internal namestring */
-
-	status = acpi_ns_internalize_name (name, &internal_path);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Invalid namestring: %s\n", name);
-		return (NULL);
-	}
-
-	/*
-	 * Lookup the name.
-	 * (Uses root node as the search starting point)
-	 */
-	status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
-			   ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
-	if (ACPI_FAILURE (status)) {
-		acpi_os_printf ("Could not locate name: %s %s\n", name, acpi_format_exception (status));
-	}
-
-	ACPI_MEM_FREE (internal_path);
-	return (node);
-}
-
-
-#endif /* ACPI_DEBUGGER */
-
-
diff -Nru a/drivers/acpi/debugger/dbxface.c b/drivers/acpi/debugger/dbxface.c
--- a/drivers/acpi/debugger/dbxface.c	Sun Sep 15 19:20:12 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,388 +0,0 @@
-/*******************************************************************************
- *
- * Module Name: dbxface - AML Debugger external interfaces
- *              $Revision: 64 $
- *
- ******************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2002, R. Byron Moore
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-
-#include "acpi.h"
-#include "amlcode.h"
-#include "acdebug.h"
-#include "acdisasm.h"
-
-
-#ifdef ACPI_DEBUGGER
-
-#define _COMPONENT          ACPI_CA_DEBUGGER
-	 ACPI_MODULE_NAME    ("dbxface")
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_single_step
- *
- * PARAMETERS:  Walk_state      - Current walk
- *              Op              - Current executing op
- *              Opcode_class    - Class of the current AML Opcode
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Called just before execution of an AML opcode.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_single_step (
-	acpi_walk_state         *walk_state,
-	acpi_parse_object       *op,
-	u32                     opcode_class)
-{
-	acpi_parse_object       *next;
-	acpi_status             status = AE_OK;
-	u32                     original_debug_level;
-	acpi_parse_object       *display_op;
-	acpi_parse_object       *parent_op;
-
-
-	ACPI_FUNCTION_ENTRY ();
-
-	/* Check for single-step breakpoint */
-
-	if (walk_state->method_breakpoint &&
-	   (walk_state->method_breakpoint <= op->common.aml_offset)) {
-		/* Check if the breakpoint has been reached or passed */
-		/* Hit the breakpoint, resume single step, reset breakpoint */
-
-		acpi_os_printf ("***Break*** at AML offset %X\n", op->common.aml_offset);
-		acpi_gbl_cm_single_step = TRUE;
-		acpi_gbl_step_to_next_call = FALSE;
-		walk_state->method_breakpoint = 0;
-	}
-
-	/* Check for user breakpoint (Must be on exact Aml offset) */
-
-	else if (walk_state->user_breakpoint &&
-			(walk_state->user_breakpoint == op->common.aml_offset)) {
-		acpi_os_printf ("***User_breakpoint*** at AML offset %X\n", op->common.aml_offset);
-		acpi_gbl_cm_single_step = TRUE;
-		acpi_gbl_step_to_next_call = FALSE;
-		walk_state->method_breakpoint = 0;
-	}
-
-
-	/*
-	 * Check if this is an opcode that we are interested in --
-	 * namely, opcodes that have arguments
-	 */
-	if (op->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
-		return (AE_OK);
-	}
-
-	switch (opcode_class) {
-	case AML_CLASS_UNKNOWN:
-	case AML_CLASS_ARGUMENT:    /* constants, literals, etc.  do nothing */
-		return (AE_OK);
-
-	default:
-		/* All other opcodes -- continue */
-		break;
-	}
-
-	/*
-	 * Under certain debug conditions, display this opcode and its operands
-	 */
-	if ((acpi_gbl_db_output_to_file)        ||
-		(acpi_gbl_cm_single_step)           ||
-		(acpi_dbg_level & ACPI_LV_PARSE)) {
-		if ((acpi_gbl_db_output_to_file)    ||
-			(acpi_dbg_level & ACPI_LV_PARSE)) {
-			acpi_os_printf ("\n[Aml_debug] Next AML Opcode to execute:\n");
-		}
-
-		/*
-		 * Display this op (and only this op - zero out the NEXT field temporarily,
-		 * and disable parser trace output for the duration of the display because
-		 * we don't want the extraneous debug output)
-		 */
-		original_debug_level = acpi_dbg_level;
-		acpi_dbg_level &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS);
-		next = op->common.next;
-		op->common.next = NULL;
-
-
-		display_op = op;
-		parent_op = op->common.parent;
-		if (parent_op) {
-			if ((walk_state->control_state) &&
-				(walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING)) {
-				/*
-				 * We are executing the predicate of an IF or WHILE statement
-				 * Search upwards for the containing IF or WHILE so that the
-				 * entire predicate can be displayed.
-				 */
-				while (parent_op) {
-					if ((parent_op->common.aml_opcode == AML_IF_OP) ||
-						(parent_op->common.aml_opcode == AML_WHILE_OP)) {
-						display_op = parent_op;
-						break;
-					}
-					parent_op = parent_op->common.parent;
-				}
-			}
-			else {
-				while (parent_op) {
-					if ((parent_op->common.aml_opcode == AML_IF_OP)   ||
-						(parent_op->common.aml_opcode == AML_ELSE_OP) ||
-						(parent_op->common.aml_opcode == AML_SCOPE_OP) ||
-						(parent_op->common.aml_opcode == AML_METHOD_OP) ||
-						(parent_op->common.aml_opcode == AML_WHILE_OP)) {
-						break;
-					}
-					display_op = parent_op;
-					parent_op = parent_op->common.parent;
-				}
-			}
-		}
-
-		/* Now we can display it */
-
-		acpi_dm_disassemble (walk_state, display_op, ACPI_UINT32_MAX);
-
-		if ((op->common.aml_opcode == AML_IF_OP) ||
-			(op->common.aml_opcode == AML_WHILE_OP)) {
-			if (walk_state->control_state->common.value) {
-				acpi_os_printf ("Predicate = [True], IF block was executed\n");
-			}
-			else {
-				acpi_os_printf ("Predicate = [False], Skipping IF block\n");
-			}
-		}
-
-		else if (op->common.aml_opcode == AML_ELSE_OP) {
-			acpi_os_printf ("Predicate = [False], ELSE block was executed\n");
-		}
-
-		/* Restore everything */
-
-		op->common.next = next;
-		acpi_os_printf ("\n\n");
-		acpi_dbg_level = original_debug_level;
-	}
-
-	/* If we are not single stepping, just continue executing the method */
-
-	if (!acpi_gbl_cm_single_step) {
-		return (AE_OK);
-	}
-
-	/*
-	 * If we are executing a step-to-call command,
-	 * Check if this is a method call.
-	 */
-	if (acpi_gbl_step_to_next_call) {
-		if (op->common.aml_opcode != AML_INT_METHODCALL_OP) {
-			/* Not a method call, just keep executing */
-
-			return (AE_OK);
-		}
-
-		/* Found a method call, stop executing */
-
-		acpi_gbl_step_to_next_call = FALSE;
-	}
-
-	/*
-	 * If the next opcode is a method call, we will "step over" it
-	 * by default.
-	 */
-	if (op->common.aml_opcode == AML_INT_METHODCALL_OP) {
-		acpi_gbl_cm_single_step = FALSE; /* No more single step while executing called method */
-
-		/* Set the breakpoint on/before the call, it will stop execution as soon as we return */
-
-		walk_state->method_breakpoint = 1; /* Must be non-zero! */
-	}
-
-
-	/* TBD: [Investigate] what are the namespace locking issues here */
-
-	/* Acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); */
-
-	/* Go into the command loop and await next user command */
-
-	acpi_gbl_method_executing = TRUE;
-	status = AE_CTRL_TRUE;
-	while (status == AE_CTRL_TRUE) {
-		if (acpi_gbl_debugger_configuration == DEBUGGER_MULTI_THREADED) {
-			/* Handshake with the front-end that gets user command lines */
-
-			status = acpi_ut_release_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
-			if (ACPI_FAILURE (status)) {
-				return (status);
-			}
-			status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
-			if (ACPI_FAILURE (status)) {
-				return (status);
-			}
-		}
-
-		else {
-			/* Single threaded, we must get a command line ourselves */
-
-			/* Force output to console until a command is entered */
-
-			acpi_db_set_output_destination (ACPI_DB_CONSOLE_OUTPUT);
-
-			/* Different prompt if method is executing */
-
-			if (!acpi_gbl_method_executing) {
-				acpi_os_printf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT);
-			}
-			else {
-				acpi_os_printf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT);
-			}
-
-			/* Get the user input line */
-
-			(void) acpi_os_get_line (acpi_gbl_db_line_buf);
-		}
-
-		status = acpi_db_command_dispatch (acpi_gbl_db_line_buf, walk_state, op);
-	}
-
-	/* Acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); */
-
-	/* User commands complete, continue execution of the interrupted method */
-
-	return (status);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_initialize
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Init and start debugger
- *
- ******************************************************************************/
-
-acpi_status
-acpi_db_initialize (void)
-{
-	acpi_status             status;
-
-
-	/* Init globals */
-
-	acpi_gbl_db_buffer          = NULL;
-	acpi_gbl_db_filename        = NULL;
-	acpi_gbl_db_output_to_file  = FALSE;
-
-	acpi_gbl_db_debug_level     = ACPI_LV_VERBOSITY2;
-	acpi_gbl_db_console_debug_level = NORMAL_DEFAULT | ACPI_LV_TABLES;
-	acpi_gbl_db_output_flags    = ACPI_DB_CONSOLE_OUTPUT;
-
-	acpi_gbl_db_opt_tables      = FALSE;
-	acpi_gbl_db_opt_disasm      = FALSE;
-	acpi_gbl_db_opt_stats       = FALSE;
-	acpi_gbl_db_opt_verbose     = TRUE;
-	acpi_gbl_db_opt_ini_methods = TRUE;
-
-	acpi_gbl_db_buffer = acpi_os_allocate (ACPI_DEBUG_BUFFER_SIZE);
-	if (!acpi_gbl_db_buffer) {
-		return (AE_NO_MEMORY);
-	}
-	ACPI_MEMSET (acpi_gbl_db_buffer, 0, ACPI_DEBUG_BUFFER_SIZE);
-
-	/* Initial scope is the root */
-
-	acpi_gbl_db_scope_buf [0] = '\\';
-	acpi_gbl_db_scope_buf [1] = 0;
-	acpi_gbl_db_scope_node = acpi_gbl_root_node;
-
-	/*
-	 * If configured for multi-thread support, the debug executor runs in
-	 * a separate thread so that the front end can be in another address
-	 * space, environment, or even another machine.
-	 */
-	if (acpi_gbl_debugger_configuration & DEBUGGER_MULTI_THREADED) {
-		/* These were created with one unit, grab it */
-
-		status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_COMPLETE);
-		if (ACPI_FAILURE (status)) {
-			acpi_os_printf ("Could not get debugger mutex\n");
-			return (status);
-		}
-		status = acpi_ut_acquire_mutex (ACPI_MTX_DEBUG_CMD_READY);
-		if (ACPI_FAILURE (status)) {
-			acpi_os_printf ("Could not get debugger mutex\n");
-			return (status);
-		}
-
-		/* Create the debug execution thread to execute commands */
-
-		status = acpi_os_queue_for_execution (0, acpi_db_execute_thread, NULL);
-		if (ACPI_FAILURE (status)) {
-			acpi_os_printf ("Could not start debugger thread\n");
-			return (status);
-		}
-	}
-
-	if (!acpi_gbl_db_opt_verbose) {
-		acpi_gbl_db_opt_disasm = TRUE;
-		acpi_gbl_db_opt_stats = FALSE;
-	}
-
-	return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    Acpi_db_terminate
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Stop debugger
- *
- ******************************************************************************/
-
-void
-acpi_db_terminate (void)
-{
-
-	if (acpi_gbl_db_table_ptr) {
-		acpi_os_free (acpi_gbl_db_table_ptr);
-	}
-	if (acpi_gbl_db_buffer) {
-		acpi_os_free (acpi_gbl_db_buffer);
-	}
-}
-
-
-#endif /* ACPI_DEBUGGER */
diff -Nru a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h
--- a/drivers/acpi/include/acpiosxf.h	Sun Sep 15 19:19:28 2002
+++ b/drivers/acpi/include/acpiosxf.h	Sun Sep 15 19:19:28 2002
@@ -261,10 +261,6 @@
 	void                    *pointer,
 	u32                     length);
 
-u32
-acpi_os_get_timer (
-	void);
-
 acpi_status
 acpi_os_signal (
 	u32                     function,
@@ -284,10 +280,6 @@
 	const NATIVE_CHAR       *format,
 	va_list                 args);
 
-void
-acpi_os_redirect_output (
-	void                    *destination);
-
 
 /*
  * Debug input
@@ -296,18 +288,6 @@
 u32
 acpi_os_get_line (
 	NATIVE_CHAR             *buffer);
-
-
-/*
- * Debug
- */
-
-void
-acpi_os_dbg_assert(
-	void                    *failed_assertion,
-	void                    *file_name,
-	u32                     line_number,
-	NATIVE_CHAR             *message);
 
 
 #endif /* __ACPIOSXF_H__ */
diff -Nru a/drivers/acpi/kdb/README.txt b/drivers/acpi/kdb/README.txt
--- a/drivers/acpi/kdb/README.txt	Sun Sep 15 19:20:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-Using the ACPI debugger with kdb
---------------------------------
-
-ACPI CA includes a full-featured debugger, which allows the examination of
-a running system's ACPI tables, as well as running and stepping through
-control methods.
-
-Configuration
--------------
-1) Edit the main acpi Makefile. On the ACPI_CFLAGS line, remove the '#', thus
-   enabling the debugger.
-
-2) Download the latest kdb patch from:
-
-   ftp://oss.sgi.com/www/projects/kdb/download/ix86/ 
-
-   Follow the instructions at http://oss.sgi.com/projects/kdb/ on how to
-   install the patch and configure KDB.
-
-3) This would probably be a good time to recompile the kernel, and make sure
-   kdb works (Hitting the Pause key should drop you into it. Type "go" to exit
-   it.
-
-4) The kdb <--> ACPI debugger interface is a module. Type "make modules", and
-   it will be built and placed in drivers/acpi/kdb.
-
-5) Change to that directory and type "insmod kdbm_acpi.o". This loads the
-   module we just built.
-
-6) Break back into kdb. If you type help, you should now see "acpi" listed as
-   a command, at the bottom.
-
-7) Type "acpi". You are now in the ACPI debugger. While hosted by kdb, it is
-   wholly separate, and has many ACPI-specific commands. Type "?" or "help"
-   to get a listing of the command categories, and then "help <category>" for
-   a list of commands and their descriptions
diff -Nru a/drivers/acpi/kdb/kdbm_acpi.c b/drivers/acpi/kdb/kdbm_acpi.c
--- a/drivers/acpi/kdb/kdbm_acpi.c	Sun Sep 15 19:19:45 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-/*
- *  kdbm_acpi.c - kdb debugger module interface for ACPI debugger
- *
- *  Copyright (C) 2000 Andrew Grover
- *
- *  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.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/kdb.h>
-#include <linux/module.h>
-
-#include "acpi.h"
-#include "acdebug.h"
-
-extern int acpi_in_debugger;
-
-static int
-kdbm_acpi(int argc, const char **argv, const char **envp, struct pt_regs *regs)
-{
-	acpi_in_debugger = 1;
-
-	acpi_db_user_commands(DB_COMMAND_PROMPT, NULL);
-
-	acpi_in_debugger = 0;
-
-	return 0;
-}
-
-int
-init_module(void)
-{
-	kdb_register("acpi", kdbm_acpi, "", "Enter ACPI debugger", 0);
-
-	return 0;
-}
-
-void
-cleanup_module(void)
-{
-	kdb_unregister("acpi");
-}
diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c	Sun Sep 15 19:20:20 2002
+++ b/drivers/acpi/osl.c	Sun Sep 15 19:20:20 2002
@@ -134,16 +134,6 @@
 	return kmalloc(size, GFP_KERNEL);
 }
 
-void *
-acpi_os_callocate(ACPI_SIZE size)
-{
-	void *ptr = acpi_os_allocate(size);
-	if (ptr)
-		memset(ptr, 0, size);
-
-	return ptr;
-}
-
 void
 acpi_os_free(void *ptr)
 {
@@ -523,37 +513,6 @@
 
 #endif /*CONFIG_ACPI_PCI*/
 
-acpi_status
-acpi_os_load_module (
-	char *module_name)
-{
-	ACPI_FUNCTION_TRACE ("os_load_module");
-
-	if (!module_name)
-		return_ACPI_STATUS (AE_BAD_PARAMETER);
-
-	if (request_module(module_name) < 0) {
-		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to load module [%s].\n", module_name));
-		return_ACPI_STATUS (AE_ERROR);
-	}
-
-	return_ACPI_STATUS (AE_OK);
-}
-
-acpi_status
-acpi_os_unload_module (
-	char *module_name)
-{
-	if (!module_name)
-		return AE_BAD_PARAMETER;
-
-	/* TODO: How on Linux? */
-	/* this is done automatically for all modules with
-	use_count = 0, I think. see: MOD_INC_USE_COUNT -ASG */
-
-	return AE_OK;
-}
-
 
 /*
  * See acpi_os_queue_for_execution()
@@ -695,9 +654,10 @@
 
 	ACPI_FUNCTION_TRACE ("os_create_semaphore");
 
-	sem = acpi_os_callocate(sizeof(struct semaphore));
+	sem = acpi_os_allocate(sizeof(struct semaphore));
 	if (!sem)
 		return_ACPI_STATUS (AE_NO_MEMORY);
+	memset(sem, 0, sizeof(struct semaphore));
 
 	sema_init(sem, initial_units);
 
@@ -913,12 +873,3 @@
 
 	return AE_OK;
 }
-
-acpi_status
-acpi_os_breakpoint(NATIVE_CHAR *msg)
-{
-	acpi_os_printf("breakpoint: %s", msg);
-	
-	return AE_OK;
-}
-
diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/acpi/pci_irq.c	Sun Sep 15 19:19:37 2002
@@ -288,7 +288,7 @@
 	while (!irq && (bridge = bridge->bus->self)) {
 		pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
 		irq = acpi_pci_irq_lookup(0, bridge->bus->number, PCI_SLOT(bridge->devfn), pin);
-	};
+	}
 
 	if (!irq) {
 		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to derive IRQ for device %s\n", dev->slot_name));
diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
--- a/drivers/acpi/pci_link.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/acpi/pci_link.c	Sun Sep 15 19:19:29 2002
@@ -54,12 +54,12 @@
 static int acpi_pci_link_remove (struct acpi_device *device, int type);
 
 static struct acpi_driver acpi_pci_link_driver = {
-        .name =		ACPI_PCI_LINK_DRIVER_NAME,
-        .class =	ACPI_PCI_LINK_CLASS,
-        .ids =		ACPI_PCI_LINK_HID,
-        .ops =		{
-				.add =		acpi_pci_link_add,
-				.remove =	acpi_pci_link_remove,
+	.name =		ACPI_PCI_LINK_DRIVER_NAME,
+	.class =	ACPI_PCI_LINK_CLASS,
+	.ids =		ACPI_PCI_LINK_HID,
+	.ops =		{
+				.add =    acpi_pci_link_add,
+				.remove = acpi_pci_link_remove,
 			},
 };
 
diff -Nru a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
--- a/drivers/acpi/pci_root.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/acpi/pci_root.c	Sun Sep 15 19:19:29 2002
@@ -51,8 +51,8 @@
 	.class =	ACPI_PCI_ROOT_CLASS,
 	.ids =		ACPI_PCI_ROOT_HID,
 	.ops =		{
-				.add =		acpi_pci_root_add,
-				.remove =	acpi_pci_root_remove,
+				.add =    acpi_pci_root_add,
+				.remove = acpi_pci_root_remove,
 			},
 };
 
diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c
--- a/drivers/acpi/system.c	Sun Sep 15 19:19:52 2002
+++ b/drivers/acpi/system.c	Sun Sep 15 19:19:52 2002
@@ -23,8 +23,6 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#define ACPI_C
-
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff -Nru a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
--- a/drivers/acpi/toshiba_acpi.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/acpi/toshiba_acpi.c	Sun Sep 15 19:19:28 2002
@@ -26,15 +26,15 @@
  *	Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
  *		engineering the Windows drivers
  *	Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
+ *	Rob Miller - TV out and hotkeys help
  *
  *
  *  TODO
- *	provide version info in proc
- *	add Fn key status
  *
  */
 
-#define TOSHIBA_ACPI_VERSION "0.12"
+#define TOSHIBA_ACPI_VERSION	"0.13"
+#define PROC_INTERFACE_VERSION	1
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -43,9 +43,10 @@
 #include <linux/proc_fs.h>
 #include <linux/version.h>
 
-#define KERNEL24 (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+#include <acconfig.h>
+#define OLD_ACPI_INTERFACE (ACPI_CA_VERSION < 0x20020000)
 
-#if KERNEL24
+#if OLD_ACPI_INTERFACE
 #include <acpi.h>
 extern struct proc_dir_entry* bm_proc_root;
 #define acpi_root_dir bm_proc_root
@@ -82,10 +83,13 @@
 #define HCI_SUCCESS			0x0000
 #define HCI_FAILURE			0x1000
 #define HCI_NOT_SUPPORTED		0x8000
+#define HCI_EMPTY			0x8c00
 
 /* registers */
 #define HCI_FAN				0x0004
+#define HCI_SYSTEM_EVENT		0x0016
 #define HCI_VIDEO_OUT			0x001c
+#define HCI_HOTKEY_EVENT		0x001e
 #define HCI_LCD_BRIGHTNESS		0x002a
 
 /* field definitions */
@@ -94,6 +98,7 @@
 #define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
 #define HCI_VIDEO_OUT_LCD		0x1
 #define HCI_VIDEO_OUT_CRT		0x2
+#define HCI_VIDEO_OUT_TV		0x4
 
 /* utility
  */
@@ -104,6 +109,23 @@
 	*word = (*word & ~mask) | (mask * value);
 }
 
+/* an sscanf that takes explicit string length */
+static int
+snscanf(const char* str, int n, const char* format, ...)
+{
+	va_list args;
+	int result;
+	char* str2 = kmalloc(n + 1, GFP_KERNEL);
+	if (str2 == 0) return 0;
+	strncpy(str2, str, n);
+	str2[n] = 0;
+	va_start(args, format);
+	result = vsscanf(str2, format, args);
+	va_end(args);
+	kfree(str2);
+	return result;
+}
+
 /* This is the common code at the end of every proc read handler.  I don't
  * understand it yet.
  */
@@ -226,14 +248,15 @@
 #define PROC_LCD		"lcd"
 #define PROC_VIDEO		"video"
 #define PROC_FAN		"fan"
+#define PROC_KEYS		"keys"
+#define PROC_VERSION		"version"
 
 static struct proc_dir_entry*	toshiba_proc_dir = NULL;
 static int			force_fan;
+static int			last_key_event;
+static int			key_event_valid;
 
 /* proc file handlers
- *
- * WARNING: The write handlers are using sscanf on non-zero-terminated
- * buffers.  This may result in memory reads past the buffer bounds.
  */
 
 static int
@@ -270,7 +293,7 @@
 	u32 hci_result;
 
 	/* ISSUE: %i doesn't work with hex values as advertised */
-	if (sscanf(buffer, " brightness : %i", &value) == 1 &&
+	if (snscanf(buffer, count, " brightness : %i", &value) == 1 &&
 			value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
 		value = value << HCI_LCD_BRIGHTNESS_SHIFT;
 		hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
@@ -297,8 +320,10 @@
 	if (hci_result == HCI_SUCCESS) {
 		int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
 		int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
+		int is_tv  = (value & HCI_VIDEO_OUT_TV ) ? 1 : 0;
 		p += sprintf(p, "lcd_out:                 %d\n", is_lcd);
 		p += sprintf(p, "crt_out:                 %d\n", is_crt);
+		p += sprintf(p, "tv_out:                  %d\n", is_tv);
 	} else {
 		p += sprintf(p, "ERROR\n");
 		goto end;
@@ -316,15 +341,18 @@
 	const char* buffer_end = buffer + count;
 	int lcd_out = -1;
 	int crt_out = -1;
+	int tv_out = -1;
 	u32 hci_result;
 	int video_out;
 
 	/* scan expression.  Multiple expressions may be delimited with ; */
 	do {
-		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
+		if (snscanf(buffer, count, " lcd_out : %i", &value) == 1)
 			lcd_out = value & 1;
-		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
+		else if (snscanf(buffer, count, " crt_out : %i", &value) == 1)
 			crt_out = value & 1;
+		else if (snscanf(buffer, count, " tv_out : %i", &value) == 1)
+			tv_out = value & 1;
 		/* advance to one character past the next ; */
 		do ++buffer;
 		while ((buffer < buffer_end) && (*(buffer-1) != ';'));
@@ -337,6 +365,8 @@
 			_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
 		if (crt_out != -1)
 			_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
+		if (tv_out != -1)
+			_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
 		/* To avoid unnecessary video disruption, only write the new
 		 * video setting if something changed. */
 		if (new_video_out != video_out)
@@ -376,7 +406,7 @@
 	int value;
 	u32 hci_result;
 
-	if (sscanf(buffer, " force_on : %i", &value) == 1 &&
+	if (snscanf(buffer, count, " force_on : %i", &value) == 1 &&
 			value >= 0 && value <= 1) {
 		hci_write1(HCI_FAN, value, &hci_result);
 		if (hci_result != HCI_SUCCESS)
@@ -390,6 +420,68 @@
 	return count;
 }
 
+static int
+proc_read_keys(char* page, char** start, off_t off, int count, int* eof,
+	void* context)
+{
+	char* p = page;
+	u32 hci_result;
+	u32 value;
+
+	if (off != 0) goto end;
+
+	if (!key_event_valid) {
+		hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
+		if (hci_result == HCI_SUCCESS) {
+			key_event_valid = 1;
+			last_key_event = value;
+		} else if (hci_result == HCI_EMPTY) {
+			/* better luck next time */
+		} else {
+			p += sprintf(p, "ERROR\n");
+			goto end;
+		}
+	}
+
+	p += sprintf(p, "hotkey_ready:            %d\n", key_event_valid);
+	p += sprintf(p, "hotkey:                  0x%04x\n", last_key_event);
+
+end:
+	return end_proc_read(p, page, off, count, start, eof);
+}
+
+static int
+proc_write_keys(struct file* file, const char* buffer, unsigned long count,
+	void* data)
+{
+	int value;
+
+	if (snscanf(buffer, count, " hotkey_ready : %i", &value) == 1 &&
+			value == 0) {
+		key_event_valid = 0;
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static int
+proc_read_version(char* page, char** start, off_t off, int count, int* eof,
+	void* context)
+{
+	char* p = page;
+
+	if (off != 0) goto end;
+
+	p += sprintf(p, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
+	p += sprintf(p, "proc_interface:          %d\n",
+		PROC_INTERFACE_VERSION);
+
+end:
+	return end_proc_read(p, page, off, count, start, eof);
+}
+
 /* proc and module init
  */
 
@@ -410,6 +502,13 @@
 		toshiba_proc_dir, proc_read_fan, 0);
 	if (proc) proc->write_proc = proc_write_fan;
 
+	proc = create_proc_read_entry(PROC_KEYS, S_IFREG | S_IRUGO | S_IWUSR,
+		toshiba_proc_dir, proc_read_keys, 0);
+	if (proc) proc->write_proc = proc_write_keys;
+
+	proc = create_proc_read_entry(PROC_VERSION, S_IFREG | S_IRUGO | S_IWUSR,
+		toshiba_proc_dir, proc_read_version, 0);
+
 	return(AE_OK);
 }
 
@@ -419,6 +518,8 @@
 	remove_proc_entry(PROC_LCD, toshiba_proc_dir);
 	remove_proc_entry(PROC_VIDEO, toshiba_proc_dir);
 	remove_proc_entry(PROC_FAN, toshiba_proc_dir);
+	remove_proc_entry(PROC_KEYS, toshiba_proc_dir);
+	remove_proc_entry(PROC_VERSION, toshiba_proc_dir);
 	return(AE_OK);
 }
 
@@ -437,6 +538,10 @@
 	printk("Toshiba Laptop ACPI Extras version %s\n", TOSHIBA_ACPI_VERSION);
 
 	force_fan = 0;
+	key_event_valid = 0;
+
+	/* enable event fifo */
+	hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
 
 	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
 	if (!toshiba_proc_dir) {
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/block/floppy.c	Sun Sep 15 19:19:29 2002
@@ -4219,8 +4219,6 @@
 {
 	int i,unit,drive;
 
-	register_sys_device(&device_floppy);
-
 	raw_cmd = NULL;
 
 	devfs_handle = devfs_mk_dir (NULL, "floppy", NULL);
@@ -4347,6 +4345,9 @@
 			register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4),
 					1, &floppy_fops, 0);
 	}
+
+	register_sys_device(&device_floppy);
+
 	return have_no_fdc;
 }
 
@@ -4529,6 +4530,7 @@
 {
 	int dummy;
 		
+	unregister_sys_device(&device_floppy);
 	devfs_unregister (devfs_handle);
 	unregister_blkdev(MAJOR_NR, "fd");
 
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/block/ll_rw_blk.c	Sun Sep 15 19:19:29 2002
@@ -919,7 +919,7 @@
  * __blk_stop_queue: see blk_stop_queue()
  *
  * Description:
- *  Like blk_stop_queue(), bust queue_lock must be held
+ *  Like blk_stop_queue(), but queue_lock must be held
  **/
 void __blk_stop_queue(request_queue_t *q)
 {
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/cdrom/cdrom.c	Sun Sep 15 19:19:29 2002
@@ -266,8 +266,8 @@
 #include <linux/proc_fs.h>
 #include <linux/blkpg.h>
 #include <linux/init.h>
+#include <linux/fcntl.h>
 
-#include <asm/fcntl.h>
 #include <asm/uaccess.h>
 
 /* used to tell the module to turn on full debugging messages */
diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help
--- a/drivers/char/Config.help	Sun Sep 15 19:19:37 2002
+++ b/drivers/char/Config.help	Sun Sep 15 19:19:37 2002
@@ -16,57 +16,6 @@
 
   Most people can say N here.
 
-CONFIG_SERIAL_EXTENDED
-  If you wish to use any non-standard features of the standard "dumb"
-  driver, say Y here. This includes HUB6 support, shared serial
-  interrupts, special multiport support, support for more than the
-  four COM 1/2/3/4 boards, etc.
-
-  Note that the answer to this question won't directly affect the
-  kernel: saying N will just cause the configurator to skip all
-  the questions about serial driver options. If unsure, say N.
-
-CONFIG_SERIAL_MANY_PORTS
-  Say Y here if you have dumb serial boards other than the four
-  standard COM 1/2/3/4 ports. This may happen if you have an AST
-  FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
-  from <http://www.linuxdoc.org/docs.html#howto>), or other custom
-  serial port hardware which acts similar to standard serial port
-  hardware. If you only use the standard COM 1/2/3/4 ports, you can
-  say N here to save some memory. You can also say Y if you have an
-  "intelligent" multiport card such as Cyclades, Digiboards, etc.
-
-CONFIG_SERIAL_ACPI
-  Legacy free machines may not have serial ports at the legacy COM1, 
-  COM2 etc addresses. Serial ports on such machines are described by
-  the ACPI tables SPCR (Serial Port Console Redirection) table and 
-  DBGP (Debug Port) table. Say Y here if you want to include support
-  for these serial ports.
-
-CONFIG_SERIAL_SHARE_IRQ
-  Some serial boards have hardware support which allows multiple dumb
-  serial ports on the same board to share a single IRQ. To enable
-  support for this in the serial driver, say Y here.
-
-CONFIG_SERIAL_DETECT_IRQ
-  Say Y here if you want the kernel to try to guess which IRQ
-  to use for your serial port.
-
-  This is considered unsafe; it is far better to configure the IRQ in
-  a boot script using the setserial command.
-
-  If unsure, say N.
-
-CONFIG_SERIAL_MULTIPORT
-  Some multiport serial ports have special ports which are used to
-  signal when there are any serial ports on the board which need
-  servicing. Say Y here to enable the serial driver to take advantage
-  of those special I/O ports.
-
-CONFIG_HUB6
-  Say Y here to enable support in the dumb serial driver to support
-  the HUB6 card.
-
 CONFIG_MWAVE
   The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
   kernel driver and a user level application. Together these components
@@ -241,54 +190,6 @@
 
   If unsure, say Y.
 
-CONFIG_SERIAL
-  This selects whether you want to include the driver for the standard
-  serial ports.  The standard answer is Y.  People who might say N
-  here are those that are setting up dedicated Ethernet WWW/FTP
-  servers, or users that have one of the various bus mice instead of a
-  serial mouse and don't intend to use their machine's standard serial
-  port for anything.  (Note that the Cyclades and Stallion multi
-  serial port drivers do not need this driver built in for them to
-  work.)
-
-  If you want to compile this driver as a module, say M here and read
-  <file:Documentation/modules.txt>.  The module will be called
-  serial.o.
-  [WARNING: Do not compile this driver as a module if you are using
-  non-standard serial ports, since the configuration information will
-  be lost when the driver is unloaded.  This limitation may be lifted
-  in the future.]
-
-  BTW1: If you have a mouseman serial mouse which is not recognized by
-  the X window system, try running gpm first.
-
-  BTW2: If you intend to use a software modem (also called Winmodem)
-  under Linux, forget it.  These modems are crippled and require
-  proprietary drivers which are only available under Windows.
-
-  Most people will say Y or M here, so that they can use serial mice,
-  modems and similar devices connecting to the standard serial ports.
-
-CONFIG_SERIAL_CONSOLE
-  If you say Y here, it will be possible to use a serial port as the
-  system console (the system console is the device which receives all
-  kernel messages and warnings and which allows logins in single user
-  mode). This could be useful if some terminal or printer is connected
-  to that serial port.
-
-  Even if you say Y here, the currently visible virtual console
-  (/dev/tty0) will still be used as the system console by default, but
-  you can alter that using a kernel command line option such as
-  "console=ttyS1". (Try "man bootparam" or see the documentation of
-  your boot loader (lilo or loadlin) about how to pass options to the
-  kernel at boot time.)
-
-  If you don't have a VGA card installed and you say Y here, the
-  kernel will automatically use the first serial line, /dev/ttyS0, as
-  system console.
-
-  If unsure, say N.
-
 CONFIG_ROCKETPORT
   This is a driver for the Comtrol Rocketport cards which provide
   multiple serial ports. You would need something like this to connect
@@ -1007,15 +908,6 @@
   The module will be called nvram.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-CONFIG_ATOMWIDE_SERIAL
-  If you have an Atomwide Serial card for an Acorn system, say Y to
-  this option.  The driver can handle 1, 2, or 3 port cards.
-  If unsure, say N.
-
-CONFIG_DUALSP_SERIAL
-  If you have the Serial Port's dual serial card for an Acorn system,
-  say Y to this option.  If unsure, say N.
-
 CONFIG_NWBUTTON
   If you say Y here and create a character device node /dev/nwbutton
   with major and minor numbers 10 and 158 ("man mknod"), then every
@@ -1071,15 +963,6 @@
   It is also possible to say M here to build it as a module (ds1620.o)
   It is recommended to be used on a NetWinder, but it is not a
   necessity.
-
-CONFIG_SERIAL_21285
-  If you have a machine based on a 21285 (Footbridge) StrongARM(R)/
-  PCI bridge you can enable its onboard serial port by enabling this
-  option. The device has major ID 4, minor 64.
-
-CONFIG_SERIAL_21285_CONSOLE
-  If you have enabled the serial port on the 21285 footbridge you can
-  make it the console by answering Y to this option.
 
 CONFIG_NWFLASH
   If you say Y here and create a character device /dev/flash with
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Sun Sep 15 19:19:29 2002
+++ b/drivers/char/Config.in	Sun Sep 15 19:19:29 2002
@@ -179,21 +179,7 @@
 fi
 endmenu
 
-dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
-if [ "$CONFIG_AGP" != "n" ]; then
-   bool '  Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
-   bool '  Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
-   bool '  VIA chipset support' CONFIG_AGP_VIA
-   bool '  AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
-   bool '  Generic SiS support' CONFIG_AGP_SIS
-   bool '  ALI chipset support' CONFIG_AGP_ALI
-   bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
-   if [ "$CONFIG_IA64" = "y" ]; then
-     bool '  Intel 460GX support' CONFIG_AGP_I460
-     bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
-   fi
-fi
-
+source drivers/char/agp/Config.in
 source drivers/char/drm/Config.in
 
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Sun Sep 15 19:20:24 2002
+++ b/drivers/char/Makefile	Sun Sep 15 19:20:24 2002
@@ -13,7 +13,7 @@
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
 export-objs     :=	busmouse.o console.o generic_serial.o ip2main.o \
-			ite_gpio.o misc.o nvram.o pty.o random.o rtc.o \
+			ite_gpio.o keyboard.o misc.o nvram.o random.o rtc.o \
 			selection.o sonypi.o sysrq.o tty_io.o tty_ioctl.o
 
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/char/dz.c	Sun Sep 15 19:19:29 2002
@@ -51,7 +51,6 @@
 
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/serial.h>
 
 #include <asm/uaccess.h>
 #include <asm/irq.h>
diff -Nru a/drivers/char/ftape/lowlevel/Makefile b/drivers/char/ftape/lowlevel/Makefile
--- a/drivers/char/ftape/lowlevel/Makefile	Sun Sep 15 19:19:29 2002
+++ b/drivers/char/ftape/lowlevel/Makefile	Sun Sep 15 19:19:29 2002
@@ -23,6 +23,8 @@
 #      driver for Linux.
 #
 
+export-objs := ftape_syms.o
+
 obj-$(CONFIG_FTAPE) += ftape.o
 
 ftape-objs := ftape-init.o fdc-io.o fdc-isr.o \
diff -Nru a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c
--- a/drivers/char/ftape/lowlevel/ftape_syms.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/char/ftape/lowlevel/ftape_syms.c	Sun Sep 15 19:19:30 2002
@@ -42,62 +42,48 @@
 #include "../lowlevel/ftape-buffer.h"
 #include "../lowlevel/ftape-format.h"
 
-#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
-# define FT_KSYM(sym) EXPORT_SYMBOL(sym);
-#else
-# define FT_KSYM(sym) X(sym),
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
-struct symbol_table ftape_symbol_table = {
-#include <linux/symtab_begin.h>
-#endif
 /* bad sector handling from ftape-bsm.c */
-FT_KSYM(ftape_get_bad_sector_entry)
-FT_KSYM(ftape_find_end_of_bsm_list)
+EXPORT_SYMBOL(ftape_get_bad_sector_entry);
+EXPORT_SYMBOL(ftape_find_end_of_bsm_list);
 /* from ftape-rw.c */
-FT_KSYM(ftape_set_state)
+EXPORT_SYMBOL(ftape_set_state);
 /* from ftape-ctl.c */
-FT_KSYM(ftape_seek_to_bot)
-FT_KSYM(ftape_seek_to_eot)
-FT_KSYM(ftape_abort_operation)
-FT_KSYM(ftape_get_status)
-FT_KSYM(ftape_enable)
-FT_KSYM(ftape_disable)
-FT_KSYM(ftape_mmap)
-FT_KSYM(ftape_calibrate_data_rate)
+EXPORT_SYMBOL(ftape_seek_to_bot);
+EXPORT_SYMBOL(ftape_seek_to_eot);
+EXPORT_SYMBOL(ftape_abort_operation);
+EXPORT_SYMBOL(ftape_get_status);
+EXPORT_SYMBOL(ftape_enable);
+EXPORT_SYMBOL(ftape_disable);
+EXPORT_SYMBOL(ftape_mmap);
+EXPORT_SYMBOL(ftape_calibrate_data_rate);
 /* from ftape-io.c */
-FT_KSYM(ftape_reset_drive)
-FT_KSYM(ftape_command)
-FT_KSYM(ftape_parameter)
-FT_KSYM(ftape_ready_wait)
-FT_KSYM(ftape_report_operation)
-FT_KSYM(ftape_report_error)
+EXPORT_SYMBOL(ftape_reset_drive);
+EXPORT_SYMBOL(ftape_command);
+EXPORT_SYMBOL(ftape_parameter);
+EXPORT_SYMBOL(ftape_ready_wait);
+EXPORT_SYMBOL(ftape_report_operation);
+EXPORT_SYMBOL(ftape_report_error);
 /* from ftape-read.c */
-FT_KSYM(ftape_read_segment_fraction)
-FT_KSYM(ftape_zap_read_buffers)
-FT_KSYM(ftape_read_header_segment)
-FT_KSYM(ftape_decode_header_segment)
+EXPORT_SYMBOL(ftape_read_segment_fraction);
+EXPORT_SYMBOL(ftape_zap_read_buffers);
+EXPORT_SYMBOL(ftape_read_header_segment);
+EXPORT_SYMBOL(ftape_decode_header_segment);
 /* from ftape-write.c */
-FT_KSYM(ftape_write_segment)
-FT_KSYM(ftape_start_writing)
-FT_KSYM(ftape_loop_until_writes_done)
+EXPORT_SYMBOL(ftape_write_segment);
+EXPORT_SYMBOL(ftape_start_writing);
+EXPORT_SYMBOL(ftape_loop_until_writes_done);
 /* from ftape-buffer.h */
-FT_KSYM(ftape_set_nr_buffers)
+EXPORT_SYMBOL(ftape_set_nr_buffers);
 /* from ftape-format.h */
-FT_KSYM(ftape_format_track)
-FT_KSYM(ftape_format_status)
-FT_KSYM(ftape_verify_segment)
+EXPORT_SYMBOL(ftape_format_track);
+EXPORT_SYMBOL(ftape_format_status);
+EXPORT_SYMBOL(ftape_verify_segment);
 /* from tracing.c */
 #ifndef CONFIG_FT_NO_TRACE_AT_ALL
-FT_KSYM(ftape_tracing)
-FT_KSYM(ftape_function_nest_level)
-FT_KSYM(ftape_trace_call)
-FT_KSYM(ftape_trace_exit)
-FT_KSYM(ftape_trace_log)
-#endif
-/* end of ksym table */
-#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
-#include <linux/symtab_end.h>
-};
+EXPORT_SYMBOL(ftape_tracing);
+EXPORT_SYMBOL(ftape_function_nest_level);
+EXPORT_SYMBOL(ftape_trace_call);
+EXPORT_SYMBOL(ftape_trace_exit);
+EXPORT_SYMBOL(ftape_trace_log);
 #endif
+
diff -Nru a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c
--- a/drivers/char/ftape/zftape/zftape_syms.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/char/ftape/zftape/zftape_syms.c	Sun Sep 15 19:19:28 2002
@@ -34,26 +34,12 @@
 #include "../zftape/zftape-buffers.h"
 #include "../zftape/zftape-ctl.h"
 
-#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
-# define FT_KSYM(sym) EXPORT_SYMBOL(sym);
-#else
-# define FT_KSYM(sym) X(sym),
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
-struct symbol_table zft_symbol_table = {
-#include <linux/symtab_begin.h>
-#endif
 /* zftape-init.c */
-FT_KSYM(zft_cmpr_register)
-FT_KSYM(zft_cmpr_unregister)
+EXPORT_SYMBOL(zft_cmpr_register);
+EXPORT_SYMBOL(zft_cmpr_unregister);
 /* zftape-read.c */
-FT_KSYM(zft_fetch_segment_fraction)
+EXPORT_SYMBOL(zft_fetch_segment_fraction);
 /* zftape-buffers.c */
-FT_KSYM(zft_vmalloc_once)
-FT_KSYM(zft_vmalloc_always)
-FT_KSYM(zft_vfree)
-#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18)
-#include <linux/symtab_end.h>
-};
-#endif
+EXPORT_SYMBOL(zft_vmalloc_once);
+EXPORT_SYMBOL(zft_vmalloc_always);
+EXPORT_SYMBOL(zft_vfree);
diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
--- a/drivers/char/hvc_console.c	Sun Sep 15 19:20:20 2002
+++ b/drivers/char/hvc_console.c	Sun Sep 15 19:20:20 2002
@@ -227,6 +227,8 @@
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
 
+extern unsigned long cpus_in_xmon;
+
 int khvcd(void *unused)
 {
 	int i;
@@ -236,8 +238,10 @@
 	sigfillset(&current->blocked);
 
 	for (;;) {
-		for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i)
-			hvc_poll(i);
+		if (!cpus_in_xmon) {
+			for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i)
+				hvc_poll(i);
+		}
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(TIMEOUT);
 	}
@@ -282,7 +286,7 @@
 		panic("Couldn't register hvc console driver\n");
 
 	if (hvc_driver.num > 0)
-		kernel_thread(khvcd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+		kernel_thread(khvcd, NULL, CLONE_KERNEL);
 
 	return 0;
 }
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Sun Sep 15 19:19:34 2002
+++ b/drivers/char/keyboard.c	Sun Sep 15 19:19:34 2002
@@ -66,6 +66,7 @@
 #endif
 
 struct pt_regs *kbd_pt_regs;
+EXPORT_SYMBOL(kbd_pt_regs);
 void compute_shiftstate(void);
 
 /*
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/char/lp.c	Sun Sep 15 19:19:28 2002
@@ -335,7 +335,7 @@
 	do {
 		/* Write the data. */
 		written = parport_write (port, kbuf, copy_size);
-		if (written >= 0) {
+		if (written > 0) {
 			copy_size -= written;
 			count -= written;
 			buf  += written;
@@ -840,7 +840,7 @@
 		    port->probe_info[0].class != PARPORT_CLASS_PRINTER)
 			return;
 		if (lp_count == LP_NO) {
-			printk("lp: ignoring parallel port (max. %d)\n",LP_NO);
+			printk(KERN_INFO "lp: ignoring parallel port (max. %d)\n",LP_NO);
 			return;
 		}
 		if (!lp_register(lp_count, port))
@@ -904,14 +904,14 @@
 	}
 
 	if (register_chrdev (LP_MAJOR, "lp", &lp_fops)) {
-		printk ("lp: unable to get major %d\n", LP_MAJOR);
+		printk (KERN_ERR "lp: unable to get major %d\n", LP_MAJOR);
 		return -EIO;
 	}
 
 	devfs_handle = devfs_mk_dir (NULL, "printers", NULL);
 
 	if (parport_register_driver (&lp_driver)) {
-		printk ("lp: unable to register with parport\n");
+		printk (KERN_ERR "lp: unable to register with parport\n");
 		return -EIO;
 	}
 
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Sun Sep 15 19:19:56 2002
+++ b/drivers/char/raw.c	Sun Sep 15 19:19:56 2002
@@ -201,25 +201,29 @@
 }
 
 static ssize_t
-rw_raw_dev(int rw, struct file *filp, char *buf, size_t size, loff_t *offp)
+rw_raw_dev(int rw, struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp)
 {
 	const int minor = minor(filp->f_dentry->d_inode->i_rdev);
 	struct block_device *bdev = raw_devices[minor].binding;
 	struct inode *inode = bdev->bd_inode;
+ 	size_t count = iov_length(iov, nr_segs); 
 	ssize_t ret = 0;
 
-	if (size == 0)
-		goto out;
-	ret = -EINVAL;
-	if (size < 0)
-		goto out;
-	ret = -ENXIO;
-	if (*offp >= inode->i_size)
-		goto out;
-
-	if (size + *offp > inode->i_size)
-		size = inode->i_size - *offp;
-	ret = generic_file_direct_IO(rw, inode, buf, *offp, size);
+	if (count == 0)
+		goto out;	
+
+	if ((ssize_t)count < 0)
+		return -EINVAL;	
+
+	if (*offp >= inode->i_size) 
+		return -ENXIO;
+
+	if (count + *offp > inode->i_size) {
+		count = inode->i_size - *offp;
+		nr_segs = iov_shorten((struct iovec *)iov, nr_segs, count);
+	}
+	ret = generic_file_direct_IO(rw, inode, iov, *offp, nr_segs);
+
 	if (ret > 0)
 		*offp += ret;
 out:
@@ -227,15 +231,31 @@
 }
 
 static ssize_t
-raw_read(struct file *filp, char * buf, size_t size, loff_t *offp)
+raw_read(struct file *filp, char *buf, size_t size, loff_t *offp)
 {
-	return rw_raw_dev(READ, filp, buf, size, offp);
+	struct iovec local_iov = { .iov_base = buf, .iov_len = size};
+
+	return rw_raw_dev(READ, filp, &local_iov, 1, offp);
 }
 
 static ssize_t
 raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp)
 {
-	return rw_raw_dev(WRITE, filp, (char *)buf, size, offp);
+	struct iovec local_iov = { .iov_base = buf, .iov_len = size};
+
+	return rw_raw_dev(WRITE, filp, &local_iov, 1, offp);
+}
+
+static ssize_t 
+raw_readv(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp) 
+{
+	return rw_raw_dev(READ, filp, iov, nr_segs, offp);
+}
+
+static ssize_t 
+raw_writev(struct file *filp, const struct iovec *iov, unsigned long nr_segs, loff_t *offp) 
+{
+	return rw_raw_dev(WRITE, filp, iov, nr_segs, offp);
 }
 
 static struct file_operations raw_fops = {
@@ -244,6 +264,8 @@
 	.open	=	raw_open,
 	.release=	raw_release,
 	.ioctl	=	raw_ioctl,
+	.readv	= 	raw_readv,
+	.writev	= 	raw_writev,
 	.owner	=	THIS_MODULE,
 };
 
diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c
--- a/drivers/char/serial_tx3912.c	Sun Sep 15 19:19:50 2002
+++ b/drivers/char/serial_tx3912.c	Sun Sep 15 19:19:50 2002
@@ -16,7 +16,6 @@
 #include <linux/tty.h>
 #include <linux/major.h>
 #include <linux/ptrace.h>
-#include <linux/init.h>
 #include <linux/console.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c
--- a/drivers/char/sysrq.c	Sun Sep 15 19:20:20 2002
+++ b/drivers/char/sysrq.c	Sun Sep 15 19:20:20 2002
@@ -299,7 +299,7 @@
 {
 	struct task_struct *p;
 
-	for_each_task(p) {
+	for_each_process(p) {
 		if (p->mm && p->pid != 1)
 			/* Not swapper, init nor kernel thread */
 			force_sig(sig, p);
diff -Nru a/drivers/char/toshiba.c b/drivers/char/toshiba.c
--- a/drivers/char/toshiba.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/char/toshiba.c	Sun Sep 15 19:20:24 2002
@@ -114,11 +114,10 @@
 	if (tosh_fn!=0) {
 		scan = inb(tosh_fn);
 	} else {
-		save_flags(flags);
-		cli();
+		local_irq_save(flags);
 		outb(0x8e, 0xe4);
 		scan = inb(0xe5);
-		restore_flags(flags);
+		local_irq_restore(flags);
 	}
 
         return (int) scan;
@@ -141,35 +140,32 @@
 	if (tosh_id==0xfccb) {
 		if (eax==0xfe00) {
 			/* fan status */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xbe, 0xe4);
 			al = inb(0xe5);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = (unsigned int) (al & 0x01);
 		}
 		if ((eax==0xff00) && (ecx==0x0000)) {
 			/* fan off */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xbe, 0xe4);
 			al = inb(0xe5);
 			outb(0xbe, 0xe4);
 			outb (al | 0x01, 0xe5);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = 0x00;
 		}
 		if ((eax==0xff00) && (ecx==0x0001)) {
 			/* fan on */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xbe, 0xe4);
 			al = inb(0xe5);
 			outb(0xbe, 0xe4);
 			outb(al & 0xfe, 0xe5);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = 0x01;
 		}
@@ -180,33 +176,30 @@
 	if (tosh_id==0xfccc) {
 		if (eax==0xfe00) {
 			/* fan status */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xe0, 0xe4);
 			al = inb(0xe5);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = al & 0x01;
 		}
 		if ((eax==0xff00) && (ecx==0x0000)) {
 			/* fan off */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xe0, 0xe4);
 			al = inb(0xe5);
 			outw(0xe0 | ((al & 0xfe) << 8), 0xe4);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = 0x00;
 		}
 		if ((eax==0xff00) && (ecx==0x0001)) {
 			/* fan on */
-			save_flags(flags);
-			cli();
+			local_irq_save(flags);
 			outb(0xe0, 0xe4);
 			al = inb(0xe5);
 			outw(0xe0 | ((al | 0x01) << 8), 0xe4);
-			restore_flags(flags);
+			local_irq_restore(flags);
 			regs->eax = 0x00;
 			regs->ecx = 0x01;
 		}
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Sun Sep 15 19:19:52 2002
+++ b/drivers/char/tty_io.c	Sun Sep 15 19:19:52 2002
@@ -204,6 +204,8 @@
 	return _tty_make_name(tty, (tty)?tty->driver.name:NULL, buf);
 }
 
+EXPORT_SYMBOL(tty_name);
+
 inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine)
 {
@@ -494,7 +496,7 @@
 	}
 	
 	read_lock(&tasklist_lock);
- 	for_each_task(p) {
+ 	for_each_process(p) {
 		if ((tty->session > 0) && (p->session == tty->session) &&
 		    p->leader) {
 			send_sig(SIGHUP,p,1);
@@ -596,7 +598,7 @@
 	tty->pgrp = -1;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p)
+	for_each_process(p)
 	  	if (p->session == current->session)
 			p->tty = NULL;
 	read_unlock(&tasklist_lock);
@@ -1221,7 +1223,7 @@
 		struct task_struct *p;
 
 		read_lock(&tasklist_lock);
-		for_each_task(p) {
+		for_each_process(p) {
 			if (p->tty == tty || (o_tty && p->tty == o_tty))
 				p->tty = NULL;
 		}
@@ -1559,7 +1561,7 @@
 			struct task_struct *p;
 
 			read_lock(&tasklist_lock);
-			for_each_task(p)
+			for_each_process(p)
 				if (p->tty == tty)
 					p->tty = NULL;
 			read_unlock(&tasklist_lock);
@@ -1832,7 +1834,7 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
 		if ((p->tty == tty) ||
 		    ((session > 0) && (p->session == session))) {
 			printk(KERN_NOTICE "SAK: killed process %d"
diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h
--- a/drivers/hotplug/cpqphp.h	Sun Sep 15 19:19:29 2002
+++ b/drivers/hotplug/cpqphp.h	Sun Sep 15 19:19:29 2002
@@ -292,16 +292,14 @@
 	struct pci_resource *io_head;
 	struct pci_resource *bus_head;
 	struct pci_dev *pci_dev;
-	struct pci_ops *pci_ops;
+	struct pci_bus *pci_bus;
 	struct proc_dir_entry* proc_entry;
 	struct proc_dir_entry* proc_entry2;
 	struct event_info event_queue[10];
 	struct slot *slot;
 	u8 next_event;
 	u8 interrupt;
-	u8 bus;
-	u8 device;
-	u8 function;
+	u8 bus;				/* bus number for the pci hotplug controller */
 	u8 rev;
 	u8 slot_device_offset;
 	u8 first_slot;
@@ -695,7 +693,8 @@
 		return 1;
 
 	hp_slot = slot->device - ctrl->slot_device_offset;
-	dbg(__FUNCTION__": slot->device = %d, ctrl->slot_device_offset = %d \n", slot->device, ctrl->slot_device_offset);
+	dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n",
+	    __FUNCTION__, slot->device, ctrl->slot_device_offset);
 
 	status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot));
 
@@ -733,7 +732,7 @@
         DECLARE_WAITQUEUE(wait, current);
 	int retval = 0;
 
-	dbg(__FUNCTION__" - start\n");
+	dbg("%s - start\n", __FUNCTION__);
 	add_wait_queue(&ctrl->queue, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	/* Sleep for up to 1 second to wait for the LED to change. */
@@ -743,7 +742,7 @@
 	if (signal_pending(current))
 		retval =  -EINTR;
 
-	dbg(__FUNCTION__" - end\n");
+	dbg("%s - end\n", __FUNCTION__);
 	return retval;
 }
 
diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
--- a/drivers/hotplug/cpqphp_core.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/hotplug/cpqphp_core.c	Sun Sep 15 19:19:28 2002
@@ -314,7 +314,7 @@
 	void *slot_entry= NULL;
 	int result;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 
 	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);
 
@@ -467,7 +467,7 @@
 //
 // Output:	SUCCESS or FAILURE
 //=============================================================================
-static int get_slot_mapping (struct pci_ops *ops, u8 bus_num, u8 dev_num, u8 *slot)
+static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
 {
 	struct irq_routing_table *PCIIRQRoutingInfoLength;
 	u32 work;
@@ -476,7 +476,7 @@
 
 	u8 tbus, tdevice, tslot, bridgeSlot;
 
-	dbg(__FUNCTION__" %p, %d, %d, %p\n", ops, bus_num, dev_num, slot);
+	dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot);
 
 	bridgeSlot = 0xFF;
 
@@ -490,7 +490,6 @@
 		return -1;
 	}
 
-
 	for (loop = 0; loop < len; ++loop) {
 		tbus = PCIIRQRoutingInfoLength->slots[loop].bus;
 		tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3;
@@ -499,7 +498,8 @@
 		if ((tbus == bus_num) && (tdevice == dev_num)) {
 			*slot = tslot;
 
-			if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength );
+			if (PCIIRQRoutingInfoLength != NULL)
+				kfree(PCIIRQRoutingInfoLength);
 			return 0;
 		} else {
 			// Didn't get a match on the target PCI device. Check if the
@@ -508,10 +508,11 @@
 			// device, I need to save the bridge's slot number.  If I can't 
 			// find an entry for the target device, I will have to assume it's 
 			// on the other side of the bridge, and assign it the bridge's slot.
-			pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_REVISION_ID, &work);
+			bus->number = tbus;
+			pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_REVISION_ID, &work);
 
 			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
-				pci_read_config_dword_nodev (ops, tbus, tdevice, 0, PCI_PRIMARY_BUS, &work);
+				pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work);
 				// See if bridge's secondary bus matches target bus.
 				if (((work >> 8) & 0x000000FF) == (long) bus_num) {
 					bridgeSlot = tslot;
@@ -521,7 +522,6 @@
 
 	}
 
-
 	// If we got here, we didn't find an entry in the IRQ mapping table 
 	// for the target PCI device.  If we did determine that the target 
 	// device is on the other side of a PCI-to-PCI bridge, return the 
@@ -592,7 +592,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -627,7 +627,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -667,7 +667,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -695,7 +695,7 @@
 	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
 	struct controller *ctrl;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	if (slot == NULL)
 		return -ENODEV;
@@ -716,7 +716,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -734,7 +734,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -752,7 +752,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -770,8 +770,8 @@
 	
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	ctrl = slot->ctrl;
 	if (ctrl == NULL)
@@ -820,7 +820,7 @@
 		// TODO: This code can be made to support non-Compaq or Intel subsystem IDs
 		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
 		if (rc) {
-			err(__FUNCTION__" : pci_read_config_word failed\n");
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
 			return rc;
 		}
 		dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
@@ -831,14 +831,14 @@
 
 		ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
 		if (!ctrl) {
-			err(__FUNCTION__" : out of memory\n");
+			err("%s : out of memory\n", __FUNCTION__);
 			return -ENOMEM;
 		}
 		memset(ctrl, 0, sizeof(struct controller));
 
 		rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid);
 		if (rc) {
-			err(__FUNCTION__" : pci_read_config_word failed\n");
+			err("%s : pci_read_config_word failed\n", __FUNCTION__);
 			goto err_free_ctrl;
 		}
 
@@ -991,12 +991,20 @@
 	dbg ("    pcix_support           %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported");
 
 	ctrl->pci_dev = pdev;
-	ctrl->pci_ops = pdev->bus->ops;
+
+	/* make our own copy of the pci bus structure, as we like tweaking it a lot */
+	ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL);
+	if (!ctrl->pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto err_free_ctrl;
+	}
+	memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
+
 	ctrl->bus = pdev->bus->number;
-	ctrl->device = PCI_SLOT(pdev->devfn);
-	ctrl->function = PCI_FUNC(pdev->devfn);
 	ctrl->rev = rev;
-	dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, ctrl->device, ctrl->function, ctrl->rev);
+	dbg("bus device function rev: %d %d %d %d\n", ctrl->bus,
+	     PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev);
 
 	init_MUTEX(&ctrl->crit_sect);
 	init_waitqueue_head(&ctrl->queue);
@@ -1004,7 +1012,7 @@
 	/* initialize our threads if they haven't already been started up */
 	rc = one_time_init();
 	if (rc) {
-		goto err_free_ctrl;
+		goto err_free_bus;
 	}
 	
 	dbg("pdev = %p\n", pdev);
@@ -1015,7 +1023,7 @@
 				pci_resource_len(pdev, 0), MY_NAME)) {
 		err("cannot reserve MMIO region\n");
 		rc = -ENOMEM;
-		goto err_free_ctrl;
+		goto err_free_bus;
 	}
 
 	ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
@@ -1043,7 +1051,7 @@
 	// in this case it will always be called for the "base"
 	// bus/dev/func of a slot.
 	// CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table)
-	rc = get_slot_mapping(ctrl->pci_ops, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot));
+	rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot));
 	dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc);
 	if (rc) {
 		err(msg_initialization_err, rc);
@@ -1053,7 +1061,7 @@
 	// Store PCI Config Space for all devices on this bus
 	rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK));
 	if (rc) {
-		err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc);
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
 		goto err_iounmap;
 	}
 
@@ -1080,7 +1088,7 @@
 	rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table);
 	if (rc) {
 		err(msg_initialization_err, 6);
-		err(__FUNCTION__": unable to save PCI configuration data, error %d\n", rc);
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
 		goto err_iounmap;
 	}
 	
@@ -1188,6 +1196,8 @@
 	iounmap(ctrl->hpc_reg);
 err_free_mem_region:
 	release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+err_free_bus:
+	kfree(ctrl->pci_bus);
 err_free_ctrl:
 	kfree(ctrl);
 	return rc;
@@ -1327,6 +1337,8 @@
 			res = res->next;
 			kfree(tres);
 		}
+
+		kfree (ctrl->pci_bus);
 
 		tctrl = ctrl;
 		ctrl = ctrl->next;
diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c
--- a/drivers/hotplug/cpqphp_ctrl.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/hotplug/cpqphp_ctrl.c	Sun Sep 15 19:19:30 2002
@@ -772,13 +772,13 @@
 		return(NULL);
 
 	for (node = *head; node; node = node->next) {
-		dbg(__FUNCTION__": req_size =%x node=%p, base=%x, length=%x\n",
-		    size, node, node->base, node->length);
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
+		    __FUNCTION__, size, node, node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg(__FUNCTION__": not aligned\n");
+			dbg("%s: not aligned\n", __FUNCTION__);
 			// this one isn't base aligned properly
 			// so we'll make a new entry and split it up
 			temp_dword = (node->base | (size-1)) + 1;
@@ -804,7 +804,7 @@
 
 		// Don't need to check if too small since we already did
 		if (node->length > size) {
-			dbg(__FUNCTION__": too big\n");
+			dbg("%s: too big\n", __FUNCTION__);
 			// this one is longer than we need
 			// so we'll make a new entry and split it up
 			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
@@ -821,7 +821,7 @@
 			node->next = split_node;
 		}  // End of too big on top end
 
-		dbg(__FUNCTION__": got one!!!\n");
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		// If we got here, then it is the right size
 		// Now take it out of the list
 		if (*head == node) {
@@ -856,7 +856,7 @@
 	struct pci_resource *node2;
 	int out_of_order = 1;
 
-	dbg(__FUNCTION__": head = %p, *head = %p\n", head, *head);
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
 
 	if (!(*head))
 		return(1);
@@ -942,7 +942,7 @@
 		// Read to clear posted writes
 		misc = readw(ctrl->hpc_reg + MISC);
 
-		dbg (__FUNCTION__" - waking up\n");
+		dbg ("%s - waking up\n", __FUNCTION__);
 		wake_up_interruptible(&ctrl->queue);
 	}
 
@@ -1382,8 +1382,8 @@
 	struct resource_lists res_lists;
 
 	hp_slot = func->device - ctrl->slot_device_offset;
-	dbg(__FUNCTION__": func->device, slot_offset, hp_slot = %d, %d ,%d\n",
-	    func->device, ctrl->slot_device_offset, hp_slot);
+	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
+	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 
 	if (ctrl->speed == 1) {
 		// Wait for exclusive access to hardware
@@ -1430,55 +1430,56 @@
 	// turn on board and blink green LED
 
 	// Wait for exclusive access to hardware
-	dbg(__FUNCTION__": before down\n");
+	dbg("%s: before down\n", __FUNCTION__);
 	down(&ctrl->crit_sect);
-	dbg(__FUNCTION__": after down\n");
+	dbg("%s: after down\n", __FUNCTION__);
 
-	dbg(__FUNCTION__": before slot_enable\n");
+	dbg("%s: before slot_enable\n", __FUNCTION__);
 	slot_enable (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before green_LED_blink\n");
+	dbg("%s: before green_LED_blink\n", __FUNCTION__);
 	green_LED_blink (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before amber_LED_blink\n");
+	dbg("%s: before amber_LED_blink\n", __FUNCTION__);
 	amber_LED_off (ctrl, hp_slot);
 
-	dbg(__FUNCTION__": before set_SOGO\n");
+	dbg("%s: before set_SOGO\n", __FUNCTION__);
 	set_SOGO(ctrl);
 
 	// Wait for SOBS to be unset
-	dbg(__FUNCTION__": before wait_for_ctrl_irq\n");
+	dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__);
 	wait_for_ctrl_irq (ctrl);
-	dbg(__FUNCTION__": after wait_for_ctrl_irq\n");
+	dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__);
 
 	// Done with exclusive hardware access
-	dbg(__FUNCTION__": before up\n");
+	dbg("%s: before up\n", __FUNCTION__);
 	up(&ctrl->crit_sect);
-	dbg(__FUNCTION__": after up\n");
+	dbg("%s: after up\n", __FUNCTION__);
 
 	// Wait for ~1 second because of hot plug spec
-	dbg(__FUNCTION__": before long_delay\n");
+	dbg("%s: before long_delay\n", __FUNCTION__);
 	long_delay(1*HZ);
-	dbg(__FUNCTION__": after long_delay\n");
+	dbg("%s: after long_delay\n", __FUNCTION__);
 
-	dbg(__FUNCTION__": func status = %x\n", func->status);
+	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
 	// Check for a power fault
 	if (func->status == 0xFF) {
 		// power fault occurred, but it was benign
 		temp_register = 0xFFFFFFFF;
-		dbg(__FUNCTION__": temp register set to %x by power fault\n", temp_register);
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
 		rc = POWER_FAILURE;
 		func->status = 0;
 	} else {
 		// Get vendor/device ID u32
-		rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register);
-		dbg(__FUNCTION__": pci_read_config_dword returns %d\n", rc);
-		dbg(__FUNCTION__": temp_register is %x\n", temp_register);
+		ctrl->pci_bus->number = func->bus;
+		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register);
+		dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
 
 		if (rc != 0) {
 			// Something's wrong here
 			temp_register = 0xFFFFFFFF;
-			dbg(__FUNCTION__": temp register set to %x by error\n", temp_register);
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
 		}
 		// Preset return code.  It will be changed later if things go okay.
 		rc = NO_ADAPTER_PRESENT;
@@ -1494,7 +1495,7 @@
 
 		rc = configure_new_device(ctrl, func, 0, &res_lists);
 
-		dbg(__FUNCTION__": back from configure_new_device\n");
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
 		ctrl->io_head = res_lists.io_head;
 		ctrl->mem_head = res_lists.mem_head;
 		ctrl->p_mem_head = res_lists.p_mem_head;
@@ -1531,7 +1532,7 @@
 		func->is_a_board = 0x01;
 
 		//next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present)
-		dbg(__FUNCTION__": configure linux pci_dev structure\n");
+		dbg("%s: configure linux pci_dev structure\n", __FUNCTION__);
 		index = 0;
 		do {
 			new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++);
@@ -1598,7 +1599,7 @@
 	device = func->device;
 
 	hp_slot = func->device - ctrl->slot_device_offset;
-	dbg("In "__FUNCTION__", hp_slot = %d\n", hp_slot);
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
 	// When we get here, it is safe to change base Address Registers.
 	// We will attempt to save the base Address Register Lengths
@@ -1927,7 +1928,7 @@
 		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
 		dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl);
 		if (!func) {
-			dbg("Error! func NULL in "__FUNCTION__"\n");
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
 			return ;
 		}
 
@@ -1951,7 +1952,7 @@
 		func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0);
 		dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl);
 		if (!func) {
-			dbg("Error! func NULL in "__FUNCTION__"\n");
+			dbg("Error! func NULL in %s\n", __FUNCTION__);
 			return ;
 		}
 
@@ -2066,7 +2067,7 @@
 	}
 
 	if (rc) {
-		dbg(__FUNCTION__": rc = %d\n", rc);
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
 	}
 
 	if (p_slot)
@@ -2082,7 +2083,9 @@
 	u8 index = 0;
 	u8 replace_flag;
 	u32 rc = 0;
+	unsigned int devfn;
 	struct slot* p_slot;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
 	int physical_slot=0;
 
 	device = func->device; 
@@ -2094,8 +2097,11 @@
 
 	// Make sure there are no video controllers here
 	while (func && !rc) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
 		// Check the Class Code
-		rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code);
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
 		if (rc)
 			return rc;
 
@@ -2104,13 +2110,13 @@
 			rc = REMOVE_NOT_SUPPORTED;
 		} else {
 			// See if it's a bridge
-			rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type);
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 			if (rc)
 				return rc;
 
 			// If it's a bridge, check the VGA Enable bit
 			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
-				rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, &BCR);
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
 				if (rc)
 					return rc;
 
@@ -2332,11 +2338,12 @@
 
 	new_slot = func;
 
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 	// Check for Multi-function device
-	rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0E, &temp_byte);
+	ctrl->pci_bus->number = func->bus;
+	rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte);
 	if (rc) {
-		dbg(__FUNCTION__": rc = %d\n", rc);
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
 		return rc;
 	}
 
@@ -2372,7 +2379,7 @@
 		//  and creates a board structure
 
 		while ((function < max_functions) && (!stop_it)) {
-			pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, function, 0x00, &ID);
+			pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID);
 
 			if (ID == 0xFFFFFFFF) {	  // There's nothing there. 
 				function++;
@@ -2435,6 +2442,7 @@
 	u32 temp_register;
 	u32 base;
 	u32 ID;
+	unsigned int devfn;
 	struct pci_resource *mem_node;
 	struct pci_resource *p_mem_node;
 	struct pci_resource *io_node;
@@ -2445,17 +2453,22 @@
 	struct pci_resource *hold_bus_node;
 	struct irq_mapping irqs;
 	struct pci_func *new_slot;
+	struct pci_bus *pci_bus;
 	struct resource_lists temp_resources;
 
+	pci_bus = ctrl->pci_bus;
+	pci_bus->number = func->bus;
+	devfn = PCI_DEVFN(func->device, func->function);
+
 	// Check for Bridge
-	rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &temp_byte);
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte);
 	if (rc)
 		return rc;
 
 	if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge
 		// set Primary bus
 		dbg("set Primary bus = %d\n", func->bus);
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, func->bus);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
 		if (rc)
 			return rc;
 
@@ -2470,29 +2483,29 @@
 		// set Secondary bus
 		temp_byte = bus_node->base;
 		dbg("set Secondary bus = %d\n", bus_node->base);
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
 		if (rc)
 			return rc;
 
 		// set subordinate bus
 		temp_byte = bus_node->base + bus_node->length - 1;
 		dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1);
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
 		if (rc)
 			return rc;
 
 		// set subordinate Latency Timer and base Latency Timer
 		temp_byte = 0x40;
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SEC_LATENCY_TIMER, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
 		if (rc)
 			return rc;
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
 		if (rc)
 			return rc;
 
 		// set Cache Line size
 		temp_byte = 0x08;
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
 		if (rc)
 			return rc;
 
@@ -2568,10 +2581,10 @@
 
 			// set IO base and Limit registers
 			temp_byte = io_node->base >> 8;
-			rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
 
 			temp_byte = (io_node->base + io_node->length - 1) >> 8;
-			rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
 		} else {
 			kfree(hold_IO_node);
 			hold_IO_node = NULL;
@@ -2586,16 +2599,16 @@
 
 			// set Mem base and Limit registers
 			temp_word = mem_node->base >> 16;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
 
 			temp_word = (mem_node->base + mem_node->length - 1) >> 16;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
 		} else {
 			temp_word = 0xFFFF;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
 
 			temp_word = 0x0000;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
 
 			kfree(hold_mem_node);
 			hold_mem_node = NULL;
@@ -2610,16 +2623,16 @@
 
 			// set Pre Mem base and Limit registers
 			temp_word = p_mem_node->base >> 16;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
 
 			temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
 		} else {
 			temp_word = 0xFFFF;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
 
 			temp_word = 0x0000;
-			rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
 
 			kfree(hold_p_mem_node);
 			hold_p_mem_node = NULL;
@@ -2635,7 +2648,9 @@
 			irqs.barber_pole = (irqs.barber_pole + 1) & 0x03;
 
 			ID = 0xFFFFFFFF;
-			pci_read_config_dword_nodev (ctrl->pci_ops, hold_bus_node->base, device, 0, 0x00, &ID);
+			pci_bus->number = hold_bus_node->base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID);
+			pci_bus->number = func->bus;
 
 			if (ID != 0xFFFFFFFF) {	  //  device Present
 				// Setup slot structure.
@@ -2703,7 +2718,7 @@
 			temp_byte = temp_resources.bus_head->base - 1;
 
 			// set subordinate bus
-			rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
 
 			if (temp_resources.bus_head->length == 0) {
 				kfree(temp_resources.bus_head);
@@ -2724,7 +2739,7 @@
 				hold_IO_node->base = io_node->base + io_node->length;
 
 				temp_byte = (hold_IO_node->base) >> 8;
-				rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, temp_byte);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte);
 
 				return_resource(&(resources->io_head), io_node);
 			}
@@ -2742,13 +2757,13 @@
 					func->io_head = hold_IO_node;
 
 					temp_byte = (io_node->base - 1) >> 8;
-					rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_byte);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
 
 					return_resource(&(resources->io_head), io_node);
 				} else {
 					// it doesn't need any IO
 					temp_word = 0x0000;
-					pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, temp_word);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word);
 
 					return_resource(&(resources->io_head), io_node);
 					kfree(hold_IO_node);
@@ -2774,7 +2789,7 @@
 				hold_mem_node->base = mem_node->base + mem_node->length;
 
 				temp_word = (hold_mem_node->base) >> 16;
-				rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, temp_word);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
 
 				return_resource(&(resources->mem_head), mem_node);
 			}
@@ -2792,14 +2807,14 @@
 
 					// configure end address
 					temp_word = (mem_node->base - 1) >> 16;
-					rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
 
 					// Return unused resources to the pool
 					return_resource(&(resources->mem_head), mem_node);
 				} else {
 					// it doesn't need any Mem
 					temp_word = 0x0000;
-					rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, temp_word);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
 
 					return_resource(&(resources->mem_head), mem_node);
 					kfree(hold_mem_node);
@@ -2825,7 +2840,7 @@
 				hold_p_mem_node->base = p_mem_node->base + p_mem_node->length;
 
 				temp_word = (hold_p_mem_node->base) >> 16;
-				rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, temp_word);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
 
 				return_resource(&(resources->p_mem_head), p_mem_node);
 			}
@@ -2843,13 +2858,13 @@
 					func->p_mem_head = hold_p_mem_node;
 
 					temp_word = (p_mem_node->base - 1) >> 16;
-					rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
 
 					return_resource(&(resources->p_mem_head), p_mem_node);
 				} else {
 					// it doesn't need any PMem
 					temp_word = 0x0000;
-					rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, temp_word);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
 
 					return_resource(&(resources->p_mem_head), p_mem_node);
 					kfree(hold_p_mem_node);
@@ -2870,14 +2885,14 @@
 
 		// enable card
 		command = 0x0157;	// = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |  PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR
-		rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command);
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command);
 
 		// set Bridge Control Register
 		command = 0x07;		// = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA
-		rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command);
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
 	} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
 		// Standard device
-		rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code);
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
 
 		if (class_code == PCI_BASE_CLASS_DISPLAY) {
 			// Display (video) adapter (not supported)
@@ -2887,10 +2902,10 @@
 		for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
 			temp_register = 0xFFFFFFFF;
 
-			dbg("CND: bus=%d, device=%d, func=%d, offset=%d\n", func->bus, func->device, func->function, cloop);
-			rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
+			dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop);
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
 
-			rc = pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp_register);
+			rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register);
 			dbg("CND: base = 0x%x\n", temp_register);
 
 			if (temp_register) {	  // If this register is implemented
@@ -2971,7 +2986,7 @@
 					return(NOT_ENOUGH_RESOURCES);
 				}
 
-				rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base);
+				rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base);
 
 				// Check for 64-bit base
 				if ((temp_register & 0x07L) == 0x04) {
@@ -2980,13 +2995,13 @@
 					// Upper 32 bits of address always zero on today's systems
 					// FIXME this is probably not true on Alpha and ia64???
 					base = 0;
-					rc = pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, base);
+					rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base);
 				}
 			}
 		}		// End of base register loop
 
 		// Figure out which interrupt pin this function uses
-		rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_PIN, &temp_byte);
+		rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte);
 
 		// If this function needs an interrupt and we are behind a bridge
 		// and the pin is tied to something that's alread mapped,
@@ -2998,7 +3013,7 @@
 			IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03];
 		} else {
 			// Program IRQ based on card type
-			rc = pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, 0x0B, &class_code);
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
 
 			if (class_code == PCI_BASE_CLASS_STORAGE) {
 				IRQ = cpqhp_disk_irq;
@@ -3008,7 +3023,7 @@
 		}
 
 		// IRQ Line
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_INTERRUPT_LINE, IRQ);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
 
 		if (!behind_bridge) {
 			rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
@@ -3022,19 +3037,19 @@
 
 		// Latency Timer
 		temp_byte = 0x40;
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_LATENCY_TIMER, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
 
 		// Cache Line size
 		temp_byte = 0x08;
-		rc = pci_write_config_byte_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_CACHE_LINE_SIZE, temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
 
 		// disable ROM base Address
 		temp_dword = 0x00L;
-		rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_ROM_ADDRESS, temp_dword);
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_dword);
 
 		// enable card
 		temp_word = 0x0157;	// = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |  PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR
-		rc = pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, temp_word);
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, temp_word);
 	}			// End of Not-A-Bridge else
 	else {
 		// It's some strange type of PCI adapter (Cardbus?)
diff -Nru a/drivers/hotplug/cpqphp_nvram.c b/drivers/hotplug/cpqphp_nvram.c
--- a/drivers/hotplug/cpqphp_nvram.c	Sun Sep 15 19:20:23 2002
+++ b/drivers/hotplug/cpqphp_nvram.c	Sun Sep 15 19:20:23 2002
@@ -161,7 +161,7 @@
 	    (temp6 == 'Q')) {
 		result = 1;
 	}
-	dbg (__FUNCTION__" - returned %d\n", result);
+	dbg ("%s - returned %d\n", __FUNCTION__, result);
 	return result;
 }
 
@@ -286,12 +286,12 @@
 			return(rc);
 
 		// The device Number
-		rc = add_byte( &pFill, ctrl->device, &usedbytes, &available);
+		rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
 		if (rc)
 			return(rc);
 
 		// The function Number
-		rc = add_byte( &pFill, ctrl->function, &usedbytes, &available);
+		rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
 		if (rc)
 			return(rc);
 
@@ -479,8 +479,9 @@
 		device = p_ev_ctrl->device;
 		function = p_ev_ctrl->function;
 
-		while ((bus != ctrl->bus) || (device != ctrl->device)
-		       || (function != ctrl->function)) {
+		while ((bus != ctrl->bus) ||
+		       (device != PCI_SLOT(ctrl->pci_dev->devfn)) || 
+		       (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
 			nummem = p_ev_ctrl->mem_avail;
 			numpmem = p_ev_ctrl->p_mem_avail;
 			numio = p_ev_ctrl->io_avail;
diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c
--- a/drivers/hotplug/cpqphp_pci.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/hotplug/cpqphp_pci.c	Sun Sep 15 19:20:24 2002
@@ -140,7 +140,7 @@
 		//We did not even find a hotplug rep of the function, create it
 		//This code might be taken out if we can guarantee the creation of functions
 		//in parallel (hotplug and Linux at the same time).
-		dbg("@@@@@@@@@@@ cpqhp_slot_create in "__FUNCTION__"\n");
+		dbg("@@@@@@@@@@@ cpqhp_slot_create in %s\n", __FUNCTION__);
 		temp_func = cpqhp_slot_create(bus->number);
 		if (temp_func == NULL)
 			return -ENOMEM;
@@ -150,8 +150,9 @@
 	//Create /proc/bus/pci proc entry for this device and bus device is on
 	//Notify the drivers of the change
 	if (temp_func->pci_dev) {
-		pci_proc_attach_device(temp_func->pci_dev);
-		pci_announce_device_to_drivers(temp_func->pci_dev);
+//		pci_insert_device (temp_func->pci_dev, bus);
+//		pci_proc_attach_device(temp_func->pci_dev);
+//		pci_announce_device_to_drivers(temp_func->pci_dev);
 	}
 
 	return 0;
@@ -307,7 +308,7 @@
 	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
 	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
 
-	dbg(__FUNCTION__": bus/dev/func = %x/%x/%x\n",func->bus, func->device, func->function);
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function);
 
 	for (j=0; j<8 ; j++) {
 		struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j);
@@ -326,15 +327,15 @@
 	return rc;
 }
 
-static int PCI_RefinedAccessConfig(struct pci_ops *ops, u8 bus, u8 device, u8 function, u8 offset, u32 *value)
+static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value)
 {
 	u32 vendID = 0;
 
-	if (pci_read_config_dword_nodev (ops, bus, device, function, PCI_VENDOR_ID, &vendID) == -1)
+	if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1)
 		return -1;
 	if (vendID == 0xffffffff)
 		return -1;
-	return pci_read_config_dword_nodev (ops, bus, device, function, offset, value);
+	return pci_bus_read_config_dword (bus, devfn, offset, value);
 }
 
 
@@ -355,10 +356,10 @@
 	fakedev.devfn = dev_num << 3;
 	fakedev.bus = &fakebus;
 	fakebus.number = bus_num;
-	dbg(__FUNCTION__": dev %d, bus %d, pin %d, num %d\n",
-	    dev_num, bus_num, int_pin, irq_num);
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
 	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
-	dbg(__FUNCTION__":rc %d\n", rc);
+	dbg("%s: rc %d\n", __FUNCTION__, rc);
 	if (rc)
 		return rc;
 
@@ -392,9 +393,11 @@
 	u32 work;
 	u8 tbus;
 
+	ctrl->pci_bus->number = bus_num;
+
 	for (tdevice = 0; tdevice < 0x100; tdevice++) {
 		//Scan for access first
-		if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1)
+		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
 			continue;
 		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);
 		//Yep we got one. Not a bridge ?
@@ -406,12 +409,12 @@
 	}
 	for (tdevice = 0; tdevice < 0x100; tdevice++) {
 		//Scan for access first
-		if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1)
+		if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1)
 			continue;
 		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);
 		//Yep we got one. bridge ?
 		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
-			pci_read_config_byte_nodev (ctrl->pci_ops, tbus, tdevice, 0, PCI_SECONDARY_BUS, &tbus);
+			pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus);
 			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);
 			if (PCI_ScanBusNonBridge(tbus, tdevice) == 0)
 				return 0;
@@ -450,19 +453,20 @@
 		if (tslot == slot) {
 			*bus_num = tbus;
 			*dev_num = tdevice;
-			pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_VENDOR_ID, &work);
+			ctrl->pci_bus->number = tbus;
+			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work);
 			if (!nobridge || (work == 0xffffffff)) {
 				if (PCIIRQRoutingInfoLength != NULL)
 					kfree(PCIIRQRoutingInfoLength );
 				return 0;
 			}
 
-			dbg("bus_num %d dev_num %d func_num %d\n", *bus_num, *dev_num >> 3, *dev_num & 0x7);
-			pci_read_config_dword_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_CLASS_REVISION, &work);
+			dbg("bus_num %d devfn %d\n", *bus_num, *dev_num);
+			pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work);
 			dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS);
 
 			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
-				pci_read_config_byte_nodev (ctrl->pci_ops, *bus_num, *dev_num >> 3, *dev_num & 0x7, PCI_SECONDARY_BUS, &tbus);
+				pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus);
 				dbg("Scan bus for Non Bridge: bus %d\n", tbus);
 				if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) {
 					*bus_num = tbus;
@@ -535,17 +539,17 @@
 	}
 
 	//     Save PCI configuration space for all devices in supported slots
-
+	ctrl->pci_bus->number = busnumber;
 	for (device = FirstSupported; device <= LastSupported; device++) {
 		ID = 0xFFFFFFFF;
-		rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_VENDOR_ID, &ID);
+		rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID);
 
 		if (ID != 0xFFFFFFFF) {	  //  device in slot
-			rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, 0x0B, &class_code);
+			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code);
 			if (rc)
 				return rc;
 
-			rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, 0, PCI_HEADER_TYPE, &header_type);
+			rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type);
 			if (rc)
 				return rc;
 
@@ -563,7 +567,7 @@
 				if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   // P-P Bridge
 					//  Recurse the subordinate bus
 					//  get the subordinate bus number
-					rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_SECONDARY_BUS, &secondary_bus);
+					rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus);
 					if (rc) {
 						return rc;
 					} else {
@@ -572,9 +576,9 @@
 						// Save secondary bus cfg spc
 						// with this recursive call.
 						rc = cpqhp_save_config(ctrl, sub_bus, 0);
-
 						if (rc)
 							return rc;
+						ctrl->pci_bus->number = busnumber;
 					}
 				}
 
@@ -602,7 +606,7 @@
 				new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
 
 				for (cloop = 0; cloop < 0x20; cloop++) {
-					rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
 					if (rc)
 						return rc;
 				}
@@ -615,15 +619,15 @@
 				//  reading in Class Code and Header type.
 
 				while ((function < max_functions)&&(!stop_it)) {
-					rc = pci_read_config_dword_nodev (ctrl->pci_ops, busnumber, device, function, PCI_VENDOR_ID, &ID);
+					rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID);
 					if (ID == 0xFFFFFFFF) {	 // nothing there.
 						function++;
 					} else {  // Something there
-						rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, 0x0B, &class_code);
+						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code);
 						if (rc)
 							return rc;
 
-						rc = pci_read_config_byte_nodev (ctrl->pci_ops, busnumber, device, function, PCI_HEADER_TYPE, &header_type);
+						rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type);
 						if (rc)
 							return rc;
 
@@ -677,12 +681,12 @@
 
 	ID = 0xFFFFFFFF;
 
-	pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_VENDOR_ID, &ID);
+	ctrl->pci_bus->number = new_slot->bus;
+	pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID);
 
 	if (ID != 0xFFFFFFFF) {	  //  device in slot
-		pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, 0x0B, &class_code);
-
-		pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, 0, PCI_HEADER_TYPE, &header_type);
+		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
+		pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
 
 		if (header_type & 0x80)	// Multi-function device
 			max_functions = 8;
@@ -694,22 +698,22 @@
 		do {
 			if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
 				//  Recurse the subordinate bus
-				pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_SECONDARY_BUS, &secondary_bus);
+				pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
 
 				sub_bus = (int) secondary_bus;
 
 				// Save the config headers for the secondary bus.
 				rc = cpqhp_save_config(ctrl, sub_bus, 0);
-
 				if (rc)
 					return(rc);
+				ctrl->pci_bus->number = new_slot->bus;
 
 			}	// End of IF
 
 			new_slot->status = 0;
 
 			for (cloop = 0; cloop < 0x20; cloop++) {
-				pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
+				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop]));
 			}
 
 			function++;
@@ -720,14 +724,14 @@
 			//  reading in the Class Code and the Header type.
 
 			while ((function < max_functions) && (!stop_it)) {
-				pci_read_config_dword_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_VENDOR_ID, &ID);
+				pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID);
 
 				if (ID == 0xFFFFFFFF) {	 // nothing there.
 					function++;
 				} else {  // Something there
-					pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, 0x0B, &class_code);
+					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code);
 
-					pci_read_config_byte_nodev (ctrl->pci_ops, new_slot->bus, new_slot->device, function, PCI_HEADER_TYPE, &header_type);
+					pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type);
 
 					stop_it++;
 				}
@@ -763,17 +767,21 @@
 	u32 rc;
 	struct pci_func *next;
 	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
 
 	func = cpqhp_slot_find(func->bus, func->device, index++);
 
 	while (func != NULL) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
 
 		// Check for Bridge
-		pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type);
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 
 		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
 			// PCI-PCI Bridge
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
 
 			sub_bus = (int) secondary_bus;
 
@@ -787,13 +795,14 @@
 
 				next = next->next;
 			}
+			pci_bus->number = func->bus;
 
 			//FIXME: this loop is duplicated in the non-bridge case.  The two could be rolled together
 			// Figure out IO and memory base lengths
 			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
 				temp_register = 0xFFFFFFFF;
-				pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base);
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
 
 				if (base) {  // If this register is implemented
 					if (base & 0x01L) {
@@ -827,8 +836,8 @@
 			// Figure out IO and memory base lengths
 			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
 				temp_register = 0xFFFFFFFF;
-				pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base);
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
 
 				if (base) {  // If this register is implemented
 					if (base & 0x01L) {
@@ -897,28 +906,31 @@
 	struct pci_resource *p_mem_node;
 	struct pci_resource *io_node;
 	struct pci_resource *bus_node;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
 
 	func = cpqhp_slot_find(func->bus, func->device, index++);
 
 	while ((func != NULL) && func->is_a_board) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
 		// Save the command register
-		pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, &save_command);
+		pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command);
 
 		// disable card
 		command = 0x00;
-		pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_COMMAND, command);
+		pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command);
 
 		// Check for Bridge
-		pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type);
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 
 		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
 			// Clear Bridge Control Register
 			command = 0x00;
-			pci_write_config_word_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_BRIDGE_CONTROL, command);
-
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus);
-
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBORDINATE_BUS, &temp_byte);
+			pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);
 
 			bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
 			if (!bus_node)
@@ -931,9 +943,8 @@
 			func->bus_head = bus_node;
 
 			// Save IO base and Limit registers
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_BASE, &b_base);
-
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_IO_LIMIT, &b_length);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length);
 
 			if ((b_base <= b_length) && (save_command & 0x01)) {
 				io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
@@ -946,10 +957,10 @@
 				io_node->next = func->io_head;
 				func->io_head = io_node;
 			}
-			// Save memory base and Limit registers
-			pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_BASE, &w_base);
 
-			pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_MEMORY_LIMIT, &w_length);
+			// Save memory base and Limit registers
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);
 
 			if ((w_base <= w_length) && (save_command & 0x02)) {
 				mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
@@ -962,10 +973,10 @@
 				mem_node->next = func->mem_head;
 				func->mem_head = mem_node;
 			}
-			// Save prefetchable memory base and Limit registers
-			pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_BASE, &w_base);
 
-			pci_read_config_word_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_PREF_MEMORY_LIMIT, &w_length);
+			// Save prefetchable memory base and Limit registers
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);
 
 			if ((w_base <= w_length) && (save_command & 0x02)) {
 				p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
@@ -980,12 +991,11 @@
 			}
 			// Figure out IO and memory base lengths
 			for (cloop = 0x10; cloop <= 0x14; cloop += 4) {
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
 
 				temp_register = 0xFFFFFFFF;
-				pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
-
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base);
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
 
 				temp_register = base;
 
@@ -1046,12 +1056,11 @@
 		} else if ((header_type & 0x7F) == 0x00) {	  // Standard header
 			// Figure out IO and memory base lengths
 			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &save_base);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base);
 
 				temp_register = 0xFFFFFFFF;
-				pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
-
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base);
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
 
 				temp_register = base;
 
@@ -1138,21 +1147,26 @@
 	u32 temp;
 	u32 rc;
 	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
 
 	func = cpqhp_slot_find(func->bus, func->device, index++);
 
 	while (func != NULL) {
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
 		// Start at the top of config space so that the control
 		// registers are programmed last
 		for (cloop = 0x3C; cloop > 0; cloop -= 4) {
-			pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, func->config_space[cloop >> 2]);
+			pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]);
 		}
 
-		pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type);
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 
 		// If this is a bridge device, restore subordinate devices
 		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
-			pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SECONDARY_BUS, &secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
 
 			sub_bus = (int) secondary_bus;
 
@@ -1172,7 +1186,7 @@
 			// they are the same.  If not, the board is different.
 
 			for (cloop = 16; cloop < 40; cloop += 4) {
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &temp);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp);
 
 				if (temp != func->config_space[cloop >> 2]) {
 					dbg("Config space compare failure!!! offset = %x\n", cloop);
@@ -1212,6 +1226,8 @@
 	u32 rc;
 	struct pci_func *next;
 	int index = 0;
+	struct pci_bus *pci_bus = ctrl->pci_bus;
+	unsigned int devfn;
 
 	if (!func->is_a_board)
 		return(ADD_NOT_SUPPORTED);
@@ -1219,7 +1235,10 @@
 	func = cpqhp_slot_find(func->bus, func->device, index++);
 
 	while (func != NULL) {
-		pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_VENDOR_ID, &temp_register);
+		pci_bus->number = func->bus;
+		devfn = PCI_DEVFN(func->device, func->function);
+
+		pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register);
 
 		// No adapter present
 		if (temp_register == 0xFFFFFFFF)
@@ -1229,14 +1248,14 @@
 			return(ADAPTER_NOT_SAME);
 
 		// Check for same revision number and class code
-		pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_CLASS_REVISION, &temp_register);
+		pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register);
 
 		// Adapter not the same
 		if (temp_register != func->config_space[0x08 >> 2])
 			return(ADAPTER_NOT_SAME);
 
 		// Check for Bridge
-		pci_read_config_byte_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_HEADER_TYPE, &header_type);
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
 
 		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  // PCI-PCI Bridge
 			// In order to continue checking, we must program the
@@ -1244,7 +1263,7 @@
 			// for it's subordinate bus(es)
 
 			temp_register = func->config_space[0x18 >> 2];
-			pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, PCI_PRIMARY_BUS, temp_register);
+			pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register);
 
 			secondary_bus = (temp_register >> 8) & 0xFF;
 
@@ -1263,7 +1282,7 @@
 		// Check to see if it is a standard config header
 		else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
 			// Check subsystem vendor and ID
-			pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
+			pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
 
 			if (temp_register != func->config_space[0x2C >> 2]) {
 				// If it's a SMART-2 and the register isn't filled
@@ -1277,10 +1296,8 @@
 			// Figure out IO and memory base lengths
 			for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
 				temp_register = 0xFFFFFFFF;
-				pci_write_config_dword_nodev(ctrl->pci_ops, func->bus, func->device, func->function, cloop, temp_register);
-
-				pci_read_config_dword_nodev (ctrl->pci_ops, func->bus, func->device, func->function, cloop, &base);
-
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &base);
 				if (base) {	  // If this register is implemented
 					if (base & 0x01L) {
 						// IO base
@@ -1436,8 +1453,8 @@
 			continue;
 		}
 		// find out if this entry is for an occupied slot
-		pci_read_config_dword_nodev (ctrl->pci_ops, primary_bus, dev_func >> 3, dev_func & 0x07, PCI_VENDOR_ID, &temp_dword);
-
+		ctrl->pci_bus->number = primary_bus;
+		pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword);
 		dbg("temp_D_word = %x\n", temp_dword);
 
 		if (temp_dword != 0xFFFFFFFF) {
@@ -1586,7 +1603,7 @@
 	int rc = 0;
 	struct pci_resource *node;
 	struct pci_resource *t_node;
-	dbg(__FUNCTION__"\n");
+	dbg("%s\n", __FUNCTION__);
 
 	if (!func)
 		return(1);
diff -Nru a/drivers/hotplug/cpqphp_proc.c b/drivers/hotplug/cpqphp_proc.c
--- a/drivers/hotplug/cpqphp_proc.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/hotplug/cpqphp_proc.c	Sun Sep 15 19:20:24 2002
@@ -53,8 +53,9 @@
 	*eof = 1;
 
 	out += sprintf(out, "hot plug ctrl Info Page\n");
-	out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus,
-		       ctrl->device, ctrl->function);
+	out += sprintf(out, "bus = %d, device = %d, function = %d\n",
+		       ctrl->bus, PCI_SLOT(ctrl->pci_dev->devfn),
+		       PCI_FUNC(ctrl->pci_dev->devfn));
 	out += sprintf(out, "Free resources: memory\n");
 	index = 11;
 	res = ctrl->mem_head;
@@ -104,8 +105,9 @@
 	*eof = 1;
 
 	out += sprintf(out, "hot plug ctrl Info Page\n");
-	out += sprintf(out, "bus = %d, device = %d, function = %d\n",ctrl->bus,
-		       ctrl->device, ctrl->function);
+	out += sprintf(out, "bus = %d, device = %d, function = %d\n",
+		       ctrl->bus, PCI_SLOT(ctrl->pci_dev->devfn),
+		       PCI_FUNC(ctrl->pci_dev->devfn));
 
 	slot=ctrl->slot;
 
diff -Nru a/drivers/hotplug/ibmphp.h b/drivers/hotplug/ibmphp.h
--- a/drivers/hotplug/ibmphp.h	Sun Sep 15 19:19:29 2002
+++ b/drivers/hotplug/ibmphp.h	Sun Sep 15 19:19:29 2002
@@ -39,7 +39,8 @@
 #else
 	#define MY_NAME THIS_MODULE->name
 #endif
-#define debug(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
 #define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
 #define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
@@ -121,6 +122,7 @@
 	u8 port1_port_connect;
 	u8 port2_node_connect;
 	u8 port2_port_connect;
+	u8 chassis_num;
 //	struct list_head scal_detail_list;
 };
 
@@ -139,9 +141,27 @@
 	u8 port1_port_connect;
 	u8 first_slot_num;
 	u8 status;
-//	struct list_head rio_detail_list;
+	u8 wpindex;
+	u8 chassis_num;
+	struct list_head rio_detail_list;
 };
 
+struct opt_rio {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	struct list_head opt_rio_list;
+};	
+
+struct opt_rio_lo {
+	u8 rio_type;
+	u8 chassis_num;
+	u8 first_slot_num;
+	u8 middle_num;
+	u8 pack_count;
+	struct list_head opt_rio_lo_list;
+};	
 
 /****************************************************************
 *  HPC DESCRIPTOR NODE                                          *
@@ -153,7 +173,6 @@
 	short phys_addr;
 //      struct list_head ebda_hpc_list;
 };
-
 /*****************************************************************
 *   IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS           *
 *   STRUCTURE                                                    *
@@ -195,6 +214,9 @@
 	u8 i2c_addr;
 };
 
+#define HPC_DEVICE_ID		0x0246
+#define HPC_SUBSYSTEM_ID	0x0247
+#define HPC_PCI_OFFSET		0x40
 /*************************************************************************
 *   RSTC DESCRIPTOR NODE                                                 *
 *************************************************************************/
@@ -215,8 +237,9 @@
 	u8 rsrc_type;
 	u8 bus_num;
 	u8 dev_fun;
-	ulong start_addr;
-	ulong end_addr;
+	u32 start_addr;
+	u32 end_addr;
+	u8 marked;	/* for NVRAM */
 	struct list_head ebda_pci_rsrc_list;
 };
 
@@ -248,7 +271,7 @@
 ***********************************************************/
 extern struct list_head ibmphp_ebda_pci_rsrc_head;
 extern struct list_head ibmphp_slot_head;
-
+extern struct list_head ibmphp_res_head;
 /***********************************************************
 * FUNCTION PROTOTYPES                                      *
 ***********************************************************/
@@ -263,6 +286,7 @@
 extern struct bus_info *ibmphp_find_same_bus_num (u32);
 extern int ibmphp_get_bus_index (u8);
 extern u16 ibmphp_get_total_controllers (void);
+extern int ibmphp_register_pci (void);
 
 /* passed parameters */
 #define MEM		0
@@ -669,7 +693,7 @@
 #define PCIX66		0x05
 #define PCI66		0x04
 
-extern struct pci_ops *ibmphp_pci_root_ops;
+extern struct pci_bus *ibmphp_pci_bus;
 
 /* Variables */
 
@@ -713,6 +737,7 @@
 struct controller {
 	struct ebda_hpc_slot *slots;
 	struct ebda_hpc_bus *buses;
+	struct pci_dev *ctrl_dev; /* in case where controller is PCI */
 	u8 starting_slot_num;	/* starting and ending slot #'s this ctrl controls*/
 	u8 ending_slot_num;
 	u8 revision;
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Sun Sep 15 19:19:46 2002
+++ b/drivers/hotplug/ibmphp_core.c	Sun Sep 15 19:19:46 2002
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.3"
+#define DRIVER_VERSION	"0.6"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -56,7 +56,7 @@
 MODULE_DESCRIPTION (DRIVER_DESC);
 
 static int *ops[MAX_OPS + 1];
-struct pci_ops *ibmphp_pci_root_ops;
+struct pci_bus *ibmphp_pci_bus;
 static int max_slots;
 
 static int irqs[16];    /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */
@@ -88,6 +88,8 @@
 	slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus);
 	if (READ_BUS_MODE (slot_cur->ctrl))
 		slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus);
+	else
+		slot_cur->bus_on->current_bus_mode = 0xFF;
 
 	debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode);
 	
@@ -108,11 +110,15 @@
 
 static int __init get_max_slots (void)
 {
+	struct slot * slot_cur;
 	struct list_head * tmp;
-	int slot_count = 0;
+	u8 slot_count = 0;
 
-	list_for_each (tmp, &ibmphp_slot_head) 
-		++slot_count;
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+		/* sometimes the hot-pluggable slots start with 4 (not always from 1 */
+		slot_count = max (slot_count, slot_cur->number);
+	}
 	return slot_count;
 }
 
@@ -330,7 +336,7 @@
 			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
 			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
 			if (!hpcrc) {
-				*value = SLOT_POWER (myslot.status);
+				*value = SLOT_PWRGD (myslot.status);
 				rc = 0;
 			}
 		}
@@ -394,15 +400,22 @@
 		if (pslot) {
 			rc = 0;
 			mode = pslot->supported_bus_mode;
-			*value = pslot->supported_speed;
-			*value &= 0x0f;
-
-			if (mode == BUS_MODE_PCIX)
-				*value |= 0x80;
-			else if (mode == BUS_MODE_PCI)
-				*value |= 0x40;
-			else
-				*value |= 0x20;
+			*value = pslot->supported_speed; 
+			switch (*value) {
+			case BUS_SPEED_33:
+				break;
+			case BUS_SPEED_66:
+				if (mode == BUS_MODE_PCIX) 
+					*value += 0x01;
+				break;
+			case BUS_SPEED_100:
+			case BUS_SPEED_133:
+				*value = pslot->supported_speed + 0x01;
+				break;
+			default:
+*/				/* Note (will need to change): there would be soon 256, 512 also */
+/*				rc = -ENODEV;
+			}
 		}
 	} else
 		rc = -ENODEV;
@@ -429,14 +442,25 @@
 			if (!rc) {
 				mode = pslot->bus_on->current_bus_mode;
 				*value = pslot->bus_on->current_speed;
-				*value &= 0x0f;
-				
-				if (mode == BUS_MODE_PCIX)
-					*value |= 0x80;
-				else if (mode == BUS_MODE_PCI)
-					*value |= 0x40;
-				else
-					*value |= 0x20;	
+				switch (*value) {
+				case BUS_SPEED_33:
+					break;
+				case BUS_SPEED_66:
+					if (mode == BUS_MODE_PCIX) 
+						*value += 0x01;
+					else if (mode == BUS_MODE_PCI)
+						;
+					else
+						*value = PCI_SPEED_UNKNOWN;
+					break;
+				case BUS_SPEED_100:
+				case BUS_SPEED_133:
+					*value += 0x01;
+					break;
+				default:
+*/					/* Note of change: there would also be 256, 512 soon */
+/*					rc = -ENODEV;
+				}
 			}
 		}
 	} else
@@ -454,7 +478,7 @@
 	int hpcrc = 0;
 	struct slot myslot;
 
-	debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
 
 	if (flag)
 		ibmphp_lock_operations ();
@@ -485,17 +509,16 @@
 	if (flag)
 		ibmphp_unlock_operations ();
 
-	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
 
-static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
+static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot = NULL;
-	struct pci_dev * dev = NULL;
 
-	debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
+	debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
 
 	ibmphp_lock_operations ();
 
@@ -503,26 +526,17 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			if (pslot->func)
-				dev = pslot->func->dev;
-			else
-                		dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7));
-			if (dev) 
-				snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name);
-			else
-				snprintf (value, 100, "Bus %d", pslot->bus);
-			
-				
+			snprintf (value, 100, "Bus %x", pslot->bus);
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value);
 	return rc;
 }
-
 */
+
 /*******************************************************************************
  * This routine will initialize the ops data structure used in the validate
  * function. It will also power off empty slots that are powered on since BIOS
@@ -531,12 +545,14 @@
 static int __init init_ops (void)
 {
 	struct slot *slot_cur;
+	struct list_head *tmp;
 	int retval;
-	int j;
 	int rc;
+	int j;
 
 	for (j = 0; j < MAX_OPS; j++) {
 		ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL);
+		memset (ops[j], 0, (max_slots + 1) * sizeof (int));
 		if (!ops[j]) {
 			err ("out of system memory \n");
 			return -ENOMEM;
@@ -547,12 +563,13 @@
 	ops[REMOVE][0] = 0;
 	ops[DETAIL][0] = 0;
 
-	for (j = 1; j <= max_slots; j++) {
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
-		slot_cur = ibmphp_get_slot_from_physical_num (j);
+		if (!slot_cur)
+			return -ENODEV;
 
 		debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number);
-
 		if (slot_cur->ctrl->revision == 0xFF) 
 			if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision))
 				return -1;
@@ -572,21 +589,21 @@
 		debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status);
 		debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status));
 
-		if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/* No power, adapter, and latch closed */
-			ops[ADD][j] = 1;
+			ops[ADD][slot_cur->number] = 1;
 		else
-			ops[ADD][j] = 0;
+			ops[ADD][slot_cur->number] = 0;
 
-		ops[DETAIL][j] = 1;
+		ops[DETAIL][slot_cur->number] = 1;
 
-		if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/*Power,adapter,latch closed */
-			ops[REMOVE][j] = 1;
+			ops[REMOVE][slot_cur->number] = 1;
 		else
-			ops[REMOVE][j] = 0;
+			ops[REMOVE][slot_cur->number] = 0;
 
-		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
+		if ((SLOT_PWRGD (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
 			debug ("BEFORE POWER OFF COMMAND\n");
 				rc = power_off (slot_cur);
 				if (rc)
@@ -624,7 +641,7 @@
 	if (retval)
 		return retval;
 
-	if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[ADD][number] = 1;
 	else
@@ -632,7 +649,7 @@
 
 	ops[DETAIL][number] = 1;
 
-	if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[REMOVE][number] = 1;
 	else
@@ -678,7 +695,7 @@
 	}
         
 	snprintf (buffer, 10, "%d", slot_cur->number);
-	info->power_status = SLOT_POWER (slot_cur->status);
+	info->power_status = SLOT_PWRGD (slot_cur->status);
 	info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
 	info->latch_status = SLOT_LATCH (slot_cur->status);
         if (!SLOT_PRESENT (slot_cur->status)) {
@@ -688,8 +705,8 @@
                 info->adapter_status = 1;
 //		get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0);
 	}
-/*
-	bus_speed = slot_cur->bus_on->current_speed;
+	/* !!!!!!!!!TO DO: THIS NEEDS TO CHANGE!!!!!!!!!!!!! */
+/*	bus_speed = slot_cur->bus_on->current_speed;
 	bus_speed &= 0x0f;
                         
 	if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
@@ -701,7 +718,7 @@
 
 	info->cur_bus_speed_status = bus_speed;
 	info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status;
-	// To do: card_bus_names 
+	// To do: bus_names 
 */	
 	rc = pci_hp_change_slot_info (buffer, info);
 	kfree (info);
@@ -752,18 +769,6 @@
 	return NULL;
 }
 
-/******************************************************************
- * This function is here because we can no longer use pci_root_ops
- ******************************************************************/
-static struct pci_ops *get_root_pci_ops (void)
-{
-	struct pci_bus * bus;
-
-	if ((bus = find_bus (0)))
-		return bus->ops;
-	return NULL;
-}
-
 /*************************************************************
  * This routine frees up memory used by struct slot, including
  * the pointers to pci_func, bus, hotplug_slot, controller,
@@ -775,8 +780,10 @@
 	struct list_head * tmp;
 	struct list_head * next;
 
-	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	debug ("%s -- enter\n", __FUNCTION__);
 
+	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	
 		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
 		pci_hp_deregister (slot_cur->hotplug_slot);
@@ -795,7 +802,9 @@
 		ibmphp_unconfigure_card (&slot_cur, -1);  /* we don't want to actually remove the resources, since free_resources will do just that */
 
 		kfree (slot_cur);
+		slot_cur = NULL;
 	}
+	debug ("%s -- exit\n", __FUNCTION__);
 }
 
 static int ibm_is_pci_dev_in_use (struct pci_dev *dev)
@@ -851,7 +860,7 @@
 	if (temp_func)
 		temp_func->dev = NULL;
 	else
-		err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+		debug ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
 
 	return 0;
 }
@@ -954,8 +963,8 @@
 	}
 
 	if (temp_func->dev) {
-		pci_proc_attach_device (temp_func->dev);
-		pci_announce_device_to_drivers (temp_func->dev);
+//		pci_proc_attach_device (temp_func->dev);
+//		pci_announce_device_to_drivers (temp_func->dev);
 	}
 
 	return 0;
@@ -965,6 +974,51 @@
 	.visit_pci_dev =configure_visit_pci_dev,
 };
 
+
+/*
+ * The following function is to fix kernel bug regarding 
+ * getting bus entries, here we manually add those primary 
+ * bus entries to kernel bus structure whenever apply
+ */
+
+static u8 bus_structure_fixup (u8 busno)
+{
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	u16 l;
+
+	if (!find_bus (busno) || !(ibmphp_find_same_bus_num (busno)))
+		return 1;
+
+	bus = kmalloc (sizeof (*bus), GFP_KERNEL);
+	if (!bus) {
+		err ("%s - out of memory\n", __FUNCTION__);
+		return 1;
+	}
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev) {
+		kfree (bus);
+		err ("%s - out of memory\n", __FUNCTION__);
+		return 1;
+	}
+
+	bus->number = busno;
+	bus->ops = ibmphp_pci_bus->ops;
+	dev->bus = bus;
+	for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) {
+		if (!pci_read_config_word (dev, PCI_VENDOR_ID, &l) &&  l != 0x0000 && l != 0xffff) {
+			debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__);
+			pci_scan_bus (busno, ibmphp_pci_bus->ops, NULL);
+			break;
+		}
+	}
+
+	kfree (dev);
+	kfree (bus);
+
+	return 0;
+}
+
 static int ibm_configure_device (struct pci_func *func)
 {
 	unsigned char bus;
@@ -972,6 +1026,7 @@
 	struct pci_bus *child;
 	struct pci_dev *temp;
 	int rc = 0;
+	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
@@ -980,6 +1035,8 @@
 	memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
 	memset (&dev0, 0, sizeof (struct pci_dev));
 
+	if (!(bus_structure_fixup (func->busno)))
+		flag = 1;
 	if (func->dev == NULL)
 		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
 
@@ -995,7 +1052,7 @@
 			return 0;
 		}
 	}
-	if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+	if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
 		pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus);
 		child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus);
 		pci_do_scan_bus (child);
@@ -1028,7 +1085,7 @@
 		rc = slot_update (&tmp_slot);
 		if (rc)
 			return 0;
-		if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status))
+		if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status))
 			return 0;
 		i++;
 	}
@@ -1046,6 +1103,9 @@
 	int rc;
 	u8 speed;
 	u8 cmd = 0x0;
+	const struct list_head *tmp;
+	struct pci_dev * dev;
+	int retval;
 
 	debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number);
 	if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
@@ -1091,6 +1151,14 @@
 				cmd = HPC_BUS_100PCIXMODE;
 				break;
 			case BUS_SPEED_133:
+				/* This is to take care of the bug in CIOBX chip*/
+				list_for_each (tmp, &pci_devices) {
+					dev = (struct pci_dev *) pci_dev_g (tmp);
+					if (dev) {
+						if ((dev->vendor == 0x1166) && (dev->device == 0x0101))
+							ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE);
+					}
+				}
 				cmd = HPC_BUS_133PCIXMODE;
 				break;
 			default:
@@ -1103,9 +1171,17 @@
 			return -ENODEV;
 		}
 		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
-		ibmphp_hpc_writeslot (slot_cur, cmd);
+		retval = ibmphp_hpc_writeslot (slot_cur, cmd);
+		if (retval) {
+			err ("setting bus speed failed\n");
+			return retval;
+		}
+		if (CTLR_RESULT (slot_cur->ctrl->status)) {
+			err ("command not completed successfully in set_bus \n");
+			return -EIO;
+		}
 	}
-	/* This is for x400, once Brandon fixes the firmware, 
+	/* This is for x440, once Brandon fixes the firmware, 
 	will not need this delay */
 	long_delay (1 * HZ);
 	debug ("%s -Exit \n", __FUNCTION__);
@@ -1128,7 +1204,7 @@
 
 	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
 		tmp_slot = ibmphp_get_slot_from_physical_num (i);
-		if ((SLOT_POWER (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
+		if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
 			count++;
 	}
 	get_cur_bus_info (&slot_cur);
@@ -1384,11 +1460,15 @@
 
 	debug ("DISABLING SLOT... \n"); 
 		
-	if (slot_cur == NULL) 
+	if (slot_cur == NULL) {
+		ibmphp_unlock_operations (); 
 		return -ENODEV;
+	}
 	
-	if (slot_cur->ctrl == NULL) 
+	if (slot_cur->ctrl == NULL) {
+		ibmphp_unlock_operations ();
 		return -ENODEV;
+	}
 	
 	flag = slot_cur->flag;	/* to see if got here from polling */
 	
@@ -1463,7 +1543,8 @@
 			return -EFAULT;
 		}
 
-		ibmphp_update_slot_info (slot_cur);
+		if (flag)
+			ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
@@ -1503,10 +1584,10 @@
 	.get_attention_status =		get_attention_status,
 	.get_latch_status =		get_latch_status,
 	.get_adapter_status =		get_adapter_present,
-/*	get_max_bus_speed_status:	get_max_bus_speed,
+/*	.get_max_bus_speed_status =	get_max_bus_speed,
 	.get_max_adapter_speed_status =	get_max_adapter_speed,
 	.get_cur_bus_speed_status =	get_cur_bus_speed,
-	.get_card_bus_names_status =	get_card_bus_names,
+	.get_bus_name_status =		get_bus_name,
 */
 };
 
@@ -1526,6 +1607,7 @@
 
 static int __init ibmphp_init (void)
 {
+	struct pci_bus *bus;
 	int i = 0;
 	int rc = 0;
 
@@ -1533,12 +1615,19 @@
 
 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
-	ibmphp_pci_root_ops = get_root_pci_ops ();
-	if (ibmphp_pci_root_ops == NULL) {
-		err ("cannot read bus operations... will not be able to read the cards.  Please check your system\n");
-		return -ENODEV;	
+	ibmphp_pci_bus = kmalloc (sizeof (*ibmphp_pci_bus), GFP_KERNEL);
+	if (!ibmphp_pci_bus) {
+		err ("out of memory\n");
+		return -ENOMEM;
 	}
 
+	bus = find_bus (0);
+	if (!bus) {
+		err ("Can't find the root pci bus, can not continue\n");
+		return -ENODEV;
+	}
+	memcpy (ibmphp_pci_bus, bus, sizeof (*ibmphp_pci_bus));
+
 	ibmphp_debug = debug;
 
 	ibmphp_hpc_initvars ();
@@ -1559,6 +1648,11 @@
 	debug ("AFTER Resource & EBDA INITIALIZATIONS\n");
 
 	max_slots = get_max_slots ();
+	
+	if ((rc = ibmphp_register_pci ())) {
+		ibmphp_unload ();
+		return rc;
+	}
 
 	if (init_ops ()) {
 		ibmphp_unload ();
@@ -1570,11 +1664,9 @@
 		return -ENODEV;
 	}
 
-	/* lock ourselves into memory with a module count of -1 
-	 * so that no one can unload us. */
+	/* if no NVRAM module selected, lock ourselves into memory with a 
+	 * module count of -1 so that no one can unload us. */
 	MOD_DEC_USE_COUNT;
-
-
 	return 0;
 }
 
diff -Nru a/drivers/hotplug/ibmphp_ebda.c b/drivers/hotplug/ibmphp_ebda.c
--- a/drivers/hotplug/ibmphp_ebda.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/hotplug/ibmphp_ebda.c	Sun Sep 15 19:19:29 2002
@@ -56,11 +56,17 @@
 /* Local variables */
 static struct ebda_hpc_list *hpc_list_ptr;
 static struct ebda_rsrc_list *rsrc_list_ptr;
-static struct rio_table_hdr *rio_table_ptr;
+static struct rio_table_hdr *rio_table_ptr = NULL;
 static LIST_HEAD (ebda_hpc_head);
 static LIST_HEAD (bus_info_head);
+static LIST_HEAD (rio_vg_head);
+static LIST_HEAD (rio_lo_head);
+static LIST_HEAD (opt_vg_head);
+static LIST_HEAD (opt_lo_head);
 static void *io_mem;
 
+char *chassis_str, *rxe_str, *str;
+
 /* Local functions */
 static int ebda_rsrc_controller (void);
 static int ebda_rsrc_rsrc (void);
@@ -125,6 +131,7 @@
 	controller->slots = NULL;
 	kfree (controller->buses);
 	controller->buses = NULL;
+	controller->ctrl_dev = NULL;
 	kfree (controller);
 }
 
@@ -173,18 +180,77 @@
 	}
 }
 
-static void print_ebda_pci_rsrc (void)
+static void print_lo_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("print_lo_info ---- \n");	
+	list_for_each (ptr1, &rio_lo_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
+	}
+}
+
+static void print_vg_info (void)
+{
+	struct rio_detail *ptr;
+	struct list_head *ptr1;
+	debug ("%s --- \n", __FUNCTION__);
+	list_for_each (ptr1, &rio_vg_head) {
+		ptr = list_entry (ptr1, struct rio_detail, rio_detail_list);
+		debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id);
+		debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type);
+		debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id);
+		debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num);
+		debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex);
+		debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num);
+
+	}
+}
+
+static void __init print_ebda_pci_rsrc (void)
 {
 	struct ebda_pci_rsrc *ptr;
 	struct list_head *ptr1;
 
 	list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
 		ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
-		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
 			__FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
 	}
 }
 
+static void __init print_ibm_slot (void)
+{
+	struct slot *ptr;
+	struct list_head *ptr1;
+
+	list_for_each (ptr1, &ibmphp_slot_head) {
+		ptr = list_entry (ptr1, struct slot, ibm_slot_list);
+		debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); 
+	}
+}
+
+static void __init print_opt_vg (void)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	debug ("%s --- \n", __FUNCTION__);
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); 
+		debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); 
+		debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); 
+		debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); 
+	}
+}
+
 static void __init print_ebda_hpc (void)
 {
 	struct controller *hpc_ptr;
@@ -221,6 +287,7 @@
 			break;
 
 		case 2:
+		case 4:
 			debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
 			debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
 			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
@@ -357,31 +424,382 @@
 
 			rio_complete = 1;
 		}
+	}
 
-		if (hs_complete && rio_complete) {
-			rc = ebda_rsrc_controller ();
-			if (rc) {
-				iounmap(io_mem);
-				return rc;
-			}
-			rc = ebda_rsrc_rsrc ();
-			if (rc) {
-				iounmap(io_mem);
-				return rc;
-			}
+	if (!hs_complete && !rio_complete) {
+		iounmap (io_mem);
+		return -ENODEV;
+	}
+
+	if (rio_table_ptr) {
+		if (rio_complete == 1 && rio_table_ptr->ver_num == 3) {
 			rc = ebda_rio_table ();
 			if (rc) {
-				iounmap(io_mem);
+				iounmap (io_mem);
 				return rc;
-			}	
-			iounmap (io_mem);
-			return 0;
+			}
 		}
 	}
+	rc = ebda_rsrc_controller ();
+	if (rc) {
+		iounmap (io_mem);
+		return rc;
+	}
+
+	rc = ebda_rsrc_rsrc ();
+	if (rc) {
+		iounmap (io_mem);
+		return rc;
+	}
+
 	iounmap (io_mem);
-	return -ENODEV;
+	return 0;
+}
+
+/*
+ * map info of scalability details and rio details from physical address
+ */
+static int __init ebda_rio_table (void)
+{
+	u16 offset;
+	u8 i;
+	struct rio_detail *rio_detail_ptr;
+
+	offset = rio_table_ptr->offset;
+	offset += 12 * rio_table_ptr->scal_count;
+
+	// we do concern about rio details
+	for (i = 0; i < rio_table_ptr->riodev_count; i++) {
+		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL);
+		if (!rio_detail_ptr)
+			return -ENOMEM;
+		memset (rio_detail_ptr, 0, sizeof (struct rio_detail));
+		rio_detail_ptr->rio_node_id = readb (io_mem + offset);
+		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
+		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
+		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
+		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
+		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
+		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
+		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
+		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
+		rio_detail_ptr->status = readb (io_mem + offset + 12);
+		rio_detail_ptr->wpindex = readb (io_mem + offset + 13);
+		rio_detail_ptr->chassis_num = readb (io_mem + offset + 14);
+//		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
+		//create linked list of chassis
+		if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head);
+		//create linked list of expansion box				
+		else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) 
+			list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head);
+		else 
+			// not in my concern
+			kfree (rio_detail_ptr);
+		offset += 15;
+	}
+	print_lo_info ();
+	print_vg_info ();
+	return 0;
+}
+
+/*
+ * reorganizing linked list of chassis	 
+ */
+static struct opt_rio *search_opt_vg (u8 chassis_num)
+{
+	struct opt_rio *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_vg_head) {
+		ptr = list_entry (ptr1, struct opt_rio, opt_rio_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int __init combine_wpg_for_chassis (void)
+{
+	struct opt_rio *opt_rio_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_vg_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num);
+		if (!opt_rio_ptr) {
+			opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL);
+			if (!opt_rio_ptr)
+				return -ENOMEM;
+			memset (opt_rio_ptr, 0, sizeof (struct opt_rio));
+			opt_rio_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head);
+		} else {	
+			opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num);
+		}	
+	}
+	print_opt_vg ();
+	return 0;	
+}	
+
+/*
+ * reorgnizing linked list of expansion box	 
+ */
+static struct opt_rio_lo *search_opt_lo (u8 chassis_num)
+{
+	struct opt_rio_lo *ptr;
+	struct list_head *ptr1;
+	list_for_each (ptr1, &opt_lo_head) {
+		ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list);
+		if (ptr->chassis_num == chassis_num)
+			return ptr;
+	}		
+	return NULL;
+}
+
+static int combine_wpg_for_expansion (void)
+{
+	struct opt_rio_lo *opt_rio_lo_ptr = NULL;
+	struct rio_detail *rio_detail_ptr = NULL;
+	struct list_head *list_head_ptr = NULL;
+	
+	list_for_each (list_head_ptr, &rio_lo_head) {
+		rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list);
+		opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num);
+		if (!opt_rio_lo_ptr) {
+			opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL);
+			if (!opt_rio_lo_ptr)
+				return -ENOMEM;
+			memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo));
+			opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type;
+			opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num;
+			opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num;
+			opt_rio_lo_ptr->pack_count = 1;
+			
+			list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head);
+		} else {	
+			opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num);
+			opt_rio_lo_ptr->pack_count = 2;
+		}	
+	}
+	return 0;	
+}
+	
+static char *convert_2digits_to_char (int var)
+{
+	int bit;	
+	char *str1;
+
+	str = (char *) kmalloc (3, GFP_KERNEL);
+	memset (str, 0, 3);
+	str1 = (char *) kmalloc (2, GFP_KERNEL);
+	memset (str, 0, 3);
+	bit = (int)(var / 10);
+	switch (bit) {
+	case 0:
+		//one digit number
+		*str = (char)(var + 48);
+		return str;
+	default: 	
+		//2 digits number
+		*str1 = (char)(bit + 48);
+		strncpy (str, str1, 1);
+		memset (str1, 0, 3);
+		*str1 = (char)((var % 10) + 48);
+		strcat (str, str1);
+		return str;
+	}	
+	return NULL;	
+}
+
+/* Since we don't know the max slot number per each chassis, hence go
+ * through the list of all chassis to find out the range
+ * Arguments: slot_num, 1st slot number of the chassis we think we are on, 
+ * var (0 = chassis, 1 = expansion box) 
+ */
+static int first_slot_num (u8 slot_num, u8 first_slot, u8 var)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	struct list_head *ptr = NULL;
+	int rc = 0;
+
+	if (!var) {
+		list_for_each (ptr, &opt_vg_head) {
+			opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+			if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { 
+				rc = -ENODEV;
+				break;
+			}
+		}
+	} else {
+		list_for_each (ptr, &opt_lo_head) {
+			opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+			if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) {
+				rc = -ENODEV;
+				break;
+			}
+		}
+	}
+	return rc;
+}
+
+static struct opt_rio_lo * find_rxe_num (u8 slot_num)
+{
+	struct opt_rio_lo *opt_lo_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_lo_head) {
+		opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list);
+		//check to see if this slot_num belongs to expansion box
+		if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) 
+			return opt_lo_ptr;
+	}
+	return NULL;
 }
 
+static struct opt_rio * find_chassis_num (u8 slot_num)
+{
+	struct opt_rio *opt_vg_ptr;
+	struct list_head *ptr;
+
+	list_for_each (ptr, &opt_vg_head) {
+		opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list);
+		//check to see if this slot_num belongs to chassis 
+		if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) 
+			return opt_vg_ptr;
+	}
+	return NULL;
+}
+
+/* This routine will find out how many slots are in the chassis, so that
+ * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc
+ */
+static u8 calculate_first_slot (u8 slot_num)
+{
+	u8 first_slot = 1;
+	struct list_head * list;
+	struct slot * slot_cur;
+	
+	list_for_each (list, &ibmphp_slot_head) {
+		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+		if (slot_cur->ctrl) {
+			if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) 
+				first_slot = slot_cur->ctrl->ending_slot_num;
+		}
+	}			
+	return first_slot + 1;
+
+}
+static char *create_file_name (struct slot * slot_cur)
+{
+	struct opt_rio *opt_vg_ptr = NULL;
+	struct opt_rio_lo *opt_lo_ptr = NULL;
+	char *ptr_chassis_num, *ptr_rxe_num, *ptr_slot_num;
+	int which = 0; /* rxe = 1, chassis = 0 */
+	u8 number = 1; /* either chassis or rxe # */
+	u8 first_slot = 1;
+	u8 slot_num;
+	u8 flag = 0;
+
+	if (!slot_cur) {
+		err ("Structure passed is empty \n");
+		return NULL;
+	}
+	
+	slot_num = slot_cur->number;
+
+	chassis_str = (char *) kmalloc (30, GFP_KERNEL);
+	memset (chassis_str, 0, 30);
+	rxe_str = (char *) kmalloc (30, GFP_KERNEL);
+	memset (rxe_str, 0, 30);
+	ptr_chassis_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_chassis_num, 0, 3);
+	ptr_rxe_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_rxe_num, 0, 3);
+	ptr_slot_num = (char *) kmalloc (3, GFP_KERNEL);
+	memset (ptr_slot_num, 0, 3);
+	
+	strcpy (chassis_str, "chassis");
+	strcpy (rxe_str, "rxe");
+	
+	if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			opt_vg_ptr = find_chassis_num (slot_num);
+			opt_lo_ptr = find_rxe_num (slot_num);
+		}
+	}
+	if (opt_vg_ptr) {
+		if (opt_lo_ptr) {
+			if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) {
+				number = opt_lo_ptr->chassis_num;
+				first_slot = opt_lo_ptr->first_slot_num;
+				which = 1; /* it is RXE */
+			} else {
+				first_slot = opt_vg_ptr->first_slot_num;
+				number = opt_vg_ptr->chassis_num;
+				which = 0;
+			}
+		} else {
+			first_slot = opt_vg_ptr->first_slot_num;
+			number = opt_vg_ptr->chassis_num;
+			which = 0;
+		}
+		++flag;
+	} else if (opt_lo_ptr) {
+		number = opt_lo_ptr->chassis_num;
+		first_slot = opt_lo_ptr->first_slot_num;
+		which = 1;
+		++flag;
+	} else if (rio_table_ptr) {
+		if (rio_table_ptr->ver_num == 3) {
+			/* if both NULL and we DO have correct RIO table in BIOS */
+			return NULL;
+		}
+	} 
+	if (!flag) {
+		if (slot_cur->ctrl->ctlr_type == 4) {
+			first_slot = calculate_first_slot (slot_num);
+			which = 1;
+		} else {
+			which = 0;
+		}
+	}
+
+	switch (which) {
+	case 0:
+		/* Chassis */
+		*ptr_chassis_num = (char)(number + 48);
+		strcat (chassis_str, ptr_chassis_num);
+		kfree (ptr_chassis_num);
+		strcat (chassis_str, "slot");
+		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
+		strcat (chassis_str, ptr_slot_num);
+		kfree (ptr_slot_num);
+		return chassis_str;
+		break;
+	case 1:
+		/* RXE */
+		*ptr_rxe_num = (char)(number + 48);
+		strcat (rxe_str, ptr_rxe_num);
+		kfree (ptr_rxe_num);
+		strcat (rxe_str, "slot");
+		ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
+		strcat (rxe_str, ptr_slot_num);
+		kfree (ptr_slot_num);
+		return rxe_str;
+		break;
+	}	
+	return NULL;
+}
+
+static struct pci_driver ibmphp_driver;
 
 /*
  * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
@@ -400,6 +818,9 @@
 	struct ebda_hpc_slot *slot_ptr;
 	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
 	int rc;
+	int retval;
+	struct slot *slot_cur;
+	struct list_head *list;
 
 	addr = hpc_list_ptr->phys_addr;
 	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
@@ -510,23 +931,22 @@
 				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
 				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
 				hpc_ptr->irq = readb (io_mem + addr + 2);
-				addr += 3; 
+				addr += 3;
+				debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", hpc_ptr->u.pci_ctlr.bus, hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
 				break;
 
 			case 0:
 				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
 				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
+				retval = check_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1));
+				if (retval)
+					return -ENODEV;
+				request_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), "ibmphp");
 				hpc_ptr->irq = readb (io_mem + addr + 4);
 				addr += 5;
 				break;
 
 			case 2:
-				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
-				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
-
-				hpc_ptr->irq = readb (io_mem + addr + 5);
-				addr += 6;
-				break;
 			case 4:
 				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
 				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
@@ -537,12 +957,10 @@
 				iounmap (io_mem);
 				return -ENODEV;
 		}
-		/* following 3 line: Now our driver only supports I2c ctlrType */
-		if ((hpc_ptr->ctlr_type != 2) && (hpc_ptr->ctlr_type != 4)) {
-			err ("Please run this driver on ibm xseries440\n ");
-			return -ENODEV;
-		}
 
+		//reorganize chassis' linked list
+		combine_wpg_for_chassis ();
+		combine_wpg_for_expansion ();
 		hpc_ptr->revision = 0xff;
 		hpc_ptr->options = 0xff;
 		hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num;
@@ -566,7 +984,7 @@
 			}
 			memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info));
 
-			hp_slot_ptr->name = (char *) kmalloc (10, GFP_KERNEL);
+			hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL);
 			if (!hp_slot_ptr->name) {
 				iounmap (io_mem);
 				kfree (hp_slot_ptr->info);
@@ -583,9 +1001,7 @@
 				return -ENOMEM;
 			}
 
-
 			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
-			snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num);
 
 			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
 			if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
@@ -617,7 +1033,6 @@
 			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
 			
 			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
-
 			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
 			if (rc) {
 				iounmap (io_mem);
@@ -631,8 +1046,6 @@
 			}
 			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
 
-			pci_hp_register (hp_slot_ptr);
-
 			// end of registering ibm slot with hotplug core
 
 			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
@@ -642,7 +1055,20 @@
 		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
 
 	}			/* each hpc  */
+
+	list_for_each (list, &ibmphp_slot_head) {
+		slot_cur = list_entry (list, struct slot, ibm_slot_list);
+
+		snprintf (slot_cur->hotplug_slot->name, 30, "%s", create_file_name (slot_cur));
+		if (chassis_str) 
+			kfree (chassis_str);
+		if (rxe_str)
+			kfree (rxe_str);
+		pci_hp_register (slot_cur->hotplug_slot);
+	}
+
 	print_ebda_hpc ();
+	print_ibm_slot ();
 	return 0;
 }
 
@@ -682,7 +1108,7 @@
 			addr += 6;
 
 			debug ("rsrc from io type ----\n");
-			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n",
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n",
 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
 
 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
@@ -703,7 +1129,7 @@
 			addr += 10;
 
 			debug ("rsrc from mem or pfm ---\n");
-			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", 
 				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
 
 			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
@@ -715,56 +1141,6 @@
 	return 0;
 }
 
-/*
- * map info of scalability details and rio details from physical address
- */
-static int __init ebda_rio_table(void)
-{
-	u16 offset;
-	u8 i;
-	struct scal_detail *scal_detail_ptr;
-	struct rio_detail *rio_detail_ptr;
-
-	offset = rio_table_ptr->offset;
-	for (i = 0; i < rio_table_ptr->scal_count; i++) {
-		
-		scal_detail_ptr = kmalloc (sizeof (struct scal_detail), GFP_KERNEL );
-		if (!scal_detail_ptr )
-			return -ENOMEM;
-		memset (scal_detail_ptr, 0, sizeof (struct scal_detail) );
-		scal_detail_ptr->node_id = readb (io_mem + offset);
-		scal_detail_ptr->cbar = readl (io_mem+ offset + 1);
-		scal_detail_ptr->port0_node_connect = readb (io_mem + 5);
-		scal_detail_ptr->port0_port_connect = readb (io_mem + 6);
-		scal_detail_ptr->port1_node_connect = readb (io_mem + 7);
-		scal_detail_ptr->port1_port_connect = readb (io_mem + 8);
-		scal_detail_ptr->port2_node_connect = readb (io_mem + 9);
-		scal_detail_ptr->port2_port_connect = readb (io_mem + 10);
-		debug ("node_id: %x\ncbar: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nport2_node: %x\nport2_port: %x\n", scal_detail_ptr->node_id, scal_detail_ptr->cbar, scal_detail_ptr->port0_node_connect, scal_detail_ptr->port0_port_connect, scal_detail_ptr->port1_node_connect, scal_detail_ptr->port1_port_connect, scal_detail_ptr->port2_node_connect, scal_detail_ptr->port2_port_connect);
-//		list_add (&scal_detail_ptr->scal_detail_list, &scal_detail_head);
-		offset += 11;
-	}
-	for (i=0; i < rio_table_ptr->riodev_count; i++) {
-		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL );
-		if (!rio_detail_ptr )
-			return -ENOMEM;
-		memset (rio_detail_ptr, 0, sizeof (struct rio_detail) );
-		rio_detail_ptr->rio_node_id = readb (io_mem + offset );
-		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
-		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
-		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
-		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
-		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
-		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
-		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
-		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
-		rio_detail_ptr->status = readb (io_mem + offset + 12);
-		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
-		offset += 13;
-	}
-	return 0;
-}
-
 u16 ibmphp_get_total_controllers (void)
 {
 	return hpc_list_ptr->num_ctlrs;
@@ -830,32 +1206,21 @@
 	}
 }
 
-/*
- * Calculate the total hot pluggable slots controlled by total hpcs
- */
-/*
-int ibmphp_get_total_hp_slots (void)
-{
-	struct ebda_hpc *ptr;
-	int slot_num = 0;
-
-	ptr = ebda_hpc_head;
-	while (ptr != NULL) {
-		slot_num += ptr->slot_count;
-		ptr = ptr->next;
-	}
-	return slot_num;
-}
-*/
-
 void ibmphp_free_ebda_hpc_queue (void)
 {
-	struct controller *controller;
+	struct controller *controller = NULL;
 	struct list_head *list;
 	struct list_head *next;
+	int pci_flag = 0;
 
 	list_for_each_safe (list, next, &ebda_hpc_head) {
 		controller = list_entry (list, struct controller, ebda_hpc_list);
+		if (controller->ctlr_type == 0)
+			release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1));
+		else if ((controller->ctlr_type == 1) && (!pci_flag)) {
+			++pci_flag;
+			pci_unregister_driver (&ibmphp_driver);
+		}
 		free_ebda_hpc (controller);
 	}
 }
@@ -871,5 +1236,60 @@
 		kfree (resource);
 		resource = NULL;
 	}
+}
+
+static struct pci_device_id id_table[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_IBM,
+		device:		HPC_DEVICE_ID,
+		subvendor:	PCI_VENDOR_ID_IBM,
+		subdevice:	HPC_SUBSYSTEM_ID,
+		class:		((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00),
+	}, {}
+};		
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *);
+static struct pci_driver ibmphp_driver = {
+	name:		"ibmphp",
+	id_table:	id_table,
+	probe:		ibmphp_probe,
+};
+
+int ibmphp_register_pci (void)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+	int rc = 0;
+
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			rc = pci_module_init (&ibmphp_driver);
+			break;
+		}
+	}
+	return rc;
+}
+static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids)
+{
+	struct controller *ctrl;
+	struct list_head *tmp;
+
+	debug ("inside ibmphp_probe \n");
+	
+	list_for_each (tmp, &ebda_hpc_head) {
+		ctrl = list_entry (tmp, struct controller, ebda_hpc_list);
+		if (ctrl->ctlr_type == 1) {
+			if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) {
+				ctrl->ctrl_dev = dev;
+				debug ("found device!!! \n");
+				debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device);
+				return 0;
+			}
+		}
+	}
+	return -ENODEV;
 }
 
diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c
--- a/drivers/hotplug/ibmphp_hpc.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/hotplug/ibmphp_hpc.c	Sun Sep 15 19:19:29 2002
@@ -107,8 +107,8 @@
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
-static u8 ctrl_read (struct controller *, void *, u8);
-static u8 ctrl_write (struct controller *, void *, u8, u8);
+static u8 i2c_ctrl_read (struct controller *, void *, u8);
+static u8 i2c_ctrl_write (struct controller *, void *, u8, u8);
 static u8 hpc_writecmdtoindex (u8, u8);
 static u8 hpc_readcmdtoindex (u8, u8);
 static void get_hpc_access (void);
@@ -142,12 +142,12 @@
 }
 
 /*----------------------------------------------------------------------
-* Name:    ctrl_read
+* Name:    i2c_ctrl_read
 *
 * Action:  read from HPC over I2C
 *
 *---------------------------------------------------------------------*/
-static u8 ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index)
+static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index)
 {
 	u8 status;
 	int i;
@@ -249,13 +249,13 @@
 }
 
 /*----------------------------------------------------------------------
-* Name:    ctrl_write
+* Name:    i2c_ctrl_write
 *
 * Action:  write to HPC over I2C
 *
 * Return   0 or error codes
 *---------------------------------------------------------------------*/
-static u8 ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd)
+static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd)
 {
 	u8 rc;
 	void *wpg_addr;		// base addr + offset
@@ -351,6 +351,93 @@
 	return (rc);
 }
 
+//------------------------------------------------------------
+//  Read from ISA type HPC 
+//------------------------------------------------------------
+static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset)
+{
+	u16 start_address;
+	u16 end_address;
+	u8 data;
+
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	end_address = ctlr_ptr->u.isa_ctlr.io_end;
+	data = inb (start_address + offset);
+	return data;
+}
+
+//--------------------------------------------------------------
+// Write to ISA type HPC
+//--------------------------------------------------------------
+static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data)
+{
+	u16 start_address;
+	u16 port_address;
+	
+	start_address = ctlr_ptr->u.isa_ctlr.io_start;
+	port_address = start_address + (u16) offset;
+	outb (data, port_address);
+}
+
+static u8 pci_ctrl_read (struct controller *ctrl, u8 offset)
+{
+	u8 data = 0x00;
+	debug ("inside pci_ctrl_read\n");
+	if (ctrl->ctrl_dev)
+		pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data);
+	return data;
+}
+
+static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data)
+{
+	u8 rc = -ENODEV;
+	debug ("inside pci_ctrl_write\n");
+	if (ctrl->ctrl_dev) {
+		pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data);
+		rc = 0;
+	}
+	return rc;
+}
+
+static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset)
+{
+	u8 rc;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		rc = isa_ctrl_read (ctlr, offset);
+		break;
+	case 1:
+		rc = pci_ctrl_read (ctlr, offset);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_read (ctlr, base, offset);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data)
+{
+	u8 rc = 0;
+	switch (ctlr->ctlr_type) {
+	case 0:
+		isa_ctrl_write(ctlr, offset, data);
+		break;
+	case 1:
+		rc = pci_ctrl_write (ctlr, offset, data);
+		break;
+	case 2:
+	case 4:
+		rc = i2c_ctrl_write(ctlr, base, offset, data);
+		break;
+	default:
+		return -ENODEV;
+	}
+	return rc;
+}
 /*----------------------------------------------------------------------
 * Name:    hpc_writecmdtoindex()
 *
@@ -449,7 +536,7 @@
 *---------------------------------------------------------------------*/
 int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus)
 {
-	void *wpg_bbar;
+	void *wpg_bbar = NULL;
 	struct controller *ctlr_ptr;
 	struct list_head *pslotlist;
 	u8 index, status;
@@ -491,7 +578,8 @@
 	//--------------------------------------------------------------------
 	// map physical address to logical address
 	//--------------------------------------------------------------------
-	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
 
 	//--------------------------------------------------------------------
 	// check controller status before reading
@@ -569,7 +657,11 @@
 	//--------------------------------------------------------------------
 	// cleanup
 	//--------------------------------------------------------------------
-	iounmap (wpg_bbar);	// remove physical to logical address mapping
+	
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);	
+	
 	free_hpc_access ();
 
 	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
@@ -583,7 +675,7 @@
 *---------------------------------------------------------------------*/
 int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd)
 {
-	void *wpg_bbar;
+	void *wpg_bbar = NULL;
 	struct controller *ctlr_ptr;
 	u8 index, status;
 	int busindex;
@@ -626,12 +718,13 @@
 	//--------------------------------------------------------------------
 	// map physical address to logical address
 	//--------------------------------------------------------------------
-	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) {
+		wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
 
-	debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
+		debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
 		ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar,
 		ctlr_ptr->u.wpeg_ctlr.i2c_addr);
-
+	}
 	//--------------------------------------------------------------------
 	// check controller status before writing
 	//--------------------------------------------------------------------
@@ -668,7 +761,10 @@
 		ctlr_ptr->status = status;
 	}
 	// cleanup
-	iounmap (wpg_bbar);	// remove physical to logical address mapping
+
+	// remove physical to logical address mapping
+	if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4))
+		iounmap (wpg_bbar);	
 	free_hpc_access ();
 
 	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
@@ -701,6 +797,7 @@
 void ibmphp_lock_operations (void)
 {
 	down (&semOperations);
+	to_debug = TRUE;
 }
 
 /*----------------------------------------------------------------------
@@ -710,6 +807,7 @@
 {
 	debug ("%s - Entry\n", __FUNCTION__);
 	up (&semOperations);
+	to_debug = FALSE;
 	debug ("%s - Exit\n", __FUNCTION__);
 }
 
@@ -734,82 +832,86 @@
 	debug ("%s - Entry\n", __FUNCTION__);
 
 	while (!ibmphp_shutdown) {
+		if (ibmphp_shutdown) 
+			break;
+		
 		/* try to get the lock to do some kind of harware access */
 		down (&semOperations);
 
 		switch (poll_state) {
-			case POLL_LATCH_REGISTER:
-				oldlatchlow = curlatchlow;
-				ctrl_count = 0x00;
-				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (ctrl_count >= ibmphp_get_total_controllers())
-						break;
-					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
-					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-						ctrl_count++;
-						if (READ_SLOT_LATCH (pslot->ctrl)) {
-							rc = ibmphp_hpc_readslot (pslot,
-										  READ_SLOTLATCHLOWREG,
-										  &curlatchlow);
-							if (oldlatchlow != curlatchlow)
-								process_changeinlatch (oldlatchlow,
-										       curlatchlow,
-										       pslot->ctrl);
-						}
+		case POLL_LATCH_REGISTER: 
+			oldlatchlow = curlatchlow;
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl)) {
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
+						if (oldlatchlow != curlatchlow)
+							process_changeinlatch (oldlatchlow,
+									       curlatchlow,
+									       pslot->ctrl);
 					}
 				}
-				poll_state = POLL_SLOTS;
-				break;
-
-			case POLL_SLOTS:
-				list_for_each (pslotlist, &ibmphp_slot_head) {
-					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
-					// make a copy of the old status
-					memcpy ((void *) &myslot, (void *) pslot,
-						sizeof (struct slot));
-					rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
-					if ((myslot.status != pslot->status)
-					    || (myslot.ext_status != pslot->ext_status))
-						process_changeinstatus (pslot, &myslot);
+			}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLOTS:
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				// make a copy of the old status
+				memcpy ((void *) &myslot, (void *) pslot,
+					sizeof (struct slot));
+				rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+				if ((myslot.status != pslot->status)
+				    || (myslot.ext_status != pslot->ext_status))
+					process_changeinstatus (pslot, &myslot);
+			}
+			ctrl_count = 0x00;
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				if (ctrl_count >= ibmphp_get_total_controllers())
+					break;
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+					ctrl_count++;
+					if (READ_SLOT_LATCH (pslot->ctrl))
+						rc = ibmphp_hpc_readslot (pslot,
+									  READ_SLOTLATCHLOWREG,
+									  &curlatchlow);
 				}
+			}
+			++poll_count;
+			poll_state = POLL_SLEEP;
+			break;
+		case POLL_SLEEP:
+			/* don't sleep with a lock on the hardware */
+			up (&semOperations);
+			long_delay (POLL_INTERVAL_SEC * HZ);
 
-				ctrl_count = 0x00;
-				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (ctrl_count >= ibmphp_get_total_controllers())
-						break;
-					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
-					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-						ctrl_count++;
-						if (READ_SLOT_LATCH (pslot->ctrl))
-							rc = ibmphp_hpc_readslot (pslot,
-										  READ_SLOTLATCHLOWREG,
-										  &curlatchlow);
-					}
-				}
-				++poll_count;
-				if (poll_count >= POLL_LATCH_CNT) {
-					poll_count = 0;
-					poll_state = POLL_SLEEP;
-				}
+			if (ibmphp_shutdown) 
 				break;
-
-			case POLL_SLEEP:
-				/* don't sleep with a lock on the hardware */
-				up (&semOperations);
-				long_delay (POLL_INTERVAL_SEC * HZ);
-				down (&semOperations);
+			
+			down (&semOperations);
+			
+			if (poll_count >= POLL_LATCH_CNT) {
+				poll_count = 0;
+				poll_state = POLL_SLOTS;
+			} else
 				poll_state = POLL_LATCH_REGISTER;
-				break;
-		}
-
+			break;
+		}	
 		/* give up the harware semaphore */
 		up (&semOperations);
-
 		/* sleep for a short time just for good measure */
 		set_current_state (TASK_INTERRUPTIBLE);
 		schedule_timeout (HZ/10);
 	}
-
 	up (&sem_exit);
 	debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -1070,15 +1172,23 @@
 	debug ("%s - Entry\n", __FUNCTION__);
 
 	ibmphp_shutdown = TRUE;
+	debug ("before locking operations \n");
 	ibmphp_lock_operations ();
-
+	debug ("after locking operations \n");
+	
 	// wait for poll thread to exit
+	debug ("before sem_exit down \n");
 	down (&sem_exit);
+	debug ("after sem_exit down \n");
 
 	// cleanup
+	debug ("before free_hpc_access \n");
 	free_hpc_access ();
+	debug ("after free_hpc_access \n");
 	ibmphp_unlock_operations ();
+	debug ("after unlock operations \n");
 	up (&sem_exit);
+	debug ("after sem exit up\n");
 
 	debug ("%s - Exit\n", __FUNCTION__);
 }
diff -Nru a/drivers/hotplug/ibmphp_pci.c b/drivers/hotplug/ibmphp_pci.c
--- a/drivers/hotplug/ibmphp_pci.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/hotplug/ibmphp_pci.c	Sun Sep 15 19:19:28 2002
@@ -104,11 +104,15 @@
 
 	/* For every function on the card */
 	for (function = 0x00; function < 0x08; function++) {
+		unsigned int devfn = PCI_DEVFN(device, function);
+		ibmphp_pci_bus->number = cur_func->busno;
+
 		cur_func->function = function;
 
-		debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", cur_func->busno, device, function);
+		debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n",
+			cur_func->busno, cur_func->device, cur_func->function);
 
-		pci_read_config_word_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_VENDOR_ID, &vendor_id);
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
 
 		debug ("vendor_id is %x\n", vendor_id);
 		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
@@ -122,8 +126,8 @@
 			 *         |_=> 0 = single function device, 1 = multi-function device
 			 */
 
-			pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_HEADER_TYPE, &hdr_type);
-			pci_read_config_dword_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_CLASS_REVISION, &class);
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
 
 			class_code = class >> 24;
 			debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code);
@@ -195,7 +199,7 @@
 						goto error;
 					}
 
-					pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
 					flag = FALSE;
 					for (i = 0; i < 32; i++) {
 						if (func->devices[i]) {
@@ -267,8 +271,9 @@
 						cleanup_count = 2;
 						goto error;
 					}
-					debug ("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function);
-					pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+					debug ("cur_func->busno = %x, device = %x, function = %x\n",
+						cur_func->busno, device, function);
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
 					debug ("after configuring bridge..., sec_number = %x\n", sec_number);
 					flag = FALSE;
 					for (i = 0; i < 32; i++) {
@@ -361,13 +366,12 @@
 	struct resource_node *mem[6];
 	struct resource_node *mem_tmp;
 	struct resource_node *pfmem[6];
-	u8 device;
-	u8 function;
+	unsigned int devfn;
 
 	debug ("%s - inside\n", __FUNCTION__);
 
-	device = func->device;
-	function = func->function;
+	devfn = PCI_DEVFN(func->device, func->function);
+	ibmphp_pci_bus->number = func->busno;
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
 
@@ -384,8 +388,8 @@
 			pcibios_write_config_dword(cur_func->busno, cur_func->device, 
 			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF);
 		 */
-		pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 
 		if (!bar[count])	/* This BAR is not implemented */
 			continue;
@@ -421,11 +425,11 @@
 				kfree (io[count]);
 				return -EIO;
 			}
-			pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start);
+			pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
 	
 			/* _______________This is for debugging purposes only_____________________ */ 
 			debug ("b4 writing, the IO address is %x\n", func->io[count]->start);
-			pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 			debug ("after writing.... the start address is %x\n", bar[count]);
 			/* _________________________________________________________________________*/
 
@@ -484,11 +488,11 @@
 					}
 				}
 
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
 
-				/*_______________This if for debugging purposes only______________________________*/				
+				/*_______________This is for debugging purposes only______________________________*/				
 				debug ("b4 writing, start addres is %x\n", func->pfmem[count]->start);
-				pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 				debug ("after writing, start address is %x\n", bar[count]);
 				/*_________________________________________________________________________________*/
 
@@ -496,7 +500,7 @@
 					debug ("inside the mem 64 case, count %d\n", count);
 					count += 1;
 					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
-					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
 				}
 			} else {
 				/* regular memory */
@@ -526,10 +530,10 @@
 					kfree (mem[count]);
 					return -EIO;
 				}
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
 				/* _______________________This is for debugging purposes only _______________________*/
 				debug ("b4 writing, start address is %x\n", func->mem[count]->start);
-				pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 				debug ("after writing, the address is %x\n", bar[count]);
 				/* __________________________________________________________________________________*/
 
@@ -538,22 +542,22 @@
 					debug ("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
 					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
-					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
 				}
 			}
 		}		/* end of mem */
 	}			/* end of for */
 
 	func->bus = 0;		/* To indicate that this is not a PPB */
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
 	if ((irq > 0x00) && (irq < 0x05))
-		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
 
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE);
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
 
-	pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_ROM_ADDRESS, 0x00L);
-	pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE);
+	pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L);
+	pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
 
 	return 0;
 }
@@ -593,24 +597,23 @@
 		0
 	};
 	struct pci_func *func = *func_passed;
-	u8 function;
-	u8 device;
+	unsigned int devfn;
 	u8 irq;
 	int retval;
 
 	debug ("%s - enter\n", __FUNCTION__);
 
-	function = func->function;
-	device = func->device;
+	devfn = PCI_DEVFN(func->function, func->device);
+	ibmphp_pci_bus->number = func->busno;
 
 	/* Configuring necessary info for the bridge so that we could see the devices
 	 * behind it
 	 */
 
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, func->busno);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno);
 
 	/* _____________________For debugging purposes only __________________________
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, &pri_number);
+	pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
 	debug ("primary # written into the bridge is %x\n", pri_number);
 	 ___________________________________________________________________________*/
 
@@ -624,23 +627,23 @@
 	debug ("after find_sec_number, the number we got is %x\n", sec_number);
 	debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno);
 
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, sec_number);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number);
 	
 	/* __________________For debugging purposes only __________________________________
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
 	debug ("sec_number after write/read is %x\n", sec_number);
 	 ________________________________________________________________________________*/
 
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, sec_number);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number);
 
 	/* __________________For debugging purposes only ____________________________________
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, &sec_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number);
 	debug ("subordinate number after write/read is %x\n", sec_number);
 	 __________________________________________________________________________________*/
 
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE);
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY);
-	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SEC_LATENCY_TIMER, LATENCY);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY);
+	pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY);
 
 	debug ("func->busno is %x\n", func->busno);
 	debug ("sec_number after writing is %x\n", sec_number);
@@ -653,8 +656,8 @@
 
 	/* First we need to allocate mem/io for the bridge itself in case it needs it */
 	for (count = 0; address[count]; count++) {	/* for 2 BARs */
-		pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 
 		if (!bar[count]) {
 			/* This BAR is not implemented */
@@ -694,7 +697,7 @@
 				return -EIO;
 			}
 
-			pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start);
+			pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start);
 
 		} else {
 			/* This is Memory */
@@ -747,13 +750,13 @@
 					}
 				}
 
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start);
 
 				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
 					count += 1;
 					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
-					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
 
 				}
 			} else {
@@ -784,13 +787,13 @@
 					return -EIO;
 				}
 
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start);
 
 				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
 					count += 1;
 					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
-					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000);
 
 				}
 			}
@@ -802,6 +805,7 @@
 	if (amount_needed == NULL)
 		return -ENOMEM;
 
+	ibmphp_pci_bus->number = func->busno;
 	debug ("after coming back from scan_behind_bridge\n");
 	debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct);
 	debug ("amount_needed->io = %x\n", amount_needed->io);
@@ -920,16 +924,30 @@
 	debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem);
 
 	if (flag_io && flag_mem && flag_pfmem) {
-		bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+		/* If on bootup, there was a bridged card in this slot,
+		 * then card was removed and ibmphp got unloaded and loaded
+		 * back again, there's no way for us to remove the bus
+		 * struct, so no need to kmalloc, can use existing node
+		 */
+		bus = ibmphp_find_res_bus (sec_number);
 		if (!bus) {
-			err ("out of system memory \n");
-			retval = -ENOMEM;
+			bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+			if (!bus) {
+				err ("out of system memory \n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (bus, 0, sizeof (struct bus_node));
+			bus->busno = sec_number;
+			debug ("b4 adding new bus\n");
+			rc = add_new_bus (bus, io, mem, pfmem, func->busno);
+		} else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem))
+			rc = add_new_bus (bus, io, mem, pfmem, 0xFF);
+		else {
+			err ("expected bus structure not empty? \n");
+			retval = -EIO;
 			goto error;
 		}
-		memset (bus, 0, sizeof (struct bus_node));
-		bus->busno = sec_number;
-		debug ("b4 adding new bus\n");
-		rc = add_new_bus (bus, io, mem, pfmem, func->busno);
 		if (rc) {
 			if (rc == -ENOMEM) {
 				ibmphp_remove_bus (bus, func->busno);
@@ -938,8 +956,8 @@
 			retval = rc;
 			goto error;
 		}
-		pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &io_base);
-		pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &pfmem_base);
+		pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base);
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base);
 
 		if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
 			debug ("io 32\n");
@@ -951,73 +969,73 @@
 		}
 
 		if (bus->noIORanges) {
-			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8);
-			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8);	
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8);	
 
 			/* _______________This is for debugging purposes only ____________________
-			pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &temp);
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp);
 			debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
-			pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, &temp);
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp);
 			debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
 			 ________________________________________________________________________*/
 
 			if (need_io_upper) {	/* since can't support n.e.ways */
-				pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE_UPPER16, 0x0000);
-				pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT_UPPER16, 0x0000);
+				pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000);
+				pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000);
 			}
 		} else {
-			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00);
-			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00);
 		}
 
 		if (bus->noMemRanges) {
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16);
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16);
 			
 			/* ____________________This is for debugging purposes only ________________________
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, &temp);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp);
 			debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, &temp);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp);
 			debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
 			 __________________________________________________________________________________*/
 
 		} else {
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0xffff);
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000);
 		}
 		if (bus->noPFMemRanges) {
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16);
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16);
 
 			/* __________________________This is for debugging purposes only _______________________
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &temp);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp);
 			debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, &temp);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp);
 			debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
 			 ______________________________________________________________________________________*/
 
 			if (need_pfmem_upper) {	/* since can't support n.e.ways */
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_BASE_UPPER32, 0x00000000);
-				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_LIMIT_UPPER32, 0x00000000);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000);
+				pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000);
 			}
 		} else {
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0xffff);
-			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff);
+			pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000);
 		}
 
 		debug ("b4 writing control information\n");
 
-		pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq);
+		pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq);
 		if ((irq > 0x00) && (irq < 0x05))
-			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+			pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
 		/*    
-		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, ctrl);
-		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY);
-		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY);
+		pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
 		 */
 
-		pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE);
-		pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, 0x07);
+		pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE);
+		pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07);
 		for (i = 0; i < 32; i++) {
 			if (amount_needed->devices[i]) {
 				debug ("device where devices[i] is 1 = %x\n", i);
@@ -1073,6 +1091,7 @@
 	u16 vendor_id;
 	u8 hdr_type;
 	u8 device, function;
+	unsigned int devfn;
 	int howmany = 0;	/*this is to see if there are any devices behind the bridge */
 
 	u32 bar[6], class;
@@ -1092,20 +1111,23 @@
 		return NULL;
 	memset (amount, 0, sizeof (struct res_needed));
 
+	ibmphp_pci_bus->number = busno;
+
 	debug ("the bus_no behind the bridge is %x\n", busno);
 	debug ("scanning devices behind the bridge...\n");
 	for (device = 0; device < 32; device++) {
 		amount->devices[device] = 0;
 		for (function = 0; function < 8; function++) {
+			devfn = PCI_DEVFN(device, function);
 
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
 
 			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
 				/* found correct device!!! */
 				howmany++;
 
-				pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
-				pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class);
+				pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+				pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
 
 				debug ("hdr_type behind the bridge is %x\n", hdr_type);
 				if (hdr_type & PCI_HEADER_TYPE_BRIDGE) {
@@ -1132,14 +1154,14 @@
 				for (count = 0; address[count]; count++) {
 					/* for 6 BARs */
 					/*
-					pci_read_config_byte_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], &tmp);
+					pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp);
 					if (tmp & 0x01) // IO
-						pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFD);
+						pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD);
 					else // MEMORY
-						pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
+						pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
 					*/
-					pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
-					pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &bar[count]);
+					pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+					pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]);
 
 					debug ("what is bar[count]? %x, count = %d\n", bar[count], count);
 
@@ -1223,6 +1245,7 @@
 	u32 temp_end;
 	u32 size;
 	u32 tmp_address;
+	unsigned int devfn;
 
 	debug ("%s - enter\n", __FUNCTION__);
 
@@ -1232,14 +1255,16 @@
 		return -EINVAL;
 	}
 
+	devfn = PCI_DEVFN(device, function);
+	ibmphp_pci_bus->number = busno;
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address);
 
 		/* We can do this here, b/c by that time the device driver of the card has been stopped */
 
-		pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &size);
-		pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], start_address);
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size);
+		pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address);
 
 		debug ("start_address is %x\n", start_address);
 		debug ("busno, device, function %x %x %x\n", busno, device, function);
@@ -1336,13 +1361,16 @@
 		PCI_BASE_ADDRESS_1,
 		0
 	};
+	unsigned int devfn;
 
+	devfn = PCI_DEVFN(device, function);
+	ibmphp_pci_bus->number = busno;
 	bus_no = (int) busno;
 	debug ("busno is %x\n", busno);
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PRIMARY_BUS, &pri_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number);
 	debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number);
 
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
 	debug ("sec_number is %x\n", sec_number);
 	sec_no = (int) sec_number;
 	pri_no = (int) pri_number;
@@ -1351,10 +1379,10 @@
 		return -EINVAL;
 	}
 
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number);
 	sec_no = (int) sec_no;
 
-	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SUBORDINATE_BUS, &sub_number);
+	pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number);
 	sub_no = (int) sub_number;
 	debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no);
 	if (sec_no != sub_number) {
@@ -1374,7 +1402,7 @@
 
 	for (count = 0; address[count]; count++) {
 		/* for 2 BARs */
-		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address);
+		pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address);
 
 		if (!start_address) {
 			/* This BAR is not implemented */
@@ -1447,6 +1475,7 @@
 	u8 busno;
 	u8 function;
 	int rc;
+	unsigned int devfn;
 	u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */
 
 	debug ("%s - enter\n", __FUNCTION__);
@@ -1457,8 +1486,10 @@
 	debug ("b4 for loop, device is %x\n", device);
 	/* For every function on the card */
 	for (function = 0x0; function < 0x08; function++) {
+		devfn = PCI_DEVFN(device, function);
+		ibmphp_pci_bus->number = busno;
 
-		pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+		pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
 
 		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
 			/* found correct device!!! */
@@ -1471,8 +1502,8 @@
 			 *         |_=> 0 = single function device, 1 = multi-function device
 			 */
 
-			pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
-			pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class);
+			pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
+			pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
 
 			debug ("hdr_type %x, class %x\n", hdr_type, class);
 			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
@@ -1579,7 +1610,6 @@
 	}
 
 	if (sl->func) {
-		debug ("do we come in here? \n");
 		cur_func = sl->func;
 		while (cur_func) {
 			/* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */
@@ -1619,6 +1649,7 @@
 
 	sl->func = NULL;
 	*slot_cur = sl;
+	debug ("%s - exit\n", __FUNCTION__);
 	return 0;
 }
 
@@ -1638,14 +1669,15 @@
 	struct bus_node *cur_bus = NULL;
 
 	/* Trying to find the parent bus number */
-	cur_bus	= ibmphp_find_res_bus (parent_busno);
-	if (!cur_bus) {
-		err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
-		return -ENODEV;
+	if (parent_busno != 0xFF) {
+		cur_bus	= ibmphp_find_res_bus (parent_busno);
+		if (!cur_bus) {
+			err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
+			return -ENODEV;
+		}
+	
+		list_add (&bus->bus_list, &cur_bus->bus_list);
 	}
-
-	list_add (&bus->bus_list, &cur_bus->bus_list);
-
 	if (io) {
 		io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
 		if (!io_range) {
@@ -1698,6 +1730,7 @@
 	int min, max;
 	u8 busno;
 	struct bus_info *bus;
+	struct bus_node *bus_cur;
 
 	bus = ibmphp_find_same_bus_num (primary_busno);
 	if (!bus) {
@@ -1712,7 +1745,12 @@
 	}
 	busno = (u8) (slotno - (u8) min);
 	busno += primary_busno + 0x01;
-	if (!ibmphp_find_res_bus (busno))
+	bus_cur = ibmphp_find_res_bus (busno);
+	/* either there is no such bus number, or there are no ranges, which
+	 * can only happen if we removed the bridged device in previous load
+	 * of the driver, and now only have the skeleton bus struct
+	 */
+	if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem)))
 		return busno;
 	return 0xff;
 }
diff -Nru a/drivers/hotplug/ibmphp_res.c b/drivers/hotplug/ibmphp_res.c
--- a/drivers/hotplug/ibmphp_res.c	Sun Sep 15 19:20:22 2002
+++ b/drivers/hotplug/ibmphp_res.c	Sun Sep 15 19:20:22 2002
@@ -45,11 +45,17 @@
 static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
 
 static LIST_HEAD(gbuses);
+LIST_HEAD(ibmphp_res_head);
 
-static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr)
+static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag)
 {
 	struct bus_node * newbus;
 
+	if (!(curr) && !(flag)) {
+		err ("NULL pointer passed \n");
+		return NULL;
+	}
+
 	newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
 	if (!newbus) {
 		err ("out of system memory \n");
@@ -57,14 +63,24 @@
 	}
 
 	memset (newbus, 0, sizeof (struct bus_node));
-	newbus->busno = curr->bus_num;
+	if (flag)
+		newbus->busno = busno;
+	else
+		newbus->busno = curr->bus_num;
 	list_add_tail (&newbus->bus_list, &gbuses);
 	return newbus;
 }
 
 static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
 {
-	struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+	struct resource_node *rs;
+	
+	if (!curr) {
+		err ("NULL passed to allocate \n");
+		return NULL;
+	}
+
+	rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
 	if (!rs) {
 		err ("out of system memory \n");
 		return NULL;
@@ -299,7 +315,7 @@
 				 * actually appears...
 				 */
 				if (ibmphp_add_resource (new_mem) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstMem = new_mem;
@@ -316,7 +332,7 @@
 				new_pfmem->type = PFMEM;
 				new_pfmem->fromMem = FALSE;
 				if (ibmphp_add_resource (new_pfmem) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstPFMem = new_pfmem;
@@ -340,7 +356,7 @@
 				 * range actually appears...
 				 */
 				if (ibmphp_add_resource (new_io) < 0) {
-					newbus = alloc_error_bus (curr);
+					newbus = alloc_error_bus (curr, 0, 0);
 					if (!newbus)
 						return -ENOMEM;
 					newbus->firstIO = new_io;
@@ -352,8 +368,6 @@
 		}
 	}
 
-	debug ("after the while loop in rsrc_init \n");
-
 	list_for_each (tmp, &gbuses) {
 		bus_cur = list_entry (tmp, struct bus_node, bus_list);
 		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
@@ -361,11 +375,9 @@
 		if (rc)
 			return rc;
 	}
-	debug ("b4 once_over in rsrc_init \n");
 	rc = once_over ();  /* This is to align ranges (so no -1) */
 	if (rc)
 		return rc;
-	debug ("after once_over in rsrc_init \n");
 	return 0;
 }
 
@@ -580,7 +592,7 @@
  * based on their resource type and sorted by their starting addresses.  It assigns
  * the ptrs to next and nextRange if needed.
  *
- * Input: 3 diff. resources (nulled out if not needed)
+ * Input: resource ptr
  * Output: ptrs assigned (to the node)
  * 0 or -1
  *******************************************************************************/
@@ -593,12 +605,17 @@
 	struct resource_node *res_start = NULL;
 
 	debug ("%s - enter\n", __FUNCTION__);
+
+	if (!res) {
+		err ("NULL passed to add \n");
+		return -ENODEV;
+	}
 	
 	bus_cur = find_bus_wprev (res->busno, NULL, 0);
 	
 	if (!bus_cur) {
 		/* didn't find a bus, smth's wrong!!! */
-		err ("no bus in the system, either pci_dev's wrong or allocation failed\n");
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
 		return -ENODEV;
 	}
 
@@ -769,6 +786,11 @@
 	struct resource_node *mem_cur;
 	char * type = "";
 
+	if (!res)  {
+		err ("resource to remove is NULL \n");
+		return -ENODEV;
+	}
+
 	bus_cur = find_bus_wprev (res->busno, NULL, 0);
 
 	if (!bus_cur) {
@@ -797,7 +819,6 @@
 	res_prev = NULL;
 
 	while (res_cur) {
-		/* ???????????DO WE _NEED_ TO BE CHECKING FOR END AS WELL?????????? */
 		if ((res_cur->start == res->start) && (res_cur->end == res->end))
 			break;
 		res_prev = res_cur;
@@ -981,7 +1002,7 @@
 
 	if (!bus_cur) {
 		/* didn't find a bus, smth's wrong!!! */
-		err ("no bus in the system, either pci_dev's wrong or allocation failed \n");
+		debug ("no bus in the system, either pci_dev's wrong or allocation failed \n");
 		return -EINVAL;
 	}
 
@@ -1340,7 +1361,7 @@
 	prev_bus = find_bus_wprev (parent_busno, NULL, 0);	
 
 	if (!prev_bus) {
-		err ("something terribly wrong. Cannot find parent bus to the one to remove\n");
+		debug ("something terribly wrong. Cannot find parent bus to the one to remove\n");
 		return -ENODEV;
 	}
 
@@ -1467,13 +1488,18 @@
 
 /*
  * find the resource node in the bus 
- * Input: Resource needed, start address of the resource, type or resource
+ * Input: Resource needed, start address of the resource, type of resource
  */
 int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
 {
 	struct resource_node *res_cur = NULL;
 	char * type = "";
 
+	if (!bus) {
+		err ("The bus passed in NULL to find resource \n");
+		return -ENODEV;
+	}
+
 	switch (flag) {
 		case IO:
 			res_cur = bus->firstIO;
@@ -1514,11 +1540,11 @@
 				res_cur = res_cur->next;
 			}
 			if (!res_cur) {
-				err ("SOS...cannot find %s resource in the bus. \n", type);
+				debug ("SOS...cannot find %s resource in the bus. \n", type);
 				return -EINVAL;
 			}
 		} else {
-			err ("SOS... cannot find %s resource in the bus. \n", type);
+			debug ("SOS... cannot find %s resource in the bus. \n", type);
 			return -EINVAL;
 		}
 	}
@@ -1756,6 +1782,8 @@
 	struct range_node *range;
 	struct resource_node *res;
 	struct list_head *tmp;
+	
+	debug_pci ("*****************START**********************\n");
 
 	if ((!list_empty(&gbuses)) && flags) {
 		err ("The GBUSES is not NULL?!?!?!?!?\n");
@@ -1764,50 +1792,50 @@
 
 	list_for_each (tmp, &gbuses) {
 		bus_cur = list_entry (tmp, struct bus_node, bus_list);
-		debug ("This is bus # %d.  There are \n", bus_cur->busno);
-		debug ("IORanges = %d\t", bus_cur->noIORanges);
-		debug ("MemRanges = %d\t", bus_cur->noMemRanges);
-		debug ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
-		debug ("The IO Ranges are as follows:\n");
+		debug_pci ("This is bus # %d.  There are \n", bus_cur->busno);
+		debug_pci ("IORanges = %d\t", bus_cur->noIORanges);
+		debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges);
+		debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
+		debug_pci ("The IO Ranges are as follows:\n");
 		if (bus_cur->rangeIO) {
 			range = bus_cur->rangeIO;
 			for (i = 0; i < bus_cur->noIORanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The Mem Ranges are as follows:\n");
+		debug_pci ("The Mem Ranges are as follows:\n");
 		if (bus_cur->rangeMem) {
 			range = bus_cur->rangeMem;
 			for (i = 0; i < bus_cur->noMemRanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The PFMem Ranges are as follows:\n");
+		debug_pci ("The PFMem Ranges are as follows:\n");
 
 		if (bus_cur->rangePFMem) {
 			range = bus_cur->rangePFMem;
 			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
-				debug ("rangeno is %d\n", range->rangeno);
-				debug ("[%x - %x]\n", range->start, range->end);
+				debug_pci ("rangeno is %d\n", range->rangeno);
+				debug_pci ("[%x - %x]\n", range->start, range->end);
 				range = range->next;
 			}
 		}
 
-		debug ("The resources on this bus are as follows\n");
+		debug_pci ("The resources on this bus are as follows\n");
 
-		debug ("IO...\n");
+		debug_pci ("IO...\n");
 		if (bus_cur->firstIO) {
 			res = bus_cur->firstIO;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1816,13 +1844,13 @@
 					break;
 			}
 		}
-		debug ("Mem...\n");
+		debug_pci ("Mem...\n");
 		if (bus_cur->firstMem) {
 			res = bus_cur->firstMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1831,13 +1859,13 @@
 					break;
 			}
 		}
-		debug ("PFMem...\n");
+		debug_pci ("PFMem...\n");
 		if (bus_cur->firstPFMem) {
 			res = bus_cur->firstPFMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				if (res->next)
 					res = res->next;
 				else if (res->nextRange)
@@ -1847,23 +1875,53 @@
 			}
 		}
 
-		debug ("PFMemFromMem...\n");
+		debug_pci ("PFMemFromMem...\n");
 		if (bus_cur->firstPFMemFromMem) {
 			res = bus_cur->firstPFMemFromMem;
 			while (res) {
-				debug ("The range # is %d\n", res->rangeno);
-				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
-				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				debug_pci ("The range # is %d\n", res->rangeno);
+				debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
 				res = res->next;
 			}
 		}
 	}
+	debug_pci ("***********************END***********************\n");
+}
+
+int static range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type)
+{
+	struct range_node * range_cur = NULL;
+	switch (type) {
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			break;
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			break;
+		default:
+			err ("wrong type passed to find out if range already exists \n");
+			return -ENODEV;
+	}
+
+	while (range_cur) {
+		if ((range_cur->start == range->start) && (range_cur->end == range->end))
+			return 1;
+		range_cur = range_cur->next;
+	}
+	
+	return 0;
 }
 
 /* This routine will read the windows for any PPB we have and update the
  * range info for the secondary bus, and will also input this info into
  * primary bus, since BIOS doesn't. This is for PPB that are in the system
- * on bootup
+ * on bootup.  For bridged cards that were added during previous load of the
+ * driver, only the ranges and the bus structure are added, the devices are
+ * added from NVRAM
  * Input: primary busno
  * Returns: none
  * Note: this function doesn't take into account IO restrictions etc,
@@ -1874,7 +1932,7 @@
  */
 static int __init update_bridge_ranges (struct bus_node **bus)
 {
-	u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
+	u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address;
 	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
 	u32 start_address, end_address, upper_start, upper_end;
 	struct bus_node *bus_sec;
@@ -1883,19 +1941,24 @@
 	struct resource_node *mem;
 	struct resource_node *pfmem;
 	struct range_node *range;
+	unsigned int devfn;
+
 	bus_cur = *bus;
-	busno = bus_cur->busno;
+	if (!bus_cur)
+		return -ENODEV;
+	ibmphp_pci_bus->number = bus_cur->busno;
 
 	debug ("inside %s \n", __FUNCTION__);
 	debug ("bus_cur->busno = %x\n", bus_cur->busno);
 
 	for (device = 0; device < 32; device++) {
 		for (function = 0x00; function < 0x08; function++) {
-			pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+			devfn = PCI_DEVFN(device, function);
+			pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
 
 			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
 				/* found correct device!!! */
-				pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
+				pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
 
 				switch (hdr_type) {
 					case PCI_HEADER_TYPE_NORMAL:
@@ -1914,21 +1977,25 @@
 						   temp++;
 						   }
 						 */
-						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_busno);
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno);
 						bus_sec = find_bus_wprev (sec_busno, NULL, 0); 
-						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE, &start_io_address);
-						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT, &end_io_address);
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE_UPPER16, &upper_io_start);
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT_UPPER16, &upper_io_end);
+						/* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */
+						if (!bus_sec) {
+							bus_sec = alloc_error_bus (NULL, sec_busno, 1);
+							/* the rest will be populated during NVRAM call */
+							return 0;
+						}
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address);
+						pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end);
 						start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8;
 						start_address |= (upper_io_start << 16);
 						end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8;
 						end_address |= (upper_io_end << 16);
 
 						if ((start_address) && (start_address <= end_address)) {
-
 							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
-
 							if (!range) {
 								err ("out of system memory \n");
 								return -ENOMEM;
@@ -1937,36 +2004,42 @@
 							range->start = start_address;
 							range->end = end_address + 0xfff;
 
-							if (bus_sec->noIORanges > 0) 
-								add_range (IO, range, bus_sec);
-							else {
+							if (bus_sec->noIORanges > 0) {
+								if (!range_exists_already (range, bus_sec, IO)) {
+									add_range (IO, range, bus_sec);
+									++bus_sec->noIORanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st IO Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangeIO = range;
+								++bus_sec->noIORanges;
 							}
-
-							++bus_sec->noIORanges;
 							fix_resources (bus_sec);
-						
-							io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
-							if (!io) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
-							}
-							memset (io, 0, sizeof (struct resource_node));
-							io->type = IO;
-							io->busno = bus_cur->busno;
-							io->devfunc = ((device << 3) | (function & 0x7));
-							io->start = start_address;
-							io->end = end_address + 0xfff;
-							io->len = io->end - io->start + 1;
 
-							ibmphp_add_resource (io);
-						}
+							if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) {
+								io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
+								if (!io) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (io, 0, sizeof (struct resource_node));
+								io->type = IO;
+								io->busno = bus_cur->busno;
+								io->devfunc = ((device << 3) | (function & 0x7));
+								io->start = start_address;
+								io->end = end_address + 0xfff;
+								io->len = io->end - io->start + 1;
+								ibmphp_add_resource (io);
+							}
+						}	
 
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_BASE, &start_mem_address);
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_LIMIT, &end_mem_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address);
 
 						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
 						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
@@ -1982,36 +2055,44 @@
 							range->start = start_address;
 							range->end = end_address + 0xfffff;
 
-							if (bus_sec->noMemRanges > 0) 
-								add_range (MEM, range, bus_sec);
-							else {
+							if (bus_sec->noMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, MEM)) {
+									add_range (MEM, range, bus_sec);
+									++bus_sec->noMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st Mem Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangeMem = range;
+								++bus_sec->noMemRanges;
 							}
 
-							++bus_sec->noMemRanges;
 							fix_resources (bus_sec);
 
-							mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
-							if (!mem) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
+							if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) {
+								mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!mem) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (mem, 0, sizeof (struct resource_node));
+								mem->type = MEM;
+								mem->busno = bus_cur->busno;
+								mem->devfunc = ((device << 3) | (function & 0x7));
+								mem->start = start_address;
+								mem->end = end_address + 0xfffff;
+								mem->len = mem->end - mem->start + 1;
+								ibmphp_add_resource (mem);
 							}
-							memset (mem, 0, sizeof (struct resource_node));
-							mem->type = MEM;
-							mem->busno = bus_cur->busno;
-							mem->devfunc = ((device << 3) | (function & 0x7));
-							mem->start = start_address;
-							mem->end = end_address + 0xfffff;
-							mem->len = mem->end - mem->start + 1;
-							ibmphp_add_resource (mem);
 						}
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_BASE, &start_mem_address);
-						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
-						pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_BASE_UPPER32, &upper_start);
-						pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_LIMIT_UPPER32, &upper_end);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address);
+						pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
+						pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start);
+						pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end);
 						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
 						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
 #if BITS_PER_LONG == 64
@@ -2030,32 +2111,40 @@
 							range->start = start_address;
 							range->end = end_address + 0xfffff;
 
-							if (bus_sec->noPFMemRanges > 0)
-								add_range (PFMEM, range, bus_sec);
-							else {
+							if (bus_sec->noPFMemRanges > 0) {
+								if (!range_exists_already (range, bus_sec, PFMEM)) {
+									add_range (PFMEM, range, bus_sec);
+									++bus_sec->noPFMemRanges;
+								} else {
+									kfree (range);
+									range = NULL;
+								}
+							} else {
 								/* 1st PFMem Range on the bus */
 								range->rangeno = 1;
 								bus_sec->rangePFMem = range;
+								++bus_sec->noPFMemRanges;
 							}
 
-							++bus_sec->noPFMemRanges;
 							fix_resources (bus_sec);
+							if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) {
+								pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+								if (!pfmem) {
+									kfree (range);
+									err ("out of system memory \n");
+									return -ENOMEM;
+								}
+								memset (pfmem, 0, sizeof (struct resource_node));
+								pfmem->type = PFMEM;
+								pfmem->busno = bus_cur->busno;
+								pfmem->devfunc = ((device << 3) | (function & 0x7));
+								pfmem->start = start_address;
+								pfmem->end = end_address + 0xfffff;
+								pfmem->len = pfmem->end - pfmem->start + 1;
+								pfmem->fromMem = FALSE;
 
-							pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
-							if (!pfmem) {
-								kfree (range);
-								err ("out of system memory \n");
-								return -ENOMEM;
+								ibmphp_add_resource (pfmem);
 							}
-							memset (pfmem, 0, sizeof (struct resource_node));
-							pfmem->type = PFMEM;
-							pfmem->busno = bus_cur->busno;
-							pfmem->devfunc = ((device << 3) | (function & 0x7));
-							pfmem->start = start_address;
-							pfmem->end = end_address + 0xfffff;
-							pfmem->len = pfmem->end - pfmem->start + 1;
-							pfmem->fromMem = FALSE;
-							ibmphp_add_resource (pfmem);
 						}
 						break;
 				}	/* end of switch */
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Sun Sep 15 19:19:34 2002
+++ b/drivers/hotplug/pci_hotplug.h	Sun Sep 15 19:19:34 2002
@@ -141,20 +141,5 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
-extern int pci_read_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u8 *val);
-extern int pci_read_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u16 *val);
-extern int pci_read_config_dword_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u32 *val);
-
-extern int pci_write_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u8 val);
-extern int pci_write_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u16 val);
-extern int pci_write_config_dword_nodev	(struct pci_ops *ops, u8 bus, u8 device,
-					 u8 function, int where, u32 val);
-
-
 #endif
 
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Sun Sep 15 19:19:29 2002
+++ b/drivers/ide/Config.in	Sun Sep 15 19:19:29 2002
@@ -9,6 +9,8 @@
 dep_tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE $CONFIG_IDE
 comment 'Please see Documentation/ide.txt for help/info on IDE drives'
 if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
+   dep_bool '  Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE $CONFIG_X86
+   define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_IDE
 
    dep_tristate '  Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
@@ -27,12 +29,13 @@
 
    dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
-   dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+   dep_mbool '    Reduce media failure retries support' CONFIG_BLK_DEV_IDECD_BAILOUT $CONFIG_BLK_DEV_IDECD
+   #dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
    dep_tristate '  SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE $CONFIG_SCSI
 
    bool '  IDE Taskfile Access' CONFIG_IDE_TASK_IOCTL
-#   bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
+   #bool '  IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO
 
    comment 'IDE chipset support/bugfixes'
    if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
@@ -40,9 +43,9 @@
       dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
       dep_bool '  ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
       if [ "$CONFIG_PCI" = "y" ]; then
-	 dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-	 define_bool CONFIG_BLK_DEV_IDEPCI y
+	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    dep_bool '    Orphan Chipset Support' CONFIG_BLK_DEV_GENERIC $CONFIG_BLK_DEV_IDEPCI
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
@@ -51,16 +54,17 @@
             dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
 	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+#           dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
+            define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
+
 	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
 	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
 	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    CMD64X chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
+	    dep_mbool '      AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX
+	    dep_bool '    CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
   	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
@@ -68,26 +72,27 @@
 	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
 	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
 	    fi
 	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
 	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	    fi
-	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
+	    dep_bool '    nVidia NFORCE support' CONFIG_BLK_DEV_NFORCE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-	    dep_bool '    Pacific Digital ADMA100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
+#	    dep_bool '    Pacific Digital ADMA100 basic support' CONFIG_BLK_DEV_ADMA100 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    PROMISE PDC202{46|62|65|67} support' CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFI_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_bool '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
 	    dep_bool '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-	       bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	       dep_bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEPCI
 	    fi
          fi
       fi
@@ -139,20 +144,22 @@
 		 EXT_DIRECT	CONFIG_IDE_EXT_DIRECT"	8xx_PCCARD
       fi
 
-      bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS
+      # no isa -> no vlb
+      dep_bool '  Other IDE chipset support' CONFIG_IDE_CHIPSETS $CONFIG_ISA
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
 	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-	 fi
-	 bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
-	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+	 dep_tristate '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278 $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 $CONFIG_BLK_DEV_IDEDISK $CONFIG_EXPERIMENTAL
+	 dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672 $CONFIG_BLK_DEV_IDE
       fi
    fi
+else
+   bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
+   define_bool CONFIG_BLK_DEV_HD $CONFIG_BLK_DEV_HD_ONLY
 fi
 
 if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
@@ -175,7 +182,26 @@
   define_bool CONFIG_DMA_NONPCI n
 fi
 
-if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+   if [ "$CONFIG_BLK_DEV_PDC202XX_OLD" != "n" -o \
+        "$CONFIG_BLK_DEV_PDC202XX_NEW" != "n" ]; then
+      define_bool CONFIG_BLK_DEV_PDC202XX y
+   fi
+fi
+
+##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then
+##  dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK
+##else
+##  dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK
+##fi
+
+if [ "$CONFIG_BLK_DEV_4DRIVES" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI14XX" != "n" -o \
+     "$CONFIG_BLK_DEV_DTC2278" != "n" -o \
+     "$CONFIG_BLK_DEV_HT6560B" != "n" -o \
+     "$CONFIG_BLK_DEV_PDC4030" != "n" -o \
+     "$CONFIG_BLK_DEV_QD65XX" != "n" -o \
+     "$CONFIG_BLK_DEV_UMC8672" != "n" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
@@ -186,19 +212,26 @@
      "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
      "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" -o \
+     "$CONFIG_BLK_DEV_NFORCE" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
      "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
-     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
+     "$CONFIG_BLK_DEV_SIIMAGE" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
-     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \
-     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
    define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
 fi
+
+#dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
+#dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+#dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Sun Sep 15 19:19:46 2002
+++ b/drivers/ide/Makefile	Sun Sep 15 19:19:46 2002
@@ -7,61 +7,36 @@
 # Note : at this point, these files are compiled on all systems.
 # In the future, some of these should be built conditionally.
 #
-export-objs		:= ide-taskfile.o ide.o ide-probe.o
+export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o
 
-obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o ide-probe-mod.o
-obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
-obj-$(CONFIG_BLK_DEV_IDEDISK)   += ide-disk.o
-obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
-obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
-
-obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
-
-ide-obj-$(CONFIG_BLK_DEV_ADMA100)	+= adma100.o
-ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI15X3)	+= alim15x3.o
-ide-obj-$(CONFIG_BLK_DEV_AMD74XX)	+= amd74xx.o
-ide-obj-$(CONFIG_BLK_DEV_BUDDHA)	+= buddha.o
-ide-obj-$(CONFIG_BLK_DEV_CMD640)	+= cmd640.o
-ide-obj-$(CONFIG_BLK_DEV_CMD64X)	+= cmd64x.o
-ide-obj-$(CONFIG_BLK_DEV_CS5530)	+= cs5530.o
-ide-obj-$(CONFIG_BLK_DEV_CY82C693)	+= cy82c693.o
-ide-obj-$(CONFIG_BLK_DEV_DTC2278)	+= dtc2278.o
-ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
-ide-obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
-ide-obj-$(CONFIG_BLK_DEV_Q40IDE)	+= q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HPT34X)	+= hpt34x.o
-ide-obj-$(CONFIG_BLK_DEV_HPT366)	+= hpt366.o
-ide-obj-$(CONFIG_BLK_DEV_HT6560B)	+= ht6560b.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
-ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
-ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_SWARM)	+= ide-swarm.o
-ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
-ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
-ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
-ide-obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
-ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
-ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
-ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
-ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
-ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
-ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
-ide-obj-$(CONFIG_BLK_DEV_SLC90E66)	+= slc90e66.o
-ide-obj-$(CONFIG_BLK_DEV_SL82C105)	+= sl82c105.o
-ide-obj-$(CONFIG_BLK_DEV_TRM290)	+= trm290.o
-ide-obj-$(CONFIG_BLK_DEV_UMC8672)	+= umc8672.o
-ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)	+= via82cxxx.o
+all-subdirs	:= arm legacy pci ppc
+mod-subdirs	:= arm legacy pci ppc
 
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
+obj-y		:=
+obj-m		:=
+ide-obj-y	:=
 
-ide-mod-objs		:= ide-taskfile.o ide.o $(ide-obj-y)
-ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
+subdir-$(CONFIG_BLK_DEV_IDEPCI)	+= pci
+subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm pci
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o
+obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
+
+obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
+
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
+
+obj-$(CONFIG_BLK_DEV_IDEPCI)		+= setup-pci.o
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= pci/idedriver-pci.o
+  obj-y		+= legacy/idedriver-legacy.o
+  obj-y		+= ppc/idedriver-ppc.o
+  obj-y		+= arm/idedriver-arm.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/adma100.c b/drivers/ide/adma100.c
--- a/drivers/ide/adma100.c	Sun Sep 15 19:19:30 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- *  linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards
- *
- *     Created 09 Apr 2002 by Mark Lord
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void __init ide_init_adma100 (ide_hwif_t *hwif)
-{
-	u32  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
-	void *v_admctl;
-
-	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
-	hwif->dma_base = 0;		// disable DMA completely
-	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
-	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
-	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
-	iounmap(v_admctl);				// all done; unmap config regs
-}
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Sun Sep 15 19:20:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,670 +0,0 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.11	March 27, 2002
- *
- * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_AEC62XX_TIMINGS
-
-#ifndef HIGH_4
-#define HIGH_4(H)		((H)=(H>>4))
-#endif
-#ifndef LOW_4
-#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
-#endif
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-#ifndef MAKE_WORD
-#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
-#endif
-
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec62xx_get_info(char *, char **, off_t, int);
-extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-#define AEC_MAX_DEVS		5
-
-static struct pci_dev *aec_devs[AEC_MAX_DEVS];
-static int n_aec_devs;
-
-#undef DEBUG_AEC_REGS
-
-static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	char *chipset_nums[] = {"error", "error", "error", "error",
-				"error", "error", "850UF",   "860",
-				 "860R",   "865",  "865R", "error"  };
-//	char *modes_33[] = {};
-//	char *modes_34[] = {};
-	int i;
-
-	for (i = 0; i < n_aec_devs; i++) {
-		struct pci_dev *dev	= aec_devs[i];
-	//	u32 iobase		= dev->resource[4].start;
-		u32 iobase		= pci_resource_start(dev, 4);
-		u8 c0			= inb_p(iobase + 0x02);
-		u8 c1			= inb_p(iobase + 0x0a);
-		u8 art			= 0;
-#ifdef DEBUG_AEC_REGS
-		u8 uart			= 0;
-#endif /* DEBUG_AEC_REGS */
-
-		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
-
-		p += sprintf(p, "--------------- Primary Channel "
-				"---------------- Secondary Channel "
-				"-------------\n");
-		(void) pci_read_config_byte(dev, 0x4a, &art);
-		p += sprintf(p, "                %sabled ",
-			(art&0x02)?" en":"dis");
-		p += sprintf(p, "                        %sabled\n",
-			(art&0x04)?" en":"dis");
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"-------- drive0 ---------- drive1 ------\n");
-		p += sprintf(p, "DMA enabled:    %s              %s ",
-			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
-		p += sprintf(p, "            %s               %s\n",
-			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-
-		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-			(void) pci_read_config_byte(dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0");
-			p += sprintf(p, "          %s(%s)",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0");
-			p += sprintf(p, "         %s(%s)",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0");
-			p += sprintf(p, "           %s(%s)\n",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-#ifdef DEBUG_AEC_REGS
-			(void) pci_read_config_byte(dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-#endif /* DEBUG_AEC_REGS */
-		} else {
-			/*
-			 * case PCI_DEVICE_ID_ARTOP_ATP860:
-			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
-			 * case PCI_DEVICE_ID_ARTOP_ATP865:
-			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
-			 */
-			(void) pci_read_config_byte(dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x07)==0x07)?"6":
-				((art&0x06)==0x06)?"5":
-				((art&0x05)==0x05)?"4":
-				((art&0x04)==0x04)?"3":
-				((art&0x03)==0x03)?"2":
-				((art&0x02)==0x02)?"1":
-				((art&0x01)==0x01)?"0":"?");
-			p += sprintf(p, "          %s(%s)",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x70)==0x70)?"6":
-				((art&0x60)==0x60)?"5":
-				((art&0x50)==0x50)?"4":
-				((art&0x40)==0x40)?"3":
-				((art&0x30)==0x30)?"2":
-				((art&0x20)==0x20)?"1":
-				((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x07)==0x07)?"6":
-				((art&0x06)==0x06)?"5":
-				((art&0x05)==0x05)?"4":
-				((art&0x04)==0x04)?"3":
-				((art&0x03)==0x03)?"2":
-				((art&0x02)==0x02)?"1":
-				((art&0x01)==0x01)?"0":"?");
-			p += sprintf(p, "           %s(%s)\n",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x70)==0x70)?"6":
-				((art&0x60)==0x60)?"5":
-				((art&0x50)==0x50)?"4":
-				((art&0x40)==0x40)?"3":
-				((art&0x30)==0x30)?"2":
-				((art&0x20)==0x20)?"1":
-				((art&0x10)==0x10)?"0":"?");
-#ifdef DEBUG_AEC_REGS
-			(void) pci_read_config_byte(dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-#endif /* DEBUG_AEC_REGS */
-		}
-	}
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	byte		chipset_settings;
-	byte		ultra_settings;
-};
-
-struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_6,	0x31,	0x07	},
-	{	XFER_UDMA_5,	0x31,	0x06	},
-	{	XFER_UDMA_4,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x00,	0x00	},
-	{	0,		0x00,	0x00	}
-};
-
-struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_6,	0x41,	0x06	},
-	{	XFER_UDMA_5,	0x41,	0x05	},
-	{	XFER_UDMA_4,	0x41,	0x04	},
-	{	XFER_UDMA_3,	0x41,	0x03	},
-	{	XFER_UDMA_2,	0x41,	0x02	},
-	{	XFER_UDMA_1,	0x41,	0x01	},
-	{	XFER_UDMA_0,	0x41,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00	},
-	{	0,		0x00,	0x00	}
-};
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
-		}
-	return chipset_table->chipset_settings;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->ultra_settings;
-		}
-	return chipset_table->ultra_settings;
-}
-
-static byte aec62xx_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= 0x00;
-
-	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-		mode |= 0x01;
-	} else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP860) ||
-		   (dev->device == PCI_DEVICE_ID_ARTOP_ATP860R)) {
-		mode |= 0x02;
-	} else if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
-		   (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
-		u32 bmide = pci_resource_start(dev, 4);
-		if (IN_BYTE(bmide+2) & 0x10)
-			mode |= 0x04;
-		else
-			mode |= 0x03;
-	}
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte aec62xx_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = aec62xx_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= aec62xx_ratefilter(drive, xferspeed);
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed,
-		(struct chipset_bus_clock_list_entry *) dev->driver_data);
-	SPLIT_BYTE(tmp0,tmp1,tmp2);
-	MAKE_WORD(d_conf,tmp1,tmp2);
-	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-	tmp1 = 0x00;
-	tmp2 = 0x00;
-	pci_read_config_byte(dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-	ultra_conf = pci_bus_clock_list_ultra(speed,
-		(struct chipset_bus_clock_list_entry *) dev->driver_data);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
-	local_irq_restore(flags);
-	return(ide_config_drive_speed(drive, speed));
-}
-
-static int aec6260_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
-	byte speed		= aec62xx_ratefilter(drive, xferspeed);
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed,
-		(struct chipset_bus_clock_list_entry *) dev->driver_data);
-	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-	pci_read_config_byte(dev, ultra_pci, &ultra);
-	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-	ultra_conf = pci_bus_clock_list_ultra(speed,
-		(struct chipset_bus_clock_list_entry *) dev->driver_data);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	local_irq_restore(flags);
-	return(ide_config_drive_speed(drive, speed));
-}
-
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	switch (HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP865:
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return ((int) aec6260_tune_chipset(drive, speed));
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return ((int) aec6210_tune_chipset(drive, speed));
-		default:
-			return -1;
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= aec62xx_ratemask(drive);
-	byte speed;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-	
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-
-	(void) aec62xx_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 15) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-//	return ((int) ide_dma_on);
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	switch(pio) {
-		case 5:		speed = new_pio; break;
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-	(void) aec62xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		aec62xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			switch(dev->device) {
-				case PCI_DEVICE_ID_ARTOP_ATP860:
-				case PCI_DEVICE_ID_ARTOP_ATP860R:
-				case PCI_DEVICE_ID_ARTOP_ATP865:
-				case PCI_DEVICE_ID_ARTOP_ATP865R:
-					printk(" AEC62XX time out ");
-#if 0
-					{
-						int i = 0;
-						byte reg49h = 0;
-						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
-						for (i=0;i<256;i++)
-							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
-					}
-					return 0;
-#endif
-				default:
-					break;
-			}
-		default:
-			break;
-	}
-#if 0
-	{
-		ide_hwif_t *hwif	= HWIF(drive);
-		struct pci_dev *dev	= hwif->pci_dev;
-		unsigned long dma_base	= hwif->dma_base;
-		byte tmp1		= 0x00;
-		byte tmp2		= 0x00;
-
-		pci_read_config_byte(dev, 0x44, &tmp1);
-		pci_read_config_byte(dev, 0x45, &tmp2);
-		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
-		if (hwif->channel)
-			dma_base -= 0x08;
-		tmp1=IN_BYTE(dma_base+2) & 0x10;
-		printk(" AEC6280 133=%x ",tmp1);
-	}
-#endif
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
-{
-	int bus_speed = system_bus_clock();
-
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
-	aec_devs[n_aec_devs++] = dev;
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
-
-	if (bus_speed <= 33)
-		dev->driver_data = (void *) aec6xxx_33_base;
-	else
-		dev->driver_data = (void *) aec6xxx_34_base;
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
-{
-	byte mask	= hwif->channel ? 0x02 : 0x01;
-	byte ata66	= 0;
-
-	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-	return ((ata66 & mask) ? 0 : 1);
-}
-
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
-{
-	hwif->autodma = 0;
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &aec62xx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-
-}
-
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte reg54h		= 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	pci_read_config_byte(dev, 0x54, &reg54h);
-	pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
-	spin_unlock_irqrestore(&ide_lock, flags);
-	ide_setup_dma(hwif, dmabase, 8);
-}
-
-extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
-
-void __init fixup_device_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	u32 bar4reg = pci_resource_start(dev, 4);
-
-	if (IN_BYTE(bar4reg+2) & 0x10) {
-		strcpy(d->name, "AEC6880");
-		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
-			strcpy(d->name, "AEC6880R");
-	} else {
-		strcpy(d->name, "AEC6280");
-		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
-			strcpy(d->name, "AEC6280R");
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
diff -Nru a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
--- a/drivers/ide/ali14xx.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,223 +0,0 @@
-/*
- *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function.  The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk.  I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg  (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets.  I've added support for PIO mode 4 for the 1487.  This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.)  -Derek
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
-
-/* register initialization data */
-typedef struct { byte reg, data; } RegInitializer;
-
-static RegInitializer initData[] __initdata = {
-	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
-	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
-	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
-	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
-	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
-	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
-	{0x35, 0x03}, {0x00, 0x00}
-};
-
-#define ALI_MAX_PIO 4
-
-/* timing parameter registers for each drive */
-static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
-	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
-};
-
-static int basePort;	/* base port address */
-static int regPort;	/* port for register number */
-static int dataPort;	/* port for register data */
-static byte regOn;	/* output to base port to access registers */
-static byte regOff;	/* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline byte inReg (byte reg)
-{
-	outb_p(reg, regPort);
-	return IN_BYTE(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg (byte data, byte reg)
-{
-	outb_p(reg, regPort);
-	outb_p(data, dataPort);
-}
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int driveNum;
-	int time1, time2;
-	byte param1, param2, param3, param4;
-	unsigned long flags;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-
-	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
-	/* calculate timing, according to PIO mode */
-	time1 = d.cycle_time;
-	time2 = ide_pio_timings[pio].active_time;
-	param3 = param1 = (time2 * bus_speed + 999) / 1000;
-	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
-	if (pio < 3) {
-		param3 += 8;
-		param4 += 8;
-	}
-	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-		drive->name, pio, time1, time2, param1, param2, param3, param4);
-
-	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p(regOn, basePort);
-	outReg(param1, regTab[driveNum].reg1);
-	outReg(param2, regTab[driveNum].reg2);
-	outReg(param3, regTab[driveNum].reg3);
-	outReg(param4, regTab[driveNum].reg4);
-	outb_p(regOff, basePort);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort (void)
-{
-	int i;
-	byte t;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	for (i = 0; i < ALI_NUM_PORTS; ++i) {
-		basePort = ports[i];
-		regOff = IN_BYTE(basePort);
-		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-			outb_p(regOn, basePort);
-			if (IN_BYTE(basePort) == regOn) {
-				regPort = basePort + 4;
-				dataPort = basePort + 8;
-				t = inReg(0) & 0xf0;
-				outb_p(regOff, basePort);
-				local_irq_restore(flags);
-				if (t != 0x50)
-					return 0;
-				return 1;  /* success */
-			}
-		}
-		outb_p(regOff, basePort);
-	}
-	local_irq_restore(flags);
-	return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	outb_p(regOn, basePort);
-	for (p = initData; p->reg != 0; ++p)
-		outReg(p->data, p->reg);
-	outb_p(0x01, regPort);
-	t = IN_BYTE(regPort) & 0x01;
-	outb_p(regOff, basePort);
-	local_irq_restore(flags);
-	return t;
-}
-
-void __init init_ali14xx (void)
-{
-	/* auto-detect IDE controller port */
-	if (!findPort()) {
-		printk("\nali14xx: not found");
-		return;
-	}
-
-	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
-	ide_hwifs[0].chipset = ide_ali14xx;
-	ide_hwifs[1].chipset = ide_ali14xx;
-	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-
-	/* initialize controller registers */
-	if (!initRegisters()) {
-		printk("\nali14xx: Chip initialization failed");
-		return;
-	}
-}
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Sun Sep 15 19:19:30 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,825 +0,0 @@
-/*
- * linux/drivers/ide/alim15x3.c		Version 0.10	Jun. 9, 2000
- *
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- *  9/7/99 --Parts from the above author are included and need to be
- *  converted into standard interface, once I finish the thought.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_ALI_TIMINGS
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
-extern int (*ali_display_info)(char *, char **, off_t, int);  /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-char *fifo[4] = {
-	"FIFO Off",
-	"FIFO On ",
-	"DMA mode",
-	"PIO mode" };
-
-char *udmaT[8] = {
-	"1.5T",
-	"  2T",
-	"2.5T",
-	"  3T",
-	"3.5T",
-	"  4T",
-	"  6T",
-	"  8T"
-};
-
-char *channel_status[8] = {
-	"OK            ",
-	"busy          ",
-	"DRQ           ",
-	"DRQ busy      ",
-	"error         ",
-	"error busy    ",
-	"error DRQ     ",
-	"error DRQ busy"
-};
-
-static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
-	unsigned int bibma;
-	byte c0, c1;
-	byte rev, tmp;
-	char *p = buffer;
-	char *q;
-
-	/* fetch rev. */
-	pci_read_config_byte(bmide_dev, 0x08, &rev);
-	if (rev >= 0xc1)	/* M1543C or newer */
-		udmaT[7] = " ???";
-	else
-		fifo[3]  = "   ???  ";
-
-	/* first fetch bibma: */
-	pci_read_config_dword(bmide_dev, 0x20, &bibma);
-	bibma = (bibma & 0xfff0) ;
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte
-	 * registers to investigate:
-	 */
-	c0 = IN_BYTE((unsigned short)bibma + 0x02);
-	c1 = IN_BYTE((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p,
-		"\n                                Ali M15x3 Chipset.\n");
-	p += sprintf(p,
-		"                                ------------------\n");
-	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
-	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
-
-	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
-	p += sprintf(p,
-		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
-		(reg53h & 0x02) ? "Yes" : "No ",
-		(reg53h & 0x01) ? "Yes" : "No " );
-	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
-	p += sprintf(p,
-		"FIFO Status: contains %d Words, runs%s%s\n\n",
-		(reg53h & 0x3f),
-		(reg53h & 0x40) ? " OVERWR" : "",
-		(reg53h & 0x80) ? " OVERRD." : "." );
-
-	p += sprintf(p,
-		"-------------------primary channel"
-		"-------------------secondary channel"
-		"---------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
-	p += sprintf(p,
-		"channel status:       %s"
-		"                               %s\n",
-		(reg53h & 0x20) ? "On " : "Off",
-		(reg53h & 0x10) ? "On " : "Off" );
-
-	p += sprintf(p,
-		"both channels togth:  %s"
-		"                               %s\n",
-		(c0&0x80) ? "No " : "Yes",
-		(c1&0x80) ? "No " : "Yes" );
-
-	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
-	p += sprintf(p,
-		"Channel state:        %s                    %s\n",
-		channel_status[reg53h & 0x07],
-		channel_status[(reg53h & 0x70) >> 4] );
-
-	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
-	p += sprintf(p,
-		"Add. Setup Timing:    %dT"
-		"                                %dT\n",
-		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
-		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
-
-	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
-	p += sprintf(p,
-		"Command Act. Count:   %dT"
-		"                                %dT\n"
-		"Command Rec. Count:   %dT"
-		"                               %dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"----------------drive0-----------drive1"
-		"------------drive0-----------drive1------\n\n");
-	p += sprintf(p,
-		"DMA enabled:      %s              %s"
-		"               %s              %s\n",
-		(c0&0x20) ? "Yes" : "No ",
-		(c0&0x40) ? "Yes" : "No ",
-		(c1&0x20) ? "Yes" : "No ",
-		(c1&0x40) ? "Yes" : "No " );
-
-	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
-	q = "FIFO threshold:   %2d Words         %2d Words"
-		"          %2d Words         %2d Words\n";
-	if (rev < 0xc1) {
-		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
-			p += sprintf(p, q, 8, 8, 8, 8);
-		} else {
-			p += sprintf(p, q,
-				(reg5xh & 0x03) + 12,
-				((reg5xh & 0x30)>>4) + 12,
-				(reg5yh & 0x03) + 12,
-				((reg5yh & 0x30)>>4) + 12 );
-		}
-	} else {
-		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
-		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
-		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
-		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
-		p += sprintf(p, q, t1, t2, t3, t4);
-	}
-
-#if 0
-	p += sprintf(p, 
-		"FIFO threshold:   %2d Words         %2d Words"
-		"          %2d Words         %2d Words\n",
-		(reg5xh & 0x03) + 12,
-		((reg5xh & 0x30)>>4) + 12,
-		(reg5yh & 0x03) + 12,
-		((reg5yh & 0x30)>>4) + 12 );
-#endif
-
-	p += sprintf(p,
-		"FIFO mode:        %s         %s          %s         %s\n",
-		fifo[((reg5xh & 0x0c) >> 2)],
-		fifo[((reg5xh & 0xc0) >> 6)],
-		fifo[((reg5yh & 0x0c) >> 2)],
-		fifo[((reg5yh & 0xc0) >> 6)] );
-
-	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
-	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
-	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
-
-	p += sprintf(p,/*
-		"------------------drive0-----------drive1"
-		"------------drive0-----------drive1------\n")*/
-		"Dt RW act. Cnt    %2dT              %2dT"
-		"               %2dT              %2dT\n"
-		"Dt RW rec. Cnt    %2dT              %2dT"
-		"               %2dT              %2dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
-		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
-		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"-----------------------------------UDMA Timings"
-		"--------------------------------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
-	p += sprintf(p,
-		"UDMA:             %s               %s"
-		"                %s               %s\n"
-		"UDMA timings:     %s             %s"
-		"              %s             %s\n\n",
-		(reg5xh & 0x08) ? "OK" : "No",
-		(reg5xh & 0x80) ? "OK" : "No",
-		(reg5yh & 0x08) ? "OK" : "No",
-		(reg5yh & 0x80) ? "OK" : "No",
-		udmaT[(reg5xh & 0x07)],
-		udmaT[(reg5xh & 0x70) >> 4],
-		udmaT[reg5yh & 0x07],
-		udmaT[(reg5yh & 0x70) >> 4] );
-
-	return p-buffer; /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static byte m5229_revision;
-static byte chip_is_1543c_e;
-
-byte ali_proc = 0;
-static struct pci_dev *isa_dev;
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	int s_time, a_time, c_time;
-	byte s_clc, a_clc, r_clc;
-	unsigned long flags;
-	int bus_speed = system_bus_clock();
-	int port = hwif->channel ? 0x5c : 0x58;
-	int portFIFO = hwif->channel ? 0x55 : 0x54;
-	byte cd_dma_fifo = 0;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-	s_time = ide_pio_timings[pio].setup_time;
-	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
-		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
-		a_clc = 0;
-	c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
-		r_clc = 0;
-#endif
-
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
-		r_clc = 1;
-	} else {
-		if (r_clc >= 16)
-			r_clc = 0;
-	}
-	local_irq_save(flags);
-	
-	/* 
-	 * PIO mode => ATA FIFO on, ATAPI FIFO off
-	 */
-	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
-		if (hwif->channel) {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
-		} else {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
-		}
-	} else {
-		if (hwif->channel) {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
-		} else {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
-		}
-	}
-	
-	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-	local_irq_restore(flags);
-
-	/*
-	 * setup   active  rec
-	 * { 70,   165,    365 },   PIO Mode 0
-	 * { 50,   125,    208 },   PIO Mode 1
-	 * { 30,   100,    110 },   PIO Mode 2
-	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
-	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
-	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
-	 */
-
-}
-
-static byte ali15x3_can_ultra (ide_drive_t *drive)
-{
-#ifndef CONFIG_WDC_ALI15X3
-	struct hd_driveid *id	= drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
-
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-static byte ali15x3_ratemask (ide_drive_t *drive)
-{
-//	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= 0x00;
-	byte can_ultra		= ali15x3_can_ultra(drive);
-
-	if ((m5229_revision >= 0xC4) && (can_ultra)) {
-		mode |= 0x03;
-	} else if ((m5229_revision >= 0xC2) && (can_ultra)) {
-		mode |= 0x02;
-	} else if (can_ultra) {
-		mode |= 0x01;
-	} else {
-		return (mode &= ~0xFF);
-	}
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte ali15x3_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = ali15x3_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= ali15x3_ratefilter(drive, xferspeed);
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte tmpbyte		= 0x00;
-	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
-
-	if (speed < XFER_UDMA_0) {
-		byte ultra_enable	= (unit) ? 0x7f : 0xf7;
-		/*
-		 * clear "ultra enable" bit
-		 */
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= ultra_enable;
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-
-		if (speed < XFER_SW_DMA_0)
-			ali15x3_tune_drive(drive, speed);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	} else {
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= (0x0f << ((1-unit) << 2));
-		/*
-		 * enable ultra dma and set timing
-		 */
-		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-		if (speed >= XFER_UDMA_3) {
-			pci_read_config_byte(dev, 0x4b, &tmpbyte);
-			tmpbyte |= 1;
-			pci_write_config_byte(dev, 0x4b, tmpbyte);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	}
-	return (ide_config_drive_speed(drive, speed));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= ali15x3_ratemask(drive);
-	byte speed		= 0;
-
-	switch(mode) {
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-
-	(void) ali15x3_tune_chipset(drive, speed);
-//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_on;
-
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	drive->init_speed = 0;
-
-	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		hwif->tuneproc(drive, 5);
-	}
-	return hwif->dmaproc(dma_func, drive);
-}
-
-static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch(func) {
-		case ide_dma_check:
-			return ali15x3_config_drive_for_dma(drive);
-		case ide_dma_write:
-			if ((m5229_revision < 0xC2) &&
-			    (drive->media != ide_disk))
-				return 1;	/* try PIO instead of DMA */
-			break;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-#define ALI_INIT_CODE_TEST
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef ALI_INIT_CODE_TEST
-	unsigned long flags;
-	byte tmpbyte;
-#endif /* ALI_INIT_CODE_TEST */
-
-	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
-
-	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (IN_BYTE(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!ali_proc) {
-		ali_proc = 1;
-		bmide_dev = dev;
-		ali_display_info = &ali_get_info;
-	}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-#ifdef ALI_INIT_CODE_TEST
-	local_irq_save(flags);
-
-	if (m5229_revision >= 0xC2) {
-		/*
-		 * 1543C-B?, 1535, 1535D, 1553
-		 * Note 1: not all "motherboard" support this detection
-		 * Note 2: if no udma 66 device, the detection may "error".
-		 *         but in this case, we will not set the device to
-		 *         ultra 66, the detection result is not important
-		 */
-
-		/*
-		 * enable "Cable Detection", m5229, 0x4b, bit3
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-		/*
-		 * set south-bridge's enable bit, m1533, 0x79
-		 */
-		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-		if (m5229_revision == 0xC2) {
-			/*
-			 * 1543C-B0 (m1533, 0x79, bit 2)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-		} else if (m5229_revision >= 0xC3) {
-			/*
-			 * 1553/1535 (m1533, 0x79, bit 1)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-		}
-	} else {
-		/*
-		 * revision 0x20 (1543-E, 1543-F)
-		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		/*
-		 * clear bit 7
-		 */
-		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-	}
-
-	local_irq_save(flags);
-#endif /* ALI_INIT_CODE_TEST */
-
-	return 0;
-}
-
-/*
- * This checks if the controller and the cable are capable
- * of UDMA66 transfers. It doesn't check the drives.
- * But see note 2 below!
- */
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int ata66	= 0;
-	byte cable_80_pin[2]	= { 0, 0 };
-
-	unsigned long flags;
-	byte tmpbyte;
-
-	local_irq_save(flags);
-
-	if (m5229_revision >= 0xC2) {
-#ifndef ALI_INIT_CODE_TEST
-		/*
-		 * 1543C-B?, 1535, 1535D, 1553
-		 * Note 1: not all "motherboard" support this detection
-		 * Note 2: if no udma 66 device, the detection may "error".
-		 *         but in this case, we will not set the device to
-		 *         ultra 66, the detection result is not important
-		 */
-
-		/*
-		 * enable "Cable Detection", m5229, 0x4b, bit3
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-		/*
-		 * set south-bridge's enable bit, m1533, 0x79
-		 */
-		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-		if (m5229_revision == 0xC2) {
-			/*
-			 * 1543C-B0 (m1533, 0x79, bit 2)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-		} else if (m5229_revision >= 0xC3) {
-			/*
-			 * 1553/1535 (m1533, 0x79, bit 1)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-		}
-#endif /* ALI_INIT_CODE_TEST */
-		/*
-		 * Ultra66 cable detection (from Host View)
-		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-		 */
-		pci_read_config_byte(dev, 0x4a, &tmpbyte);
-		/*
-		 * 0x4a, bit0 is 0 => primary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
-		/*
-		 * 0x4a, bit1 is 0 => secondary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
-		/*
-		 * Allow ata66 if cable of current channel has 80 pins
-		 */
-		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
-	} else {
-#ifndef ALI_INIT_CODE_TEST
-		/*
-		 * revision 0x20 (1543-E, 1543-F)
-		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		/*
-		 * clear bit 7
-		 */
-		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-#endif /* ALI_INIT_CODE_TEST */
-		/*
-		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-		 */
-		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
-		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
-	}
-
-	/*
-	 * CD_ROM DMA on (m5229, 0x53, bit0)
-	 *      Enable this bit even if we want to use PIO
-	 * PIO FIFO off (m5229, 0x53, bit1)
-	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
-	 */
-	pci_read_config_byte(dev, 0x53, &tmpbyte);
-	tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-
-	pci_write_config_byte(dev, 0x53, tmpbyte);
-
-	local_irq_restore(flags);
-
-	return(ata66);
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_SPARC64
-	byte ideic, inmir;
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-				      1, 11, 0, 12, 0, 14, 0, 15 };
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	if (isa_dev) {
-		/*
-		 * read IDE interface control
-		 */
-		pci_read_config_byte(isa_dev, 0x58, &ideic);
-
-		/* bit0, bit1 */
-		ideic = ideic & 0x03;
-
-		/* get IRQ for IDE Controller */
-		if ((hwif->channel && ideic == 0x03) ||
-		    (!hwif->channel && !ideic)) {
-			/*
-			 * get SIRQ1 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x44, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->channel && !(ideic & 0x01)) {
-			/*
-			 * get SIRQ2 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x75, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		}
-	}
-#endif /* CONFIG_SPARC64 */
-
-	hwif->autodma = 0;
-	hwif->tuneproc = &ali15x3_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (m5229_revision >= 0x20) {
-		/*
-		 * M1543C or newer for DMAing
-		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((dmabase) && (m5229_revision < 0x20)) {
-		return;
-	}
-	ide_setup_dma(hwif, dmabase, 8);
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_ali15x3 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if (dev->resource[0].start != 0x01F1)
-		ide_register_xp_fix(dev);
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Sun Sep 15 19:19:45 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,519 +0,0 @@
-/*
- * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_VIPER_TIMINGS
-
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int amd74xx_get_info(char *, char **, off_t, int);
-extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = IN_BYTE((unsigned short)bibma + 0x02);
-	c1 = IN_BYTE((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                "
-			"AMD %04X VIPER Chipset.\n", bmide_dev->device);
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled "
-			"                        %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s "
-			"            %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte amd74xx_proc = 0;
-
-static int amd74xx_mode5_check (struct pci_dev *dev)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_VIPER_7411:
-		case PCI_DEVICE_ID_AMD_OPUS_7441:
-			return 1;
-		default:
-			return 0;
-	}
-}
-
-static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-
-	if (amd74xx_mode5_check(dev))
-		return 1;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev >= 7) ? 1 : 0);
-}
-
-static int amd74xx_swdma_error (ide_drive_t *drive)
-{
-	printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
-	return 0;
-}
-
-static byte amd74xx_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	byte mode = 0x00;
-
-        switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_OPUS_7441:
-		case PCI_DEVICE_ID_AMD_VIPER_7411:	{ mode |= 0x03; break; }
-		case PCI_DEVICE_ID_AMD_VIPER_7409:	{ mode |= 0x02; break; }
-		case PCI_DEVICE_ID_AMD_COBRA_7401:	{ mode |= 0x01; break; }
-		default:
-			return (mode &= ~0xFF);
-	}
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte amd74xx_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = amd74xx_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- */
-static int amd74xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= amd74xx_ratefilter(drive, xferspeed);
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_pio_timing	= 0x00;
-	byte pio_timing		= 0x00;
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
-		case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
-		case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
-		case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
-		default:
-                        return -1;
-        }
-
-	pci_read_config_byte(dev, drive_pci, &ultra_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
-	pci_read_config_byte(dev, 0x4c, &pio_timing);
-
-	ultra_timing	&= ~0xC7;
-	dma_pio_timing	&= ~0xFF;
-	pio_timing	&= ~(0x03 << drive->dn);
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_7:
-		case XFER_UDMA_6:
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			ultra_timing |= 0x46;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_4:
-			ultra_timing |= 0x45;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_3:
-			ultra_timing |= 0x44;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_2:
-			ultra_timing |= 0x40;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_1:
-			ultra_timing |= 0x41;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_0:
-			ultra_timing |= 0x42;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_2:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_1:
-			dma_pio_timing |= 0x21;
-			break;
-		case XFER_MW_DMA_0:
-			dma_pio_timing |= 0x77;
-			break;
-		case XFER_SW_DMA_2:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_SW_DMA_1:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_SW_DMA_0:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0xA8;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_PIO_3:
-			dma_pio_timing |= 0x22;
-			break;
-		case XFER_PIO_2:
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_PIO_1:
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_PIO_0:
-		default:
-			dma_pio_timing |= 0xA8;
-			break;
-        }
-
-	pio_timing |= (0x03 << drive->dn);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci, ultra_timing);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
-	pci_write_config_byte(dev, 0x4c, pio_timing);
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id   = drive->id;
-	byte mode		= amd74xx_ratemask(drive);
-	byte swdma		= amd74xx_swdma_check(HWIF(drive)->pci_dev);
-	byte speed		= 0;
-	int  rval;
-
-	amd74xx_tune_drive(drive, 5);
-	
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if ((id->dma_1word & 0x0004) && (swdma))
-				{ speed = XFER_SW_DMA_2; break; }
-			if ((id->dma_1word & 0x0002) && (swdma))
-				{ speed = XFER_SW_DMA_1; break; }
-			if ((id->dma_1word & 0x0001) && (swdma))
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-
-	(void) amd74xx_tune_chipset(drive, speed);
-//	return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
-	rval = (int)(   ((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			 ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			 ((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			 (((id->dma_1word >> 8) & 7) && (swdma)) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    ((id->dma_1word & 0x007) &&
-			     (amd74xx_swdma_check(HWIF(drive)->pci_dev)))) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-			
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		amd74xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * amd74xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int amd74xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (!amd74xx_swdma_check(dev))
-		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		OUT_BYTE(IN_BYTE(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (IN_BYTE(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!amd74xx_proc) {
-		amd74xx_proc = 1;
-		bmide_dev = dev;
-		amd74xx_display_info = &amd74xx_get_info;
-	}
-#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte cable_80_pin[2]	= { 0, 0 };
-	byte ata66		= 0;
-	byte tmpbyte;
-
-	/*
-	 * Ultra66 cable detection (from Host View)
-	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
-	 */
-	pci_read_config_byte(dev, 0x42, &tmpbyte);
-
-	/*
-	 * 0x42, bit0 is 1 => primary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
-
-	/*
-	 * 0x42, bit2 is 1 => secondary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_OPUS_7441:
-		case PCI_DEVICE_ID_AMD_VIPER_7411:
-			ata66 = (hwif->channel) ?
-				cable_80_pin[1] :
-				cable_80_pin[0];
-		default:
-			break;
-	}
-#ifdef CONFIG_AMD74XX_OVERRIDE
-	return(1);
-#else
-	return (unsigned int) ata66;
-#endif /* CONFIG_AMD74XX_OVERRIDE */
-}
-
-void __init ide_init_amd74xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd74xx_tune_chipset;
-
-	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
-		return;
-	}
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &amd74xx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	ide_setup_dma(hwif, dmabase, 8);
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_amd74xx (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if (dev->resource[0].start != 0x01F1)
-		ide_register_xp_fix(dev);
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
diff -Nru a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/arm/Makefile	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,12 @@
+
+O_TARGET := idedriver-arm.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/arm/icside.c	Sun Sep 15 19:19:46 2002
@@ -0,0 +1,875 @@
+/*
+ * linux/drivers/ide/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ *  08-Jun-1996	RMK	Created
+ *  12-Sep-1997	RMK	Added interrupt enable/disable
+ *  17-Apr-1999	RMK	Added support for V6 EASI
+ *  22-May-1999	RMK	Added support for V6 DMA
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#include "ide-noise.h"
+
+/*
+ * FIXME: We want to drop the the MACRO CRAP!
+ *
+ * ec->iops->in{b/w/l}
+ * ec->iops->in{b/w/l}_p
+ * ec->iops->out{b/w/l}
+ * ec->iops->out{b/w/l}_p
+ *
+ * the new core supports clean MMIO calls and other goodies
+ */
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS	2
+
+#define ICS_IDENT_OFFSET		0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT		0x000
+#define ICS_ARCIN_V5_INTROFFSET		0x001
+#define ICS_ARCIN_V5_IDEOFFSET		0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
+#define ICS_ARCIN_V5_IDESTEPPING	4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
+#define ICS_ARCIN_V6_INTROFFSET_1	0x880
+#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
+#define ICS_ARCIN_V6_IDESTEPPING	4
+
+struct cardinfo {
+	unsigned int dataoffset;
+	unsigned int ctrloffset;
+	unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+	ICS_ARCIN_V5_IDEOFFSET,
+	ICS_ARCIN_V5_IDEALTOFFSET,
+	ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+	ICS_ARCIN_V6_IDEOFFSET_1,
+	ICS_ARCIN_V6_IDEALTOFFSET_1,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+	ICS_ARCIN_V6_IDEOFFSET_2,
+	ICS_ARCIN_V6_IDEALTOFFSET_2,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+	{ MANU_ICS,  PROD_ICS_IDE  },
+	{ MANU_ICS2, PROD_ICS2_IDE },
+	{ 0xffff, 0xffff }
+};
+
+typedef enum {
+	ics_if_unknown,
+	ics_if_arcin_v5,
+	ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+	icside_irqenable_arcin_v5,
+	icside_irqdisable_arcin_v5,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+	icside_irqenable_arcin_v6,
+	icside_irqdisable_arcin_v6,
+	icside_irqpending_arcin_v6,
+	NULL,
+	NULL,
+	NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose  : identify IDE interface type
+ * Notes    : checks the description string
+ */
+static iftype_t __init icside_identifyif (struct expansion_card *ec)
+{
+	unsigned int addr;
+	iftype_t iftype;
+	int id = 0;
+
+	iftype = ics_if_unknown;
+
+	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+	id = inb(addr) & 1;
+	id |= (inb(addr + 1) & 1) << 1;
+	id |= (inb(addr + 2) & 1) << 2;
+	id |= (inb(addr + 3) & 1) << 3;
+
+	switch (id) {
+	case 0: /* A3IN */
+		printk("icside: A3IN unsupported\n");
+		break;
+
+	case 1: /* A3USER */
+		printk("icside: A3USER unsupported\n");
+		break;
+
+	case 3:	/* ARCIN V6 */
+		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v6;
+		break;
+
+	case 15:/* ARCIN V5 (no id) */
+		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v5;
+		break;
+
+	default:/* we don't know - complain very loudly */
+		printk("icside: ***********************************\n");
+		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+		printk("icside: ***********************************\n");
+		printk("icside: please report this to linux@arm.linux.org.uk\n");
+		printk("icside: defaulting to ARCIN V5\n");
+		iftype = ics_if_arcin_v5;
+		break;
+	}
+
+	return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time.  NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+#define NR_ENTRIES 256
+#define TABLE_SIZE (NR_ENTRIES * 8)
+
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int reading)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void icside_destroy_dmatable(ide_drive_t *drive)
+{
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
+
+	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
+static int
+icside_config_if(ide_drive_t *drive, int xfer_mode)
+{
+	int func = ide_dma_off;
+
+	switch (xfer_mode) {
+	case XFER_MW_DMA_2:
+		/*
+		 * The cycle time is limited to 250ns by the r/w
+		 * pulse width (90ns), however we should still
+		 * have a maximum burst transfer rate of 8MB/s.
+		 */
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_1:
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_0:
+		drive->drive_data = 480;
+		break;
+
+	default:
+		drive->drive_data = 0;
+		break;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = (u8) xfer_mode;
+
+	if (drive->drive_data &&
+	    ide_config_drive_speed(drive, (u8) xfer_mode) == 0)
+		func = ide_dma_on;
+	else
+		drive->drive_data = 480;
+
+	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+
+	drive->current_speed = (u8) xfer_mode;
+
+	return func;
+}
+
+static int
+icside_set_speed(ide_drive_t *drive, u8 speed)
+{
+	return icside_config_if(drive, speed);
+}
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+{
+	u8 dma_stat	= HWIF(drive)->ide_dma_end(drive);
+	/* get drive status */
+	u8 stat		= HWIF(drive)->INB(IDE_STATUS_REG);
+	int i;
+
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
+		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * The following is a sick duplication from ide-dma.c ;(
+ *
+ * This should be defined in one place only.
+ */
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+static struct drive_list_entry drive_whitelist [] = {
+	{ "Micropolis 2112A",			"ALL"		},
+	{ "CONNER CTMA 4000",			"ALL"		},
+	{ "CONNER CTT8000-A",			"ALL"		},
+	{ "ST34342A",				"ALL"		},
+	{ NULL,					0		}
+};
+
+static struct drive_list_entry drive_blacklist [] = {
+	{ "WDC AC11000H",			"ALL"		},
+	{ "WDC AC22100H",			"ALL"		},
+	{ "WDC AC32500H",			"ALL"		},
+	{ "WDC AC33100H",			"ALL"		},
+	{ "WDC AC31600H",			"ALL"		},
+	{ "WDC AC32100H",			"24.09P07"	},
+	{ "WDC AC23200L",			"21.10N21"	},
+	{ "Compaq CRD-8241B",			"ALL"		},
+	{ "CRD-8400B",				"ALL"		},
+	{ "CRD-8480B",				"ALL"		},
+	{ "CRD-8480C",				"ALL"		},
+	{ "CRD-8482B",				"ALL"		},
+ 	{ "CRD-84",				"ALL"		},
+	{ "SanDisk SDP3B",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SANYO CD-ROM CRD",			"ALL"		},
+	{ "HITACHI CDR-8",			"ALL"		},
+	{ "HITACHI CDR-8335",			"ALL"		},
+	{ "HITACHI CDR-8435",			"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
+	{ "CD-532E-A",				"ALL"		},
+	{ "E-IDE CD-ROM CR-840",		"ALL"		},
+	{ "CD-ROM Drive/F5A",			"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
+	{ "WPI CDD-820",			"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",			"ALL"		},
+	{ NULL,					0		}
+};
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
+}
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_good_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	return in_drive_list(id, drive_whitelist);
+}
+
+int check_drive_bad_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist)
+		printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+	return(blacklist);
+}
+
+int icside_dma_check(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	int autodma = hwif->autodma;
+	int xfer_mode = XFER_PIO_2;
+
+	if (!id || !(id->capability & 1) || !autodma)
+		return hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * Consult the list of known "bad" drives
+	 */
+	if (check_drive_bad_lists(drive))
+		return hwif->ide_dma_off(drive);
+
+	/*
+	 * Enable DMA on any drive that has multiword DMA
+	 */
+	if (id->field_valid & 2) {
+		if (id->dma_mword & 4) {
+			xfer_mode = XFER_MW_DMA_2;
+		} else if (id->dma_mword & 2) {
+			xfer_mode = XFER_MW_DMA_1;
+		} else if (id->dma_mword & 1) {
+			xfer_mode = XFER_MW_DMA_0;
+		}
+		goto out;
+	}
+
+	/*
+	 * Consult the list of known "good" drives
+	 */
+	if (check_drive_good_lists(drive)) {
+		if (id->eide_dma_time > 150)
+			goto out;
+		xfer_mode = XFER_MW_DMA_1;
+	}
+
+out:
+	if (icside_config_if(drive, xfer_mode))
+		return hwif->ide_dma_on(drive);
+	return hwif->ide_dma_off(drive);
+}
+
+int icside_dma_verbose(ide_drive_t *drive)
+{
+	printk(", DMA");
+	return 1;
+}
+
+int icside_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	return inb((unsigned long)hwif->hw.priv) & 1;
+}
+
+int icside_dma_host_off(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_off_quietly(ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	return icside_dma_host_off(drive);
+}
+
+int icside_dma_off(ide_drive_t *drive)
+{
+	printk("%s: DMA disabled\n", drive->name);
+	return icside_dma_off_quietly(drive);
+}
+
+int icside_dma_host_on(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_on(ide_drive_t *drive)
+{
+	drive->using_dma = 1;
+	return icside_dma_host_on(drive);
+}
+
+int icside_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	enable_dma(hwif->hw.dma);
+	return 0;
+}
+
+int icside_dma_end(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 
+	drive->waiting_for_dma = 0;
+	disable_dma(hwif->hw.dma);
+	icside_destroy_dmatable(drive);
+	return get_dma_residue(hwif->hw.dma) != 0;
+}
+
+int icside_dma_count (ide_drive_t *drive)
+{
+        return icside_dma_begin(drive);
+}
+
+int icside_dma_read(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, 1);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_READ);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+		if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+int icside_dma_write(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, 0);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+	printk("    %s: SG-DMA", hwif->name);
+
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+				 GFP_KERNEL);
+	if (!hwif->sg_table)
+		goto failed;
+
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+	hwif->speedproc = icside_set_speed;
+	hwif->autodma = autodma;
+
+	hwif->ide_dma_check = icside_dma_check;
+	hwif->ide_dma_host_off = icside_dma_host_off;
+	hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+	hwif->ide_dma_off = icside_dma_off;
+	hwif->ide_dma_host_on = icside_dma_host_on;
+	hwif->ide_dma_on = icside_dma_on;
+	hwif->ide_dma_read = icside_dma_read;
+	hwif->ide_dma_write = icside_dma_write;
+	hwif->ide_dma_count = icside_dma_count;
+	hwif->ide_dma_begin = icside_dma_begin;
+	hwif->ide_dma_end = icside_dma_end;
+	hwif->ide_dma_verbose = icside_dma_verbose;
+	hwif->ide_dma_bad_drive = check_drive_bad_lists;
+	hwif->ide_dma_good_drive = check_drive_good_lists;
+	hwif->ide_dma_test_irq = icside_dma_test_irq;
+
+	printk(" capable%s\n", autodma ?
+		", auto-enable" : "");
+
+	return 1;
+
+failed:
+	printk(" -- ERROR, unable to allocate DMA table\n");
+	return 0;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+	ide_hwif_t *hwif;
+	int index;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+			goto found;
+	}
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (!hwif->io_ports[IDE_DATA_OFFSET])
+			goto found;
+	}
+
+	return NULL;
+found:
+	return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+	unsigned long port = base + info->dataoffset;
+	ide_hwif_t *hwif;
+
+	hwif = icside_find_hwif(base);
+	if (hwif) {
+		int i;
+
+		memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+			hwif->io_ports[i] = (ide_ioreg_t)port;
+			port += 1 << info->stepping;
+		}
+		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->hw.irq  = irq;
+		hwif->irq     = irq;
+		hwif->hw.dma  = NO_DMA;
+		hwif->noprobe = 0;
+		hwif->chipset = ide_acorn;
+	}
+
+	return hwif;
+}
+
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port;
+	ide_hwif_t *hwif;
+
+	slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+	ec->irqmask  = 1;
+	ec->irq_data = (void *)slot_port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+	return hwif ? 0 : -1;
+}
+
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port, port;
+	ide_hwif_t *hwif, *mate;
+	int sel = 0;
+
+	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+	if (port == 0)
+		port = slot_port;
+	else
+		sel = 1 << 5;
+
+	outb(sel, slot_port);
+
+	ec->irq_data = (void *)port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+	if (ec->dma != NO_DMA) {
+		if (request_dma(ec->dma, hwif->name))
+			goto no_dma;
+
+		if (hwif) {
+			hwif->config_data = slot_port;
+			hwif->select_data = sel;
+			hwif->hw.dma  = ec->dma;
+			hwif->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_1);
+			hwif->channel = 0;
+			icside_setup_dma(hwif, autodma);
+			hwif->drives[0].autodma = autodma;
+			hwif->drives[1].autodma = autodma;
+		}
+		if (mate) {
+			mate->config_data = slot_port;
+			mate->select_data = sel | 1;
+			mate->hw.dma  = ec->dma;
+			mate->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_2);
+			mate->channel = 1;
+			icside_setup_dma(mate, autodma);
+			mate->drives[0].autodma = autodma;
+			mate->drives[1].autodma = autodma;
+		}
+	}
+no_dma:
+#endif
+	return hwif || mate ? 0 : -1;
+}
+
+int __init icside_init(void)
+{
+	int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+	autodma = 1;
+#endif
+
+	ecard_startfind ();
+
+	do {
+		struct expansion_card *ec;
+		int result;
+
+		ec = ecard_find(0, icside_cids);
+		if (ec == NULL)
+			break;
+
+		ecard_claim(ec);
+
+		switch (icside_identifyif(ec)) {
+		case ics_if_arcin_v5:
+			result = icside_register_v5(ec, autodma);
+			break;
+
+		case ics_if_arcin_v6:
+			result = icside_register_v6(ec, autodma);
+			break;
+
+		default:
+			result = -1;
+			break;
+		}
+
+		if (result)
+			ecard_release(ec);
+	} while (1);
+
+	return 0;
+}
diff -Nru a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/arm/rapide.c	Sun Sep 15 19:20:20 2002
@@ -0,0 +1,94 @@
+/*
+ * linux/drivers/ide/rapide.c
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ *
+ * Changelog:
+ *  08-06-1996	RMK	Created
+ *  13-04-1998	RMK	Added manufacturer and product IDs
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+
+static card_ids __init rapide_cids[] = {
+	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+	{ 0xffff, 0xffff }
+};
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS];
+
+static inline int rapide_register(struct expansion_card *ec)
+{
+	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+	hw_regs_t hw;
+
+	int i;
+
+	memset(&hw, 0, sizeof(hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw.io_ports[i] = (ide_ioreg_t)port;
+		port += 1 << 4;
+	}
+	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+	hw.irq = ec->irq;
+
+	return ide_register_hw(&hw, NULL);
+}
+
+int __init rapide_init(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		ec[i] = NULL;
+
+	ecard_startfind();
+
+	for (i = 0; ; i++) {
+		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
+			break;
+
+		ecard_claim(ec[i]);
+		result[i] = rapide_register(ec[i]);
+	}
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i] && result[i] < 0) {
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module (void)
+{
+	return rapide_init();
+}
+
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i]) {
+			unsigned long port;
+			port = ecard_address(ec[i], ECARD_MEMC, 0);
+
+			ide_unregister_port(port, ec[i]->irq, 16);
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+		}
+}
+#endif
+
diff -Nru a/drivers/ide/buddha.c b/drivers/ide/buddha.c
--- a/drivers/ide/buddha.c	Sun Sep 15 19:19:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,225 +0,0 @@
-/*
- *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- *  This driver was written based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at
- *  http://www.jschoenfeld.com
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *  TODO:
- *    - test it :-)
- *    - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
-    /*
-     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
-     */
-
-#define BUDDHA_NUM_HWIFS	2
-#define CATWEASEL_NUM_HWIFS	3
-#define XSURF_NUM_HWIFS         2
-
-    /*
-     *  Bases of the IDE interfaces (relative to the board address)
-     */
-
-#define BUDDHA_BASE1	0x800
-#define BUDDHA_BASE2	0xa00
-#define BUDDHA_BASE3	0xc00
-
-#define XSURF_BASE1     0xb000 /* 2.5" Interface */
-#define XSURF_BASE2     0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
-     XSURF_BASE1, XSURF_BASE2
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define BUDDHA_DATA	0x00
-#define BUDDHA_ERROR	0x06		/* see err-bits */
-#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define BUDDHA_SECTOR	0x0e		/* starting sector */
-#define BUDDHA_LCYL	0x12		/* starting cylinder */
-#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
-#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS	0x1e		/* see status-bits */
-#define BUDDHA_CONTROL	0x11a
-#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
-
-    /*
-     *  Other registers
-     */
-
-#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2	0xf40		/* interrupt */
-#define BUDDHA_IRQ3	0xf80
-
-#define XSURF_IRQ1      0x7e
-#define XSURF_IRQ2      0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
-    XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
-
-
-    /*
-     *  Board information
-     */
-
-typedef enum BuddhaType_Enum {
-    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int buddha_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-static int xsurf_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
-    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-    /*
-     *  Probe for a Buddha or Catweasel IDE interface
-     */
-
-void __init buddha_init(void)
-{
-	hw_regs_t hw;
-	int i, index;
-
-	struct zorro_dev *z = NULL;
-	u_long buddha_board = 0;
-	BuddhaType type;
-	int buddha_num_hwifs;
-
-	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-		unsigned long board;
-		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
-			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
-			type=BOARD_BUDDHA;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
-			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
-			type=BOARD_CATWEASEL;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
-			buddha_num_hwifs = XSURF_NUM_HWIFS;
-			type=BOARD_XSURF;
-		} else 
-			continue;
-		
-		board = z->resource.start;
-		
-		if(type != BOARD_XSURF) {
-			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
-				continue;
-		} else {
-			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
-				continue;
-			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
-				goto fail_base2;
-			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
-				release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
-				release_mem_region(board+XSURF_BASE1, 0x1000);
-				continue;
-			}
-		}	  
-		buddha_board = ZTWO_VADDR(board);
-		
-		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
-		/* X-Surf doesn't have this.  IRQs are always on */
-		if (type != BOARD_XSURF)
-			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
-		for(i=0;i<buddha_num_hwifs;i++) {
-			if(type != BOARD_XSURF) {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
-						buddha_offsets, 0,
-						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
-						buddha_ack_intr, IRQ_AMIGA_PORTS);
-			} else {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
-						xsurf_offsets, 0,
-						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
-						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}	
-			
-			index = ide_register_hw(&hw, NULL);
-			if (index != -1) {
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
-		}
-	}
-}
diff -Nru a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
--- a/drivers/ide/cmd640.c	Sun Sep 15 19:20:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,886 +0,0 @@
-/*
- *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *  			mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for the advanced features and bugs
- *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- *  These chips are basically fucked by design, and getting this driver
- *  to work on every motherboard design that uses this screwed chip seems
- *  bloody well impossible.  However, we're still trying.
- *
- *  Version 0.97 worked for everybody.
- *
- *  User feedback is essential.  Many thanks to the beta test team:
- *
- *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- *  liug@mama.indstate.edu, and others.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	Fixes for vlb initialization code, enable prefetch
- *			for versions 'B' and 'C' of chip by default,
- *			some code cleanup.
- *
- *  Version 0.03	Added reset of secondary interface,
- *			and black list for devices which are not compatible
- *			with prefetch mode. Separate function for setting
- *			prefetch is added, possibly it will be called some
- *			day from ioctl processing code.
- *
- *  Version 0.04	Now configs/compiles separate from ide.c
- *
- *  Version 0.05	Major rewrite of interface timing code.
- *			Added new function cmd640_set_mode to set PIO mode
- *			from ioctl call. New drives added to black list.
- *
- *  Version 0.06	More code cleanup. Prefetch is enabled only for
- *			detected hard drives, not included in prefetch
- *			black list.
- *
- *  Version 0.07	Changed to more conservative drive tuning policy.
- *			Unknown drives, which report PIO < 4 are set to
- *			(reported_PIO - 1) if it is supported, or to PIO0.
- *			List of known drives extended by info provided by
- *			CMD at their ftp site.
- *
- *  Version 0.08	Added autotune/noautotune support.
- *
- *  Version 0.09	Try to be smarter about 2nd port enabling.
- *  Version 0.10	Be nice and don't reset 2nd port.
- *  Version 0.11	Try to handle more weird situations.
- *
- *  Version 0.12	Lots of bug fixes from Laszlo Peter
- *			irq unmasking disabled for reliability.
- *			try to be even smarter about the second port.
- *			tidy up source code formatting.
- *  Version 0.13	permit irq unmasking again.
- *  Version 0.90	massive code cleanup, some bugs fixed.
- *			defaults all drives to PIO mode0, prefetch off.
- *			autotune is OFF by default, with compile time flag.
- *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- *			 (requires hdparm-3.1 or newer)
- *  Version 0.91	first release to linux-kernel list.
- *  Version 0.92	move initial reg dump to separate callable function
- *			change "readahead" to "prefetch" to avoid confusion
- *  Version 0.95	respect original BIOS timings unless autotuning.
- *			tons of code cleanup and rearrangement.
- *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
- *			prevent use of unmask when prefetch is on
- *  Version 0.96	prevent use of io_32bit when prefetch is off
- *  Version 0.97	fix VLB secondary interface for sjd@slip.net
- *			other minor tune-ups:  0.96 was very good.
- *  Version 0.98	ignore PCI version when disabled by BIOS
- *  Version 0.99	display setup/active/recovery clocks with PIO mode
- *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
- *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
- *			 ("fast" is necessary for 32bit I/O in some systems)
- *  Version 1.02	fix bug that resulted in slow "setup times"
- *			 (patch courtesy of Zoltan Hidvegi)
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-#define CMD640_PREFETCH_MASKS 1
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
- */
-int cmd640_vlb = 0;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID		0x00
-#define DID		0x02
-#define PCMD		0x04
-#define   PCMD_ENA	0x01
-#define PSTTS		0x06
-#define REVID		0x08
-#define PROGIF		0x09
-#define SUBCL		0x0a
-#define BASCL		0x0b
-#define BaseA0		0x10
-#define BaseA1		0x14
-#define BaseA2		0x18
-#define BaseA3		0x1c
-#define INTLINE		0x3c
-#define INPINE		0x3d
-
-#define	CFR		0x50
-#define   CFR_DEVREV		0x03
-#define   CFR_IDE01INTR		0x04
-#define	  CFR_DEVID		0x18
-#define	  CFR_AT_VESA_078h	0x20
-#define	  CFR_DSA1		0x40
-#define	  CFR_DSA0		0x80
-
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define DRWTIM23	0x58
-#define BRST		0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * These are initialized to point at the devices we control
- */
-static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
-static ide_drive_t *cmd_drives[4];
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*put_cmd640_reg)(unsigned short reg, byte val);
-static byte (*get_cmd640_reg)(unsigned short reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg & 3) | 0xcfc);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static byte get_cmd640_reg_pci1 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p((reg & 3) | 0xcfc);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return b;
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static byte get_cmd640_reg_pci2 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p(reg, cmd640_key);
-	outb_p(val, cmd640_key + 4);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static byte get_cmd640_reg_vlb (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	outb_p(reg, cmd640_key);
-	b = inb_p(cmd640_key + 4);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return b;
-}
-
-static int __init match_pci_cmd640_device (void)
-{
-	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
-	unsigned int i;
-	for (i = 0; i < 4; i++) {
-		if (get_cmd640_reg(i) != ven_dev[i])
-			return 0;
-	}
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
-	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
-		printk("ide: cmd640 on PCI disabled by BIOS\n");
-		return 0;
-	}
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
-	return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci1;
-	put_cmd640_reg = put_cmd640_reg_pci1;
-	for (cmd640_key = 0x80000000;
-	     cmd640_key <= 0x8000f800;
-	     cmd640_key += 0x800) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci2;
-	put_cmd640_reg = put_cmd640_reg_pci2;
-	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb (void)
-{
-	byte b;
-
-	get_cmd640_reg = get_cmd640_reg_vlb;
-	put_cmd640_reg = put_cmd640_reg_vlb;
-	cmd640_key = 0x178;
-	b = get_cmd640_reg(CFR);
-	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
-		cmd640_key = 0x78;
-		b = get_cmd640_reg(CFR);
-		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
-			return 0;
-	}
-	return 1; /* success */
-}
-
-/*
- *  Returns 1 if an IDE interface/drive exists at 0x170,
- *  Returns 0 otherwise.
- */
-static int __init secondary_port_responding (void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
-	udelay(100);
-	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
-		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
-		udelay(100);
-		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
-			spin_unlock_irqrestore(&ide_lock, flags);
-			return 0; /* nothing responded */
-		}
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers.  May be called from ide.c
- */
-void cmd640_dump_regs (void)
-{
-	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
-	/* Dump current state of chip registers */
-	printk("ide: cmd640 internal register dump:");
-	for (; reg <= 0x59; reg++) {
-		if (!(reg & 0x0f))
-			printk("\n%04x:", reg);
-		printk(" %02x", get_cmd640_reg(reg));
-	}
-	printk("\n");
-}
-#endif
-
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch (unsigned int index)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	byte b = get_cmd640_reg(prefetch_regs[index]);
-
-	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-	} else {
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-	}
-}
-
-/*
- * Figure out which devices we control
- */
-static void __init setup_device_ptrs (void)
-{
-	unsigned int i;
-
-	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
-	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		ide_hwif_t *hwif = &ide_hwifs[i];
-		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
-			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
-				cmd_hwif0 = hwif;
-			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-				cmd_hwif1 = hwif;
-		}
-	}
-	cmd_drives[0] = &cmd_hwif0->drives[0];
-	cmd_drives[1] = &cmd_hwif0->drives[1];
-	cmd_drives[2] = &cmd_hwif1->drives[0];
-	cmd_drives[3] = &cmd_hwif1->drives[1];
-}
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode (unsigned int index, int mode)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	int reg = prefetch_regs[index];
-	byte b;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	b = get_cmd640_reg(reg);
-	if (mode) {	/* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-		b &= ~prefetch_masks[index];	/* enable prefetch */
-	} else {
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-		b |= prefetch_masks[index];	/* disable prefetch */
-	}
-	put_cmd640_reg(reg, b);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks (unsigned int index)
-{
-	byte active_count, recovery_count;
-
-	active_count = active_counts[index];
-	if (active_count == 1)
-		++active_count;
-	recovery_count = recovery_counts[index];
-	if (active_count > 3 && recovery_count == 1)
-		++recovery_count;
-	if (cmd640_chip_version > 1)
-		recovery_count += 1;  /* cmd640b uses (count + 1)*/
-	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-inline static byte pack_nibbles (byte upper, byte lower)
-{
-	return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine retrieves the initial drive timings from the chipset.
- */
-static void __init retrieve_drive_counts (unsigned int index)
-{
-	byte b;
-
-	/*
-	 * Get the internal setup timing, and convert to clock count
-	 */
-	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
-	switch (b) {
-		case 0x00: b = 4; break;
-		case 0x80: b = 3; break;
-		case 0x40: b = 2; break;
-		default:   b = 5; break;
-	}
-	setup_counts[index] = b;
-
-	/*
-	 * Get the active/recovery counts
-	 */
-	b = get_cmd640_reg(drwtim_regs[index]);
-	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
-	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
-}
-
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts (unsigned int index)
-{
-	unsigned long flags;
-	byte setup_count    = setup_counts[index];
-	byte active_count   = active_counts[index];
-	byte recovery_count = recovery_counts[index];
-
-	/*
-	 * Set up address setup count and drive read/write timing registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * so we merge the timings, using the slowest value for each timing.
-	 */
-	if (index > 1) {
-		unsigned int mate;
-		if (cmd_drives[mate = index ^ 1]->present) {
-			if (setup_count < setup_counts[mate])
-				setup_count = setup_counts[mate];
-			if (active_count < active_counts[mate])
-				active_count = active_counts[mate];
-			if (recovery_count < recovery_counts[mate])
-				recovery_count = recovery_counts[mate];
-		}
-	}
-
-	/*
-	 * Convert setup_count to internal chipset representation
-	 */
-	switch (setup_count) {
-		case 4:	 setup_count = 0x00; break;
-		case 3:	 setup_count = 0x80; break;
-		case 1:
-		case 2:	 setup_count = 0x40; break;
-		default: setup_count = 0xc0; /* case 5 */
-	}
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	spin_lock_irqsave(&ide_lock, flags);
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 * (this converts counts of 16 into counts of zero -- okay).
-	 */
-	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
-	put_cmd640_reg(arttim_regs[index], setup_count);
-	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
-{
-	int setup_time, active_time, recovery_time, clock_time;
-	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = system_bus_clock();
-
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-	if (active_count < 2)
-		active_count = 2; /* minimum allowed by cmd640 */
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count < 2)
-		recovery_count = 2; /* minimum allowed by cmd640 */
-	if (recovery_count > 17) {
-		active_count += recovery_count - 17;
-		recovery_count = 17;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd640 */
-	if (cmd640_chip_version > 1)
-		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
-	if (recovery_count > 16)
-		recovery_count = 16; /* maximum allowed by cmd640 */
-
-	setup_counts[index]    = setup_count;
-	active_counts[index]   = active_count;
-	recovery_counts[index] = recovery_count;
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (index);
-}
-
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
-{
-	byte b;
-	ide_pio_data_t  d;
-	unsigned int index = 0;
-
-	while (drive != cmd_drives[index]) {
-		if (++index > 3) {
-			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
-			return;
-		}
-	}
-	switch (mode_wanted) {
-		case 6: /* set fast-devsel off */
-		case 7: /* set fast-devsel on */
-			mode_wanted &= 1;
-			b = get_cmd640_reg(CNTRL) & ~0x27;
-			if (mode_wanted)
-				b |= 0x27;
-			put_cmd640_reg(CNTRL, b);
-			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			set_prefetch_mode(index, mode_wanted);
-			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
-
-	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-		drive->name,
-		d.pio_mode,
-		d.cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "");
-	display_clocks(index);
-	return;
-}
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-static int pci_conf1(void)
-{
-	u32 tmp;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	OUT_BYTE(0x01, 0xCFB);
-	tmp = inl(0xCF8);
-	outl(0x80000000, 0xCF8);
-	if (inl(0xCF8) == 0x80000000) {
-		outl(tmp, 0xCF8);
-		spin_unlock_irqrestore(&ide_lock, flags);
-		return 1;
-	}
-	outl(tmp, 0xCF8);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return 0;
-}
-
-static int pci_conf2(void)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	OUT_BYTE(0x00, 0xCFB);
-	OUT_BYTE(0x00, 0xCF8);
-	OUT_BYTE(0x00, 0xCFA);
-	if (IN_BYTE(0xCF8) == 0x00 && IN_BYTE(0xCF8) == 0x00) {
-		spin_unlock_irqrestore(&ide_lock, flags);
-		return 1;
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return 0;
-}
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
- */
-int __init ide_probe_for_cmd640x (void)
-{
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	int second_port_toggled = 0;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	int second_port_cmd640 = 0;
-	const char *bus_type, *port2;
-	unsigned int index;
-	byte b, cfr;
-
-	if (cmd640_vlb && probe_for_cmd640_vlb()) {
-		bus_type = "VLB";
-	} else {
-		cmd640_vlb = 0;
-		/* Find out what kind of PCI probing is supported otherwise
-		   Justin Gibbs will sulk.. */
-		if (pci_conf1() && probe_for_cmd640_pci1())
-			bus_type = "PCI (type1)";
-		else if (pci_conf2() && probe_for_cmd640_pci2())
-			bus_type = "PCI (type2)";
-		else
-			return 0;
-	}
-	/*
-	 * Undocumented magic (there is no 0x5b reg in specs)
-	 */
-	put_cmd640_reg(0x5b, 0xbd);
-	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
-		return 0;
-	}
-	put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-
-	/*
-	 * Documented magic begins here
-	 */
-	cfr = get_cmd640_reg(CFR);
-	cmd640_chip_version = cfr & CFR_DEVREV;
-	if (cmd640_chip_version == 0) {
-		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
-		return 0;
-	}
-
-	/*
-	 * Initialize data for primary port
-	 */
-	setup_device_ptrs ();
-	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
-	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
-	cmd_hwif0->chipset = ide_cmd640;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	cmd_hwif0->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-	/*
-	 * Ensure compatibility by always using the slowest timings
-	 * for access to the drive's command register block,
-	 * and reset the prefetch burstsize to default (512 bytes).
-	 *
-	 * Maybe we need a way to NOT do these on *some* systems?
-	 */
-	put_cmd640_reg(CMDTIM, 0);
-	put_cmd640_reg(BRST, 0x40);
-
-	/*
-	 * Try to enable the secondary interface, if not already enabled
-	 */
-	if (cmd_hwif1->noprobe) {
-		port2 = "not probed";
-	} else {
-		b = get_cmd640_reg(CNTRL);
-		if (secondary_port_responding()) {
-			if ((b & CNTRL_ENA_2ND)) {
-				second_port_cmd640 = 1;
-				port2 = "okay";
-			} else if (cmd640_vlb) {
-				second_port_cmd640 = 1;
-				port2 = "alive";
-			} else
-				port2 = "not cmd640";
-		} else {
-			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
-			if (secondary_port_responding()) {
-				second_port_cmd640 = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-				second_port_toggled = 1;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-				port2 = "enabled";
-			} else {
-				put_cmd640_reg(CNTRL, b); /* restore original setting */
-				port2 = "not responding";
-			}
-		}
-	}
-
-	/*
-	 * Initialize data for secondary cmd640 port, if enabled
-	 */
-	if (second_port_cmd640) {
-		cmd_hwif0->serialized = 1;
-		cmd_hwif1->serialized = 1;
-		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif0->mate = cmd_hwif1;
-		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->channel = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		cmd_hwif1->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
-		cmd_hwif0->serialized ? "" : "not ", port2);
-
-	/*
-	 * Establish initial timings/prefetch for all drives.
-	 * Do not unnecessarily disturb any prior BIOS setup of these.
-	 */
-	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
-		ide_drive_t *drive = cmd_drives[index];
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-	 		/*
-	 		 * Reset timing to the slowest speed and turn off prefetch.
-			 * This way, the drive identify code has a better chance.
-			 */
-			setup_counts    [index] = 4;	/* max possible */
-			active_counts   [index] = 16;	/* max possible */
-			recovery_counts [index] = 16;	/* max possible */
-			program_drive_counts (index);
-			set_prefetch_mode (index, 0);
-			printk("cmd640: drive%d timings/prefetch cleared\n", index);
-		} else {
-			/*
-			 * Record timings/prefetch without changing them.
-			 * This preserves any prior BIOS setup.
-			 */
-			retrieve_drive_counts (index);
-			check_prefetch (index);
-			printk("cmd640: drive%d timings/prefetch(%s) preserved",
-				index, drive->no_io_32bit ? "off" : "on");
-			display_clocks(index);
-		}
-#else
-		/*
-		 * Set the drive unmask flags to match the prefetch setting
-		 */
-		check_prefetch (index);
-		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
-			index, drive->no_io_32bit ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-	return 1;
-}
-
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Sun Sep 15 19:20:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1236 +0,0 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
- *
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Note, this driver is not used at all on other systems because
- *           there the "BIOS" has done all of the following already.
- *           Due to massive hardware bugs, UltraDMA is only supported
- *           on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998		David S. Miller (davem@redhat.com)
- *
- * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define CMD_DEBUG 0
-
-#if CMD_DEBUG
-#define cmdprintk(x...)	printk(x)
-#else
-#define cmdprintk(x...)
-#endif
-
-/*
- * CMD64x specific registers definition.
- */
-
-#define CFR		0x50
-#define   CFR_INTR_CH0		0x02
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define   ARTTIM23_INTR_CH1	0x10
-#define ARTTIM2		0x57
-#define ARTTIM3		0x57
-#define DRWTIM23	0x58
-#define DRWTIM2		0x58
-#define BRST		0x59
-#define DRWTIM3		0x5b
-
-#define BMIDECR0	0x70
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
-#define UDIDETCR0	0x73
-#define DTPR0		0x74
-#define BMIDECR1	0x78
-#define BMIDECSR	0x79
-#define BMIDESR1	0x7A
-#define UDIDETCR1	0x7B
-#define DTPR1		0x7C
-
-#define DISPLAY_CMD64X_TIMINGS
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
-static char * print_sii_get_info(char *, struct pci_dev *, int);
-static int cmd64x_get_info(char *, char **, off_t, int);
-extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-byte cmd64x_proc = 0;
-
-#define CMD_MAX_DEVS		5
-
-static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
-static int n_cmd_devs;
-
-#undef DEBUG_CMD_REGS
-
-static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
-{
-	char *p = buf;
-
-	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
-	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 0, reg71 = 0;			/* extra */
-#ifdef DEBUG_CMD_REGS
-	u8 hi_byte = 0, lo_byte = 0;
-#endif /* DEBUG_CMD_REGS */
-
-	p += sprintf(p, "\nController: %d\n", index);
-	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
-	(void) pci_read_config_byte(dev, CFR,       &reg50);
-	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
-	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled           "
-			"              %sabled\n",
-		(reg72&0x80)?"dis":" en",
-		(reg7a&0x80)?"dis":" en");
-	p += sprintf(p, "--------------- drive0 "
-		"--------- drive1 -------- drive0 "
-		"---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s"
-			"             %s               %s\n",
-		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
-		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
-
-	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
-		(reg72&0x20)?(
-			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
-			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
-			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
-			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
-			"X"):"?",
-		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
-		(reg72&0x40)?(
-			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
-			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
-			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
-			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
-			"X"):"?");
-	p += sprintf(p, "         %s(%s)           %s(%s)\n",
-		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x20)?(
-			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
-			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
-			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
-			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
-			"X"):"?",
-		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x40)?(
-			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
-			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
-			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
-			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
-			"X"):"?" );
-	p += sprintf(p, "PIO Mode:       %s                %s"
-			"               %s                 %s\n",
-			"?", "?", "?", "?");
-	p += sprintf(p, "                %s                     %s\n",
-		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
-		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
-		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
-
-#ifdef DEBUG_CMD_REGS
-	SPLIT_BYTE(reg50, hi_byte, lo_byte);
-	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
-			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
-	SPLIT_BYTE(reg57, hi_byte, lo_byte);
-	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
-			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
-	SPLIT_BYTE(reg71, hi_byte, lo_byte);
-	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
-			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
-#endif /* DEBUG_CMD_REGS */
-
-	return (char *)p;
-}
-
-static char * print_sii_get_info (char *buf, struct pci_dev *dev, int index)
-{
-	char *p = buf;
-
-	p += sprintf(p, "\nController: %d\n", index);
-	p += sprintf(p, "SII%x Chipset.\n", dev->device);
-
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "PIO Mode:       %s                %s"
-			"               %s                 %s\n",
-			"?", "?", "?", "?");
-	return (char *)p;
-}
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	p += sprintf(p, "\n");
-	for (i = 0; i < n_cmd_devs; i++) {
-		struct pci_dev *dev	= cmd_devs[i];
-
-		if (dev->device <= PCI_DEVICE_ID_CMD_649)
-			p = print_cmd64x_get_info(p, dev, i);
-		else
-			p = print_sii_get_info(p, dev, i);
-	}
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
- */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
-{
-	unsigned long flags;
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	byte temp_b;
-	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const byte recovery_counts[] =
-		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const byte arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const byte drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
-
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
-		active_count, recovery_count, drive->present);
-	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
-	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
-	}
-
-	/*
-	 * Convert values to internal chipset representation
-	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
-
-	cmdprintk("Final values = %d,%d,%d\n",
-		setup_count, active_count, recovery_count);
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	local_irq_save(flags);
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
-		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
-		(byte) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n",
-		((byte) setup_count) | (temp_b & 0x3f),
-		arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n",
-		(byte) ((active_count << 4) | recovery_count),
-		drwtim_regs[channel][slave]);
-	local_irq_restore(flags);
-}
-
-/*
- * Attempts to set the interface PIO mode.
- * The preferred method of selecting PIO modes (e.g. mode 4) is 
- * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
- * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
- * Called with 255 at boot time.
- */
-static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
-	byte recovery_count2, cycle_count;
-	int setup_count, active_count, recovery_count;
-	int bus_speed = system_bus_clock();
-	/*byte b;*/
-	ide_pio_data_t  d;
-
-	switch (mode_wanted) {
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			/*set_prefetch_mode(index, mode_wanted);*/
-			cmdprintk("%s: %sabled cmd640 prefetch\n",
-				drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	pio_mode = d.pio_mode;
-	cycle_time = d.cycle_time;
-
-	/*
-	 * I copied all this complicated stuff from cmd640.c and made a few
-	 * minor changes.  For now I am just going to pray that it is correct.
-	 */
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd646 */
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it
-	 *		(proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
-
-	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
-		"clocks=%d/%d/%d\n",
-		drive->name, pio_mode, mode_wanted, cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
-}
-
-static byte cmd64x_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= 0x00;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:	{ mode |= 0x04; break; }
-		case PCI_DEVICE_ID_CMD_649:	{ mode |= 0x03; break; }
-		case PCI_DEVICE_ID_CMD_648:	{ mode |= 0x02; break; }
-		case PCI_DEVICE_ID_CMD_643:	{ mode |= 0x01; break; }
-
-		case PCI_DEVICE_ID_CMD_646:
-		{
-			unsigned int class_rev	= 0;
-			pci_read_config_dword(dev,
-				PCI_CLASS_REVISION, &class_rev);
-			class_rev &= 0xff;
-		/*
-		 * UltraDMA only supported on PCI646U and PCI646U2, which
-		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
-		 * Actually, although the CMD tech support people won't
-		 * tell me the details, the 0x03 revision cannot support
-		 * UDMA correctly without hardware modifications, and even
-		 * then it only works with Quantum disks due to some
-		 * hold time assumptions in the 646U part which are fixed
-		 * in the 646U2.
-		 *
-		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-		 */
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:	{ mode |= 0x01; break; }
-				case 0x03:
-				case 0x01:
-				default:	{ mode |= 0x00; break; }
-			}
-		}
-	}
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte cmd64x_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = cmd64x_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
-	unsigned short		timing;
-
-	pci_read_config_word(dev, addr_mask, &timing);
-
-	switch (timing) {
-		case 0x10c1:	return 4;
-		case 0x10c3:	return 3;
-		case 0x1281:	return 2;
-		case 0x2283:	return 1;
-		case 0x328a:
-		default:	return 0;
-	}
-}
-
-static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			drive_pci;
-	unsigned short		speedt;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0xA4; break;
-		case 1: drive_pci = 0xA6; break;
-		case 2: drive_pci = 0xB4; break;
-		case 3: drive_pci = 0xB6; break;
-		default: return;
-        }
-
-	pci_read_config_word(dev, drive_pci, &speedt);
-
-	/* cheat for now and use the docs */
-//	switch(cmd680_taskfile_timing(hwif)) {
-	switch(mode_wanted) {
-		case 4:		speedt = 0x10c1; break;
-		case 3:		speedt = 0x10C3; break;
-		case 2:		speedt = 0x1104; break;
-		case 1:		speedt = 0x2283; break;
-		case 0:
-		default:	speedt = 0x328A; break;
-	}
-	pci_write_config_word(dev, drive_pci, speedt);
-}
-
-static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	byte speed	= 0x00;
-	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	cmd64x_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 speed		= 0x00;
-	u8 mode_pci		= 0x00;
-	u8 channel_timings	= cmd680_taskfile_timing(hwif);
-	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-
-	/* WARNING PIO timing mess is going to happen b/w devices, argh */
-	if ((channel_timings != set_pio) && (set_pio > channel_timings))
-		set_pio = channel_timings;
-
-	cmd680_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			config_cmd680_chipset_for_pio(drive, set_speed);
-			return;
-		default:
-			break;
-	}
-	config_cmd64x_chipset_for_pio(drive, set_speed);
-}
-
-static int cmd64x_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
-	u8 regU			= 0;
-	u8 regD			= 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	u8 speed		= cmd64x_ratefilter(drive, xferspeed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return 1;
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	regD &= ~(unit ? 0x40 : 0x20);
-	regU &= ~(unit ? 0xCA : 0x35);
-	(void) pci_write_config_byte(dev, pciD, regD);
-	(void) pci_write_config_byte(dev, pciU, regU);
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
-		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
-		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
-		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
-		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
-		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
-		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
-
-		default:
-			return 1;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	(void) pci_write_config_byte(dev, pciU, regU);
-	regD |= (unit ? 0x40 : 0x20);
-	(void) pci_write_config_byte(dev, pciD, regD);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-static int cmd680_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 speed		= cmd64x_ratefilter(drive, xferspeed);
-	u8 dma_pci		= 0;
-	u8 udma_pci		= 0;
-	u8 mode_pci		= 0;
-	u8 scsc			= 0;
-	u16 ultra		= 0;
-	u16 multi		= 0;
-
-        pci_read_config_byte(dev, addr_mask, &mode_pci);
-	pci_read_config_byte(dev, 0x8A, &scsc);
-
-        switch (drive->dn) {
-		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
-		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
-		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
-		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
-		default: return 1;
-	}
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-	pci_read_config_word(dev, dma_pci, &multi);
-	pci_read_config_word(dev, udma_pci, &ultra);
-
-	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
-		pci_write_config_byte(dev, 0x8A, scsc|0x01);
-		pci_read_config_byte(dev, 0x8A, &scsc);
-#if 0
-		/* if 133 clock fails, switch to 2xbus clock */
-		if (!(scsc & 0x01))
-			pci_write_config_byte(dev, 0x8A, scsc|0x10);
-#endif
-	}
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_6:
-			if ((scsc & 0x30) == 0x00)
-				goto speed_break;
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= 0x01;
-			break;
-speed_break :
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
-			break;
-		case XFER_UDMA_4:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
-			break;
-		case XFER_UDMA_3:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
-			break;
-		case XFER_UDMA_2:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
-			break;
-		case XFER_UDMA_1:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
-			break;
-		case XFER_UDMA_0:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
-			break;
-		case XFER_MW_DMA_2:
-			multi = 0x10C1;
-			break;
-		case XFER_MW_DMA_1:
-			multi = 0x10C2;
-			break;
-		case XFER_MW_DMA_0:
-			multi = 0x2208;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
-		default:
-			return 1;
-	}
-	
-	if (speed >= XFER_MW_DMA_0) 
-		config_cmd680_chipset_for_pio(drive, 0);
-
-	if (speed >= XFER_UDMA_0)
-		mode_pci |= ((unit) ? 0x30 : 0x03);
-	else if (speed >= XFER_MW_DMA_0)
-		mode_pci |= ((unit) ? 0x20 : 0x02);
-	else
-		mode_pci |= ((unit) ? 0x10 : 0x01);
-
-	pci_write_config_byte(dev, addr_mask, mode_pci);
-	pci_write_config_word(dev, dma_pci, multi);
-	pci_write_config_word(dev, udma_pci, ultra);
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte mode               = cmd64x_ratemask(drive);
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	int rval;
-
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check,"
-			" inital check failed!!\n");
-		return ((int) ide_dma_off);
-	}
-
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			{ set_pio = 1; break; }
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	config_chipset_for_pio(drive, set_pio);
-
-	if (set_pio)
-		return ((int) ide_dma_off_quietly);
-
-	if (hwif->speedproc(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->media == ide_disk)) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive, 1);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-        return ide_dmaproc(func, drive);
-}
-
-static int cmd64x_alt_dma_status (struct pci_dev *dev)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			return 1;
-		default:
-			break;
-	}
-	return 0;
-}
-
-static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte dma_alt_stat	= 0;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte mask		= (hwif->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= hwif->dma_base;
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte alt_dma_stat	= cmd64x_alt_dma_status(dev);
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
-			/* get DMA status */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* clear the INTR & ERROR bits */
-			OUT_BYTE(dma_stat|6, dma_base+2);
-			if (alt_dma_stat) {
-				byte dma_intr	= 0;
-				byte dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
-				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-				/* clear the INTR bit */
-				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
-			}
-			/* purge DMA mappings */
-			ide_destroy_dmatable(drive);
-			/* verify good DMA status */
-			return (dma_stat & 7) != 4;
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
-#ifdef DEBUG
-			printk("%s: dma_stat: 0x%02x dma_alt_stat: "
-				"0x%02x mask: 0x%02x\n", drive->name,
-				dma_stat, dma_alt_stat, mask);
-#endif
-			if (!(dma_alt_stat & mask)) {
-				return 0;
-			}
-			/* return 1 if INTR asserted */
-			return (dma_stat & 4) == 4;
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			/* get DMA status */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
-			/* clear the INTR & ERROR bits */
-			OUT_BYTE(dma_stat|6, dma_base+2);
-			/* and free any DMA resources */
-			ide_destroy_dmatable(drive);
-			/* verify good DMA status */
-			return (dma_stat & 7) != 4;
-		default:
-			break;
-	}
-
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static int cmd680_busproc (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	u32 stat_config		= 0;
-
-        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
-
-	if (!hwif)
-		return -EINVAL;
-
-	switch (state) {
-		case BUSSTATE_ON:
-			hwif->drives[0].failures = 0;
-			hwif->drives[1].failures = 0;
-			break;
-		case BUSSTATE_OFF:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		case BUSSTATE_TRISTATE:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		default:
-			return 0;
-	}
-	hwif->bus_state = state;
-#endif
-	return 0;
-}
-
-void cmd680_reset (ide_drive_t *drive)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	byte reset		= 0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
-	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
-#endif
-}
-
-unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
-{
-	u8 tmpbyte	= 0;	
-	pci_write_config_byte(dev, 0x80, 0x00);
-	pci_write_config_byte(dev, 0x84, 0x00);
-	pci_read_config_byte(dev, 0x8A, &tmpbyte);
-	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
-#if 0
-	/* if 133 clock fails, switch to 2xbus clock */	
-	if (!(tmpbyte & 0x01)) {
-		pci_read_config_byte(dev, 0x8A, &tmpbyte);
-		pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);		
-	}
-#endif
-	pci_write_config_word(dev, 0xA2, 0x328A);
-	pci_write_config_dword(dev, 0xA4, 0x328A);
-	pci_write_config_dword(dev, 0xA8, 0x4392);
-	pci_write_config_dword(dev, 0xAC, 0x4009);
-	pci_write_config_word(dev, 0xB2, 0x328A);
-	pci_write_config_dword(dev, 0xB4, 0x328A);
-	pci_write_config_dword(dev, 0xB8, 0x4392);
-	pci_write_config_dword(dev, 0xBC, 0x4009);
-
-	cmd_devs[n_cmd_devs++] = dev;
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		cmd64x_display_info = &cmd64x_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
-{
-	unsigned char mrdmode;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-#ifdef __i386__
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-#endif
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_643:
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", name, class_rev);
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:
-					printk("UltraDMA Capable");
-					break;
-				case 0x03:
-					printk("MultiWord DMA Force Limited");
-					break;
-				case 0x01:
-				default:
-					printk("MultiWord DMA Limited, IRQ workaround enabled");
-					break;
-				}
-			printk("\n");
-                        break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			break;
-		default:
-			break;
-	}
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-
-	/* Setup interrupts. */
-	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
-	mrdmode &= ~(0x30);
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
-
-	/* Use MEMORY READ LINE for reads.
-	 * NOTE: Although not mentioned in the PCI0646U specs,
-	 *       these bits are write only and won't be read
-	 *       back as set or not.  The PCI0646U2 specs clarify
-	 *       this point.
-	 */
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#ifdef CONFIG_PPC
-	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
-#endif /* CONFIG_PPC */
-
-	cmd_devs[n_cmd_devs++] = dev;
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		cmd64x_display_info = &cmd64x_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			return cmd680_pci_init (dev, name);
-		default:
-			break;
-	}
-	return cmd64x_pci_init (dev, name);
-}
-
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66	= 0;
-	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
-	return (ata66 & 0x01) ? 1 : 0;
-}
-
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66 = 0;
-	byte mask = (hwif->channel) ? 0x02 : 0x01;
-
-	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
-	return (ata66 & mask) ? 1 : 0;
-}
-
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
-{
-	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			return cmd680_ata66(hwif);
-		default:
-			break;
-	}
-	return cmd64x_ata66(hwif);
-}
-
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			hwif->busproc	= &cmd680_busproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-			if (hwif->dma_base)
-				hwif->dmaproc	= &cmd680_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-			hwif->resetproc = &cmd680_reset;
-			hwif->speedproc	= &cmd680_tune_chipset;
-			hwif->tuneproc	= &cmd680_tuneproc;
-			break;
-		case PCI_DEVICE_ID_CMD_649:
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_643:
-#ifdef CONFIG_BLK_DEV_IDEDMA
-			if (hwif->dma_base)
-				hwif->dmaproc	= &cmd64x_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc = &cmd64x_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			hwif->chipset = ide_cmd646;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-			if (hwif->dma_base) {
-				if (class_rev == 0x01)
-					hwif->dmaproc = &cmd646_1_dmaproc;
-				else
-					hwif->dmaproc = &cmd64x_dmaproc;
-			}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc	= &cmd64x_tune_chipset;
-			break;
-		default:
-			break;
-	}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IDEDMA_AUTO)
-	if (hwif->dma_base)
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA && CONFIG_IDEDMA_AUTO*/
-}
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Sun Sep 15 19:19:30 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,386 +0,0 @@
-/*
- * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
- *
- * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
- * Ditto of GNU General Public License.
- *
- * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_CS5530_TIMINGS
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cs5530_get_info(char *, char **, off_t, int);
-extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                "
-			"Cyrix 5530 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled "
-			"                        %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s "
-			"            %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;
-}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-byte cs5530_proc = 0;
-
-/*
- * Set a new transfer mode at the drive
- */
-int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-	printk("%s: cs5530_set_xfer_mode(%s)\n",
-		drive->name, ide_xfer_verbose(mode));
-	return (ide_config_drive_speed(drive, mode));
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] =
-	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
-	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
- *
- * The ide_init_cs5530() routine guarantees that all drives
- * will have valid default PIO timings set up before we get here.
- */
-static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	unsigned int	format, basereg = CS5530_BASEREG(hwif);
-	static byte	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
-		format = (inl(basereg+4) >> 31) & 1;
-		outl(cs5530_pio_timings[format][pio],
-			basereg+(drive->select.b.unit<<3));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
- * for both the chipset and drive.
- */
-static int cs5530_config_dma (ide_drive_t *drive)
-{
-	int			udma_ok = 1, mode = 0;
-	ide_hwif_t		*hwif = HWIF(drive);
-	int			unit = drive->select.b.unit;
-	ide_drive_t		*mate = &hwif->drives[unit^1];
-	struct hd_driveid	*id = drive->id;
-	unsigned int		basereg, reg, timings;
-
-	/*
-	 * Default to DMA-off in case we run into trouble here.
-	 */
-	(void)hwif->dmaproc(ide_dma_off_quietly, drive);
-	/* turn off DMA while we fiddle */
-	(void)hwif->dmaproc(ide_dma_host_off, drive);
-	/* clear DMA_capable bit */
-
-	/*
-	 * The CS5530 specifies that two drives sharing a cable cannot
-	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
-	 * though different timings can still be chosen for each drive.
-	 * We could set the appropriate timing bits on the fly,
-	 * but that might be a bit confusing.  So, for now we statically
-	 * handle this requirement by looking at our mate drive to see
-	 * what it is capable of, before choosing a mode for our own drive.
-	 */
-	if (mate->present) {
-		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) &&
-		    !hwif->dmaproc(ide_dma_bad_drive, mate)) {
-			if ((mateid->field_valid & 4) &&
-			    (mateid->dma_ultra & 7))
-				udma_ok = 1;
-			else if ((mateid->field_valid & 2) &&
-				 (mateid->dma_mword & 7))
-				udma_ok = 0;
-			else
-				udma_ok = 1;
-		}
-	}
-
-	/*
-	 * Now see what the current drive is capable of,
-	 * selecting UDMA only if the mate said it was ok.
-	 */
-	if (id && (id->capability & 1) && hwif->autodma &&
-	    !hwif->dmaproc(ide_dma_bad_drive, drive)) {
-		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
-			if      (id->dma_ultra & 4)
-				mode = XFER_UDMA_2;
-			else if (id->dma_ultra & 2)
-				mode = XFER_UDMA_1;
-			else if (id->dma_ultra & 1)
-				mode = XFER_UDMA_0;
-		}
-		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
-			if      (id->dma_mword & 4)
-				mode = XFER_MW_DMA_2;
-			else if (id->dma_mword & 2)
-				mode = XFER_MW_DMA_1;
-			else if (id->dma_mword & 1)
-				mode = XFER_MW_DMA_0;
-		}
-	}
-
-	/*
-	 * Tell the drive to switch to the new mode; abort on failure.
-	 */
-	if (!mode || cs5530_set_xfer_mode(drive, mode))
-		return 1;	/* failure */
-
-	/*
-	 * Now tune the chipset to match the drive:
-	 */
-	switch (mode) {
-		case XFER_UDMA_0:	timings = 0x00921250; break;
-		case XFER_UDMA_1:	timings = 0x00911140; break;
-		case XFER_UDMA_2:	timings = 0x00911030; break;
-		case XFER_MW_DMA_0:	timings = 0x00077771; break;
-		case XFER_MW_DMA_1:	timings = 0x00012121; break;
-		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		default:
-			printk("%s: cs5530_config_dma: huh? mode=%02x\n",
-				drive->name, mode);
-			return 1;	/* failure */
-	}
-	basereg = CS5530_BASEREG(hwif);
-	reg = inl(basereg+4);		/* get drive0 config register */
-	timings |= reg & 0x80000000;		/* preserve PIO format bit */
-	if (unit == 0) {			/* are we configuring drive0? */
-		outl(timings, basereg+4);	/* write drive0 config register */
-	} else {
-		if (timings & 0x00100000)
-			reg |=  0x00100000;	/* enable UDMA timings for both drives */
-		else
-			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
-		outl(reg,     basereg+4);	/* write drive0 config register */
-		outl(timings, basereg+12);	/* write drive1 config register */
-	}
-	(void)hwif->dmaproc(ide_dma_host_on, drive);
-	/* set DMA_capable bit */
-
-	/*
-	 * Finally, turn DMA on in software, and exit.
-	 */
-	return hwif->dmaproc(ide_dma_on, drive);	/* success */
-}
-
-/*
- * This is a CS5530-specific wrapper for the standard ide_dmaproc().
- * We need it for our custom "ide_dma_check" function.
- * All other requests are forwarded to the standard ide_dmaproc().
- */
-int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cs5530_config_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-	unsigned short pcicmd = 0;
-	unsigned long flags;
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cs5530_proc) {
-		cs5530_proc = 1;
-		bmide_dev = dev;
-		cs5530_display_info = &cs5530_get_info;
-	}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-	pci_for_each_dev (dev) {
-		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
-			switch (dev->device) {
-				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
-					master_0 = dev;
-					break;
-				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-					cs5530_0 = dev;
-					break;
-			}
-		}
-	}
-	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", name);
-		return 0;
-	}
-	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", name);
-		return 0;
-	}
-
-	spin_lock_irqsave(&ide_lock, flags);
-		/* all CPUs (there should only be one CPU with this chipset) */
-
-	/*
-	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
-	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
-	 */
-	pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd);
-	pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
-
-	/*
-	 * Set PCI CacheLineSize to 16-bytes:
-	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
-	 */
-	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
-	/*
-	 * Disable trapping of UDMA register accesses (Win98 hack):
-	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
-	 */
-	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
-	/*
-	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
-	 * The other settings are what is necessary to get the register
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x40, 0x1e);
-
-	/* 
-	 * Set max PCI burst size (16-bytes seems to work best):
-	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
-	 *	all others: clear bit-1 at 0x41, and do:
-	 *	  128bytes: OR 0x00 at 0x41
-	 *	  256bytes: OR 0x04 at 0x41
-	 *	  512bytes: OR 0x08 at 0x41
-	 *	 1024bytes: OR 0x0c at 0x41
-	 */
-	pci_write_config_byte(master_0, 0x41, 0x14);
-
-	/*
-	 * These settings are necessary to get the chip
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x42, 0x00);
-	pci_write_config_byte(master_0, 0x43, 0xc1);
-
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	return 0;
-}
-
-/*
- * This gets invoked by the IDE driver once for each channel,
- * and performs channel-specific pre-initialization before drive probing.
- */
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
-{
-	unsigned int basereg, d0_timings;
-	hwif->autodma = 0;
-
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-
-	hwif->tuneproc = &cs5530_tuneproc;
-	basereg = CS5530_BASEREG(hwif);
-	d0_timings = inl(basereg+0);
-	if (CS5530_BAD_PIO(d0_timings)) {
-		/* PIO timings not initialized? */
-		outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
-		if (!hwif->drives[0].autotune)
-			hwif->drives[0].autotune = 1;
-			/* needs autotuning later */
-	}
-	if (CS5530_BAD_PIO(inl(basereg+8))) {
-	/* PIO timings not initialized? */
-		outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
-		if (!hwif->drives[1].autotune)
-			hwif->drives[1].autotune = 1;
-			/* needs autotuning later */
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc  = &cs5530_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,478 +0,0 @@
-/*
- * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
- *
- *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>, Integrater
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- * Writting the driver was quite simple, since most of the job is
- * done by the generic pci-ide support. 
- * The hard part was finding the CY82C693's datasheet on Cypress's
- * web page :-(. But Altavista solved this problem :-).
- *
- *
- * Notes:
- * - I recently got a 16.8G IBM DTTA, so I was able to test it with
- *   a large and fast disk - the results look great, so I'd say the
- *   driver is working fine :-)
- *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
- * - this is my first linux driver, so there's probably a lot  of room 
- *   for optimizations and bug fixing, so feel free to do it.
- * - use idebus=xx parameter to set PCI bus speed - needed to calc
- *   timings for PIO modes (default will be 40)
- * - if using PIO mode it's a good idea to set the PIO mode and 
- *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
- * - I had some problems with my IBM DHEA with PIO modes < 2
- *   (lost interrupts) ?????
- * - first tests with DMA look okay, they seem to work, but there is a
- *   problem with sound - the BusMaster IDE TimeOut should fixed this
- *
- *
- * History:
- * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
- * ASK@1999-01-23: v0.33 made a few minor code clean ups
- *                       removed DMA clock speed setting by default
- *                       added boot message
- * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
- *                       added support to set DMA Controller Clock Speed
- * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive
- * ASK@1998-10-29: v0.3 added support to set DMA modes
- * ASK@1998-10-28: v0.2 added support to set PIO modes
- * ASK@1998-10-27: v0.1 first version - chipset detection
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
-/*
- *	The following are used to debug the driver.
- */
-#define	CY82C693_DEBUG_LOGS	0
-#define	CY82C693_DEBUG_INFO	0
-
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
-/*
- * note: the value for busmaster timeout is tricky and i got it by trial and error !
- *       using a to low value will cause DMA timeouts and drop IDE performance
- *       using a to high value will cause audio playback to scatter
- *       if you know a better value or how to calc it, please let me know 
- */
-#define BUSMASTER_TIMEOUT	0x50	/* twice the value written in cy82c693ub datasheet */
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG		0x04
-#define CY82_IDE_ADDRSETUP	0x48
-#define CY82_IDE_MASTER_IOR	0x4C	
-#define CY82_IDE_MASTER_IOW	0x4D	
-#define CY82_IDE_SLAVE_IOR	0x4E	
-#define CY82_IDE_SLAVE_IOW	0x4F
-#define CY82_IDE_MASTER_8BIT	0x50	
-#define CY82_IDE_SLAVE_8BIT	0x51	
-
-#define CY82_INDEX_PORT		0x22
-#define CY82_DATA_PORT		0x23
-
-#define CY82_INDEX_CTRLREG1	0x01
-#define CY82_INDEX_CHANNEL0	0x30
-#define CY82_INDEX_CHANNEL1	0x31
-#define CY82_INDEX_TIMEOUT	0x32
-
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO	4
-
-/* the min and max PCI bus speed in MHz - from datasheet */
-#define CY82C963_MIN_BUS_SPEED	25
-#define CY82C963_MAX_BUS_SPEED	33
-
-/* the struct for the PIO mode timings */
-typedef struct pio_clocks_s {
-        byte	address_time;	/* Address setup (clocks) */
-	byte	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
-} pio_clocks_t;
-
-/*
- * calc clocks using bus_speed
- * returns (rounded up) time in bus clocks for time in ns
- */
-static int calc_clk (int time, int bus_speed)
-{
-	int clocks;
-
-	clocks = (time*bus_speed+999)/1000 -1;
-
-	if (clocks < 0)
-		clocks = 0;
-
-	if (clocks > 0x0F)
-		clocks = 0x0F;
-
-	return clocks;
-}
-
-/*
- * compute the values for the clock registers for PIO
- * mode and pci_clk [MHz] speed
- *
- * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
- *       for mode 3 and 4 drives 8 and 16-bit timings are the same
- *
- */ 
-static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
-{
-	int clk1, clk2;
-	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
-
-	/* we don't check against CY82C693's min and max speed,
-	 * so you can play with the idebus=xx parameter
-	 */
-
-	if (pio > CY82C693_MAX_PIO)
-		pio = CY82C693_MAX_PIO;
-
-	/* let's calc the address setup time clocks */
-	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
-
-	/* let's calc the active and recovery time clocks */
-	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
-
-	/* calc recovery timing */
-	clk2 =	ide_pio_timings[pio].cycle_time -
-		ide_pio_timings[pio].active_time -
-		ide_pio_timings[pio].setup_time;
-
-	clk2 = calc_clk(clk2, bus_speed);
-
-	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
-
-	/* note: we use the same values for 16bit IOR and IOW
-         *	those are all the same, since I don't have other
-	 *	timings than those from ide_modes.h
-	 */
-
-	p_pclk->time_16r = (byte)clk1;
-	p_pclk->time_16w = (byte)clk1;
-
-	/* what are good values for 8bit ?? */
-	p_pclk->time_8 = (byte)clk1;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * set DMA mode a specific channel for CY82C693
- */
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
-{
-	byte index;
-	byte data;
-
-	if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
-
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the previous values */
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	data = IN_BYTE(CY82_DATA_PORT);
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
-		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		(data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
-	data = (byte)mode|(byte)(single<<2);
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
-		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		mode, single);
-#endif /* CY82C693_DEBUG_INFO */
-
-	/* 
-	 * note: below we set the value for Bus Master IDE TimeOut Register
-	 * I'm not absolutly sure what this does, but it solved my problem
-	 * with IDE DMA and sound, so I now can play sound and work with
-	 * my IDE driver at the same time :-)
-	 *
-	 * If you know the correct (best) value for this register please
-	 * let me know - ASK
-	 */
-
-	data = BUSMASTER_TIMEOUT;
-	OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO	
-	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
-		drive->name, data);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	/*
-	 * if the function is dma on, set dma mode for drive everything
-	 * else is done by the defaul func
-	 */
-	if (func == ide_dma_on) {
-		struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-		printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-		if (id != NULL) {		
-                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
-                       if (id->field_valid & 2) {       /* regular DMA */
-			       int mmode, smode;
-
-			       mmode = id->dma_mword & (id->dma_mword >> 8);
-			       smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-		               if (mmode != 0)
-				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
-			       else if (smode != 0)
-				     cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
-			}
-		}
-	}
-        return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	pio_clocks_t pclk;
-	unsigned int addrCtrl;
-
-	/* select primary or secondary channel */
-	if (hwif->index > 0) {  /* drive is on the secondary channel */
-		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
-		if (!dev) {
-			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
-			return;
-		}
-	}
-
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the register values */
-	
-       	if (drive->select.b.unit == 0) {
-		/*
-		 * get master drive registers               	
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
-		addrCtrl &= 0x0F;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-	} else {
-		/*
-		 * set slave drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= 0xF0;
-		addrCtrl >>= 4;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-	}
-
-	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
-		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-		drive->name, hwif->channel, drive->select.b.unit,
-		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
-        /* first let's calc the pio modes */
-	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
-        compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
-
-	/* now let's write  the clocks registers */
-	if (drive->select.b.unit == 0) {
-		/*
-		 * set master drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-		
-		addrCtrl &= (~0xF);
-		addrCtrl |= (unsigned int)pclk.address_time;
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-		
-		addrCtrl &= 0xF;
-	} else {
-		/*
-		 * set slave drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= (~0xF0);
-		addrCtrl |= ((unsigned int)pclk.address_time<<4);
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
-
-		addrCtrl >>= 4;
-		addrCtrl &= 0xF;
-	}	
-
-#if CY82C693_DEBUG_INFO
-	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
-		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
-		drive->name, hwif->channel, drive->select.b.unit,
-		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-/*
- * FIXME! "pci_init_cy82c693" really should replace
- * the "init_cy82c693_chip", it is the correct location to tinker/setup
- * the device prior to INIT.
- */
-
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
-{
-#ifdef CY82C693_SETDMA_CLOCK
-        byte data;
-#endif /* CY82C693_SETDMA_CLOCK */ 
-
-	/* write info about this verion of the driver */
-	printk(KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-        
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        data = IN_BYTE(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
-		name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-        /*
-	 * for some reason sometimes the DMA controller
-	 * speed is set to ATCLK/2 ???? - we fix this here
-	 * 
-	 * note: i don't know what causes this strange behaviour,
-	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed 
-	 * 
-	 *       if anybody knows what goes wrong with my machine, please
-	 *       let me know - ASK
-         */
-
-	data |= 0x03;
-
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
-		name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-	return 0;
-}
-
-/*
- * the init function - called for each ide channel once
- */
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
-{
-	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-	if (!hwif->dma_base)
-		return;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &cy82c693_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_cy82c693 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-        if ((!(PCI_FUNC(dev->devfn) & 1) ||
-	    (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
-		return;	/* CY82C693 is more than only a IDE controller */
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
diff -Nru a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
--- a/drivers/ide/dtc2278.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,132 +0,0 @@
-/*
- *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed.  If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
-	int i;
-
-	for(i = 0; i < 3; ++i) {
-		IN_BYTE(0x3f6);
-		outb_p(b,0xb0);
-		IN_BYTE(0x3f6);
-		outb_p(c,0xb4);
-		IN_BYTE(0x3f6);
-		if(IN_BYTE(0xb4) == c) {
-			outb_p(7,0xb0);
-			IN_BYTE(0x3f6);
-			return;	/* success */
-		}
-	}
-}
-
-static void tune_dtc2278 (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	if (pio >= 3) {
-		spin_lock_irqsave(&ide_lock, flags);
-		/*
-		 * This enables PIO mode4 (3?) on the first interface
-		 */
-		sub22(1,0xc3);
-		sub22(0,0xa0);
-		spin_unlock_irqrestore(&ide_lock, flags);
-	} else {
-		/* we don't know how to set it back again.. */
-	}
-
-	/*
-	 * 32bit I/O has to be enabled for *both* drives at the same time.
-	 */
-	drive->io_32bit = 1;
-	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
-}
-
-void __init init_dtc2278 (void)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	/*
-	 * This enables the second interface
-	 */
-	outb_p(4,0xb0);
-	IN_BYTE(0x3f6);
-	outb_p(0x20,0xb4);
-	IN_BYTE(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
-	/*
-	 * This enables PIO mode4 (3?) on the first interface
-	 * and may solve start-up problems for some people.
-	 */
-	sub22(1,0xc3);
-	sub22(0,0xa0);
-#endif
-	local_irq_restore(flags);
-
-	ide_hwifs[0].serialized = 1;
-	ide_hwifs[1].serialized = 1;
-	ide_hwifs[0].chipset = ide_dtc2278;
-	ide_hwifs[1].chipset = ide_dtc2278;
-	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	ide_hwifs[0].drives[0].no_unmask = 1;
-	ide_hwifs[0].drives[1].no_unmask = 1;
-	ide_hwifs[1].drives[0].no_unmask = 1;
-	ide_hwifs[1].drives[1].no_unmask = 1;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Nru a/drivers/ide/falconide.c b/drivers/ide/falconide.c
--- a/drivers/ide/falconide.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-/*
- *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
- *
- *     Created 12 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-
-
-    /*
-     *  Base of the IDE interface
-     */
-
-#define ATA_HD_BASE	0xfff00000
-
-    /*
-     *  Offsets from the above base
-     */
-
-#define ATA_HD_DATA	0x00
-#define ATA_HD_ERROR	0x05		/* see err-bits */
-#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
-#define ATA_HD_SECTOR	0x0d		/* starting sector */
-#define ATA_HD_LCYL	0x11		/* starting cylinder */
-#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
-#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS	0x1d		/* see status-bits */
-#define ATA_HD_CONTROL	0x39
-
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
-    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
-    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
-    /*
-     *  Probe for a Falcon IDE interface
-     */
-
-void __init falconide_init(void)
-{
-    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
-	hw_regs_t hw;
-	int index;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
-			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
-
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
-    }
-}
diff -Nru a/drivers/ide/gayle.c b/drivers/ide/gayle.c
--- a/drivers/ide/gayle.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,181 +0,0 @@
-/*
- *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
- *
- *     Created 9 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
-#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define GAYLE_DATA	0x00
-#define GAYLE_ERROR	0x06		/* see err-bits */
-#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define GAYLE_SECTOR	0x0e		/* starting sector */
-#define GAYLE_LCYL	0x12		/* starting cylinder */
-#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
-#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS	0x1e		/* see status-bits */
-#define GAYLE_CONTROL	0x101a
-
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
-    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
-    /*
-     *  These are at different offsets from the base
-     */
-
-#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
-
-
-    /*
-     *  Offset of the secondary port for IDE doublers
-     *  Note that GAYLE_CONTROL is NOT available then!
-     */
-
-#define GAYLE_NEXT_PORT	0x1000
-
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS		1
-#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG	1
-#define GAYLE_IDEREG_SIZE	0x2000
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
-#define GAYLE_NUM_HWIFS		2
-#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
-					       GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
-#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
-int ide_doubler = 0;	/* support IDE doublers? */
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    return 1;
-}
-
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
-    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
-    return 1;
-}
-
-    /*
-     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-     */
-
-void __init gayle_init(void)
-{
-    int a4000, i;
-
-    if (!MACH_IS_AMIGA)
-	return;
-
-    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
-	return;
-
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-	ide_ioreg_t base, ctrlport, irqport;
-	ide_ack_intr_t *ack_intr;
-	hw_regs_t hw;
-	int index;
-	unsigned long phys_base, res_start, res_n;
-
-	if (a4000) {
-	    phys_base = GAYLE_BASE_4000;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
-	    ack_intr = gayle_ack_intr_a4000;
-	} else {
-	    phys_base = GAYLE_BASE_1200;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
-	    ack_intr = gayle_ack_intr_a1200;
-	}
-	phys_base += i*GAYLE_NEXT_PORT;
-
-	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-	res_n = GAYLE_IDEREG_SIZE;
-
-	if (!request_mem_region(res_start, res_n, "IDE"))
-	    continue;
-
-	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
-	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
-
-	ide_setup_ports(&hw, base, gayle_offsets,
-			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
-
-	index = ide_register_hw(&hw, NULL);
-	if (index != -1) {
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
-	} else
-	    release_mem_region(res_start, res_n);
-
-#if 1 /* TESTING */
-	if (i == 1) {
-	    volatile u_short *addr = (u_short *)base;
-	    u_short data;
-	    printk("+++ Probing for IDE doubler... ");
-	    *addr = 0xffff;
-	    data = *addr;
-	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
-	}
-#endif /* TESTING */
-    }
-}
diff -Nru a/drivers/ide/hd.c b/drivers/ide/hd.c
--- a/drivers/ide/hd.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,879 +0,0 @@
-/*
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- * This is the low-level hd interrupt support. It traverses the
- * request-list, using interrupts to jump between functions. As
- * all the functions are called within interrupts, we may not
- * sleep. Special care is recommended.
- *
- *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *
- *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  in the early extended-partition checks and added DM partitions
- *
- *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  and general streamlining by Mark Lord.
- *
- *  Removed 99% of above. Use Mark's ide driver for those options.
- *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
- *
- *  Modified 1995 Russell King for ARM processor.
- *
- *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
- *  off in a hurry once you queue things up - Paul G. 02/2001
- */
-
-/* Uncomment the following if you want verbose error reports. */
-/* #define VERBOSE_ERRORS */
-
-#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/genhd.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/mc146818rtc.h> /* CMOS defines */
-#include <linux/init.h>
-#include <linux/blkpg.h>
-#include <linux/hdreg.h>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR HD_MAJOR
-#define DEVICE_NR(device) (minor(device)>>6)
-#include <linux/blk.h>
-
-/* ATA commands we use.
- */
-#define WIN_SPECIFY	0x91 /* set drive geometry translation */
-#define WIN_RESTORE	0x10
-#define WIN_READ	0x20 /* 28-Bit */
-#define WIN_WRITE	0x30 /* 28-Bit */
-
-#define HD_IRQ 14	/* the standard disk interrupt */
-
-#ifdef __arm__
-#undef  HD_IRQ
-#endif
-#include <asm/irq.h>
-#ifdef __arm__
-#define HD_IRQ IRQ_HARDDISK
-#endif
-
-/* Hd controller regster ports */
-
-#define HD_DATA		0x1f0		/* _CTL when writing */
-#define HD_ERROR	0x1f1		/* see err-bits */
-#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
-#define HD_SECTOR	0x1f3		/* starting sector */
-#define HD_LCYL		0x1f4		/* starting cylinder */
-#define HD_HCYL		0x1f5		/* high byte of starting cyl */
-#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS	0x1f7		/* see status-bits */
-#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
-#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
-#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
-
-#define HD_CMD		0x3f6		/* used for resets */
-#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
-
-/* Bits of HD_STATUS */
-#define ERR_STAT		0x01
-#define INDEX_STAT		0x02
-#define ECC_STAT		0x04	/* Corrected error */
-#define DRQ_STAT		0x08
-#define SEEK_STAT		0x10
-#define SERVICE_STAT		SEEK_STAT
-#define WRERR_STAT		0x20
-#define READY_STAT		0x40
-#define BUSY_STAT		0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR		0x01	/* Bad address mark */
-#define TRK0_ERR		0x02	/* couldn't find track 0 */
-#define ABRT_ERR		0x04	/* Command aborted */
-#define MCR_ERR			0x08	/* media change request */
-#define ID_ERR			0x10	/* ID field not found */
-#define MC_ERR			0x20	/* media changed */
-#define ECC_ERR			0x40	/* Uncorrectable ECC error */
-#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
-#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
-
-static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
-
-#define TIMEOUT_VALUE	(6*HZ)
-#define	HD_DELAY	0
-
-#define MAX_ERRORS     16	/* Max read/write errors/sector */
-#define RESET_FREQ      8	/* Reset controller every 8th retry */
-#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
-#define MAX_HD		2
-
-#define STAT_OK		(READY_STAT|SEEK_STAT)
-#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
-
-static void recal_intr(void);
-static void bad_rw_intr(void);
-
-static char recalibrate[MAX_HD];
-static char special_op[MAX_HD];
-
-static int reset;
-static int hd_error;
-
-#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
-
-/*
- *  This struct defines the HD's and their types.
- */
-struct hd_i_struct {
-	unsigned int head,sect,cyl,wpcom,lzone,ctl;
-};
-	
-#ifdef HD_TYPE
-static struct hd_i_struct hd_info[] = { HD_TYPE };
-static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
-#else
-static struct hd_i_struct hd_info[MAX_HD];
-static int NR_HD;
-#endif
-
-static struct timer_list device_timer;
-
-#define TIMEOUT_VALUE (6*HZ)
-
-#define SET_TIMER							\
-	do {								\
-		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
-	} while (0)
-
-static void (*do_hd)(void) = NULL;
-#define SET_HANDLER(x) \
-if ((do_hd = (x)) != NULL) \
-	SET_TIMER; \
-else \
-	del_timer(&device_timer);
-
-
-#if (HD_DELAY > 0)
-unsigned long last_req;
-
-unsigned long read_timer(void)
-{
-        extern spinlock_t i8253_lock;
-	unsigned long t, flags;
-	int i;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	spin_unlock_irqrestore(&i8253_lock, flags);
-	return(t - i);
-}
-#endif
-
-void __init hd_setup(char *str, int *ints)
-{
-	int hdind = 0;
-
-	if (ints[0] != 3)
-		return;
-	if (hd_info[0].head != 0)
-		hdind=1;
-	hd_info[hdind].head = ints[2];
-	hd_info[hdind].sect = ints[3];
-	hd_info[hdind].cyl = ints[1];
-	hd_info[hdind].wpcom = 0;
-	hd_info[hdind].lzone = ints[1];
-	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
-	NR_HD = hdind+1;
-}
-
-static void dump_status (const char *msg, unsigned int stat)
-{
-	char devc;
-
-	devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
-#ifdef VERBOSE_ERRORS
-	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
-	if (stat & BUSY_STAT)	printk("Busy ");
-	if (stat & READY_STAT)	printk("DriveReady ");
-	if (stat & WRERR_STAT)	printk("WriteFault ");
-	if (stat & SEEK_STAT)	printk("SeekComplete ");
-	if (stat & DRQ_STAT)	printk("DataRequest ");
-	if (stat & ECC_STAT)	printk("CorrectedError ");
-	if (stat & INDEX_STAT)	printk("Index ");
-	if (stat & ERR_STAT)	printk("Error ");
-	printk("}\n");
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
-		if (hd_error & BBD_ERR)		printk("BadSector ");
-		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
-		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
-		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
-		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
-		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
-		printk("}");
-		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
-			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
-				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-			if (!blk_queue_empty(QUEUE))
-				printk(", sector=%ld", CURRENT->sector);
-		}
-		printk("\n");
-	}
-#else
-	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
-	}
-#endif
-}
-
-void check_status(void)
-{
-	int i = inb_p(HD_STATUS);
-
-	if (!OK_STATUS(i)) {
-		dump_status("check_status", i);
-		bad_rw_intr();
-	}
-}
-
-static int controller_busy(void)
-{
-	int retries = 100000;
-	unsigned char status;
-
-	do {
-		status = inb_p(HD_STATUS);
-	} while ((status & BUSY_STAT) && --retries);
-	return status;
-}
-
-static int status_ok(void)
-{
-	unsigned char status = inb_p(HD_STATUS);
-
-	if (status & BUSY_STAT)
-		return 1;	/* Ancient, but does it make sense??? */
-	if (status & WRERR_STAT)
-		return 0;
-	if (!(status & READY_STAT))
-		return 0;
-	if (!(status & SEEK_STAT))
-		return 0;
-	return 1;
-}
-
-static int controller_ready(unsigned int drive, unsigned int head)
-{
-	int retry = 100;
-
-	do {
-		if (controller_busy() & BUSY_STAT)
-			return 0;
-		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
-		if (status_ok())
-			return 1;
-	} while (--retry);
-	return 0;
-}
-
-static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
-		unsigned int head,unsigned int cyl,unsigned int cmd,
-		void (*intr_addr)(void))
-{
-	unsigned short port;
-
-#if (HD_DELAY > 0)
-	while (read_timer() - last_req < HD_DELAY)
-		/* nothing */;
-#endif
-	if (reset)
-		return;
-	if (!controller_ready(drive, head)) {
-		reset = 1;
-		return;
-	}
-	SET_HANDLER(intr_addr);
-	outb_p(hd_info[drive].ctl,HD_CMD);
-	port=HD_DATA;
-	outb_p(hd_info[drive].wpcom>>2,++port);
-	outb_p(nsect,++port);
-	outb_p(sect,++port);
-	outb_p(cyl,++port);
-	outb_p(cyl>>8,++port);
-	outb_p(0xA0|(drive<<4)|head,++port);
-	outb_p(cmd,++port);
-}
-
-static void hd_request (void);
-
-static int drive_busy(void)
-{
-	unsigned int i;
-	unsigned char c;
-
-	for (i = 0; i < 500000 ; i++) {
-		c = inb_p(HD_STATUS);
-		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
-			return 0;
-	}
-	dump_status("reset timed out", c);
-	return 1;
-}
-
-static void reset_controller(void)
-{
-	int	i;
-
-	outb_p(4,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	if (drive_busy())
-		printk("hd: controller still busy\n");
-	else if ((hd_error = inb(HD_ERROR)) != 1)
-		printk("hd: controller reset failed: %02x\n",hd_error);
-}
-
-static void reset_hd(void)
-{
-	static int i;
-
-repeat:
-	if (reset) {
-		reset = 0;
-		i = -1;
-		reset_controller();
-	} else {
-		check_status();
-		if (reset)
-			goto repeat;
-	}
-	if (++i < NR_HD) {
-		special_op[i] = recalibrate[i] = 1;
-		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
-			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
-		if (reset)
-			goto repeat;
-	} else
-		hd_request();
-}
-
-/*
- * Ok, don't know what to do with the unexpected interrupts: on some machines
- * doing a reset and a retry seems to result in an eternal loop. Right now I
- * ignore it, and just set the timeout.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- */
-void unexpected_hd_interrupt(void)
-{
-	unsigned int stat = inb_p(HD_STATUS);
-
-	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
-		dump_status ("unexpected interrupt", stat);
-		SET_TIMER;
-	}
-}
-
-/*
- * bad_rw_intr() now tries to be a bit smarter and does things
- * according to the error returned by the controller.
- * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
- */
-static void bad_rw_intr(void)
-{
-	int dev;
-
-	if (blk_queue_empty(QUEUE))
-		return;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-		end_request(CURRENT, 0);
-		special_op[dev] = recalibrate[dev] = 1;
-	} else if (CURRENT->errors % RESET_FREQ == 0)
-		reset = 1;
-	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
-		special_op[dev] = recalibrate[dev] = 1;
-	/* Otherwise just retry */
-}
-
-static inline int wait_DRQ(void)
-{
-	int retries = 100000, stat;
-
-	while (--retries > 0)
-		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
-			return 0;
-	dump_status("wait_DRQ", stat);
-	return -1;
-}
-
-static void read_intr(void)
-{
-	int i, retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if (i & DRQ_STAT)
-			goto ok_to_read;
-	} while (--retries > 0);
-	dump_status("read_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_read:
-	insw(HD_DATA,CURRENT->buffer,256);
-	CURRENT->sector++;
-	CURRENT->buffer += 512;
-	CURRENT->errors = 0;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-#ifdef DEBUG
-	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
-		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
-		(unsigned long) CURRENT->buffer+512));
-#endif
-	if (CURRENT->current_nr_sectors <= 0)
-		end_request(CURRENT, 1);
-	if (i > 0) {
-		SET_HANDLER(&read_intr);
-		return;
-	}
-	(void) inb_p(HD_STATUS);
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	if (!blk_queue_empty(QUEUE))
-		hd_request();
-	return;
-}
-
-static void write_intr(void)
-{
-	int i;
-	int retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
-			goto ok_to_write;
-	} while (--retries > 0);
-	dump_status("write_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_write:
-	CURRENT->sector++;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-	CURRENT->buffer += 512;
-	if (!i || (CURRENT->bio && !SUBSECTOR(i)))
-		end_request(CURRENT, 1);
-	if (i > 0) {
-		SET_HANDLER(&write_intr);
-		outsw(HD_DATA,CURRENT->buffer,256);
-		local_irq_enable();
-	} else {
-#if (HD_DELAY > 0)
-		last_req = read_timer();
-#endif
-		hd_request();
-	}
-	return;
-}
-
-static void recal_intr(void)
-{
-	check_status();
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	hd_request();
-}
-
-/*
- * This is another of the error-routines I don't know what to do with. The
- * best idea seems to just set reset, and start all over again.
- */
-static void hd_times_out(unsigned long dummy)
-{
-	unsigned int dev;
-
-	do_hd = NULL;
-
-	if (blk_queue_empty(QUEUE))
-		return;
-
-	disable_irq(HD_IRQ);
-	local_irq_enable();
-	reset = 1;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	printk("hd%c: timeout\n", dev+'a');
-	if (++CURRENT->errors >= MAX_ERRORS) {
-#ifdef DEBUG
-		printk("hd%c: too many errors\n", dev+'a');
-#endif
-		end_request(CURRENT, 0);
-	}
-	local_irq_disable();
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-int do_special_op (unsigned int dev)
-{
-	if (recalibrate[dev]) {
-		recalibrate[dev] = 0;
-		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
-		return reset;
-	}
-	if (hd_info[dev].head > 16) {
-		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
-		end_request(CURRENT, 0);
-	}
-	special_op[dev] = 0;
-	return 1;
-}
-
-/*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is disabled before entering hd_request(),
- * and (b) the timeout-interrupt is disabled before the sti().
- *
- * 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. The IDE driver has support to unmask
- * interrupts for non-broken hardware, so use that driver if required.
- */
-static void hd_request(void)
-{
-	unsigned int dev, block, nsect, sec, track, head, cyl;
-
-	if (do_hd)
-		return;
-repeat:
-	del_timer(&device_timer);
-	local_irq_enable();
-
-	if (blk_queue_empty(QUEUE)) {
-		do_hd = NULL;
-		return;
-	}
-
-	if (reset) {
-		local_irq_disable();
-		reset_hd();
-		return;
-	}
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
-	if (dev >= NR_HD || block >= get_capacity(hd_gendisk+dev) ||
-	    ((block+nsect) > get_capacity(hd_gendisk+unit))) {
-		if (dev >= NR_HD)
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				dev+'a', block, nsect);
-		end_request(CURRENT, 0);
-		goto repeat;
-	}
-
-	if (special_op[dev]) {
-		if (do_special_op(dev))
-			goto repeat;
-		return;
-	}
-	sec   = block % hd_info[dev].sect + 1;
-	track = block / hd_info[dev].sect;
-	head  = track % hd_info[dev].head;
-	cyl   = track / hd_info[dev].head;
-#ifdef DEBUG
-	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
-		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
-		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
-#endif
-	if(CURRENT->flags & REQ_CMD) {
-		switch (rq_data_dir(CURRENT)) {
-		case READ:
-			hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
-			if (reset)
-				goto repeat;
-			break;
-		case WRITE:
-			hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
-			if (reset)
-				goto repeat;
-			if (wait_DRQ()) {
-				bad_rw_intr();
-				goto repeat;
-			}
-			outsw(HD_DATA,CURRENT->buffer,256);
-			break;
-		default:
-			printk("unknown hd-command\n");
-			end_request(CURRENT, 0);
-			break;
-		}
-	}
-}
-
-static void do_hd_request (request_queue_t * q)
-{
-	disable_irq(HD_IRQ);
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-static int hd_ioctl(struct inode * inode, struct file * file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct hd_geometry *loc = (struct hd_geometry *) arg;
-	int dev;
-
-	if ((!inode) || kdev_none(inode->i_rdev))
-		return -EINVAL;
-	dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= NR_HD)
-		return -EINVAL;
-	switch (cmd) {
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g; 
-			if (!loc)  return -EINVAL;
-			g.heads = hd_info[dev].head;
-			g.sectors = hd_info[dev].sect;
-			g.cylinders = hd_info[dev].cyl;
-			g.start = get_start_sect(inode->i_bdev);
-			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
-		}
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target =  DEVICE_NR(inode->i_rdev);
-	if (target >= NR_HD)
-		return -ENODEV;
-	return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-
-extern struct block_device_operations hd_fops;
-
-static struct gendisk hd_gendisk[2] = {
-{
-	.major =	MAJOR_NR,
-	.first_minor =	0,
-	.major_name =	"hda",
-	.minor_shift =	6,
-	.fops =		&hd_fops,
-},{
-	.major =	MAJOR_NR,
-	.first_minor =	64,
-	.major_name =	"hdb",
-	.minor_shift =	6,
-	.fops =		&hd_fops,
-}
-};
-	
-static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	void (*handler)(void) = do_hd;
-
-	do_hd = NULL;
-	del_timer(&device_timer);
-	if (!handler)
-		handler = unexpected_hd_interrupt;
-	handler();
-	local_irq_enable();
-}
-
-static struct block_device_operations hd_fops = {
-	.open =		hd_open,
-	.ioctl =	hd_ioctl,
-};
-
-/*
- * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
- * means we run 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 in some of the routines after making sure it's
- * safe.
- */
-static void __init hd_geninit(void)
-{
-	int drive;
-
-	blk_queue_hardsect_size(QUEUE, 512);
-
-#ifdef __i386__
-	if (!NR_HD) {
-		extern struct drive_info drive_info;
-		unsigned char *BIOS = (unsigned char *) &drive_info;
-		unsigned long flags;
-		int cmos_disks;
-
-		for (drive=0 ; drive<2 ; drive++) {
-			hd_info[drive].cyl = *(unsigned short *) BIOS;
-			hd_info[drive].head = *(2+BIOS);
-			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
-			hd_info[drive].ctl = *(8+BIOS);
-			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
-			hd_info[drive].sect = *(14+BIOS);
-#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
-			if (hd_info[drive].cyl && NR_HD == drive)
-				NR_HD++;
-#endif
-			BIOS += 16;
-		}
-
-	/*
-		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
-		BIOS table, but not register compatible, and therefore
-		not present in CMOS.
-
-		Furthermore, we will assume that our ST-506 drives
-		<if any> are the primary drives in the system, and 
-		the ones reflected as drive 1 or 2.
-
-		The first drive is stored in the high nibble of CMOS
-		byte 0x12, the second in the low nibble.  This will be
-		either a 4 bit drive type or 0xf indicating use byte 0x19 
-		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
-		Needless to say, a non-zero value means we have 
-		an AT controller hard disk for that drive.
-
-		Currently the rtc_lock is a bit academic since this
-		driver is non-modular, but someday... ?         Paul G.
-	*/
-
-		spin_lock_irqsave(&rtc_lock, flags);
-		cmos_disks = CMOS_READ(0x12);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		if (cmos_disks & 0xf0) {
-			if (cmos_disks & 0x0f)
-				NR_HD = 2;
-			else
-				NR_HD = 1;
-		}
-	}
-#endif /* __i386__ */
-#ifdef __arm__
-	if (!NR_HD) {
-		/* We don't know anything about the drive.  This means
-		 * that you *MUST* specify the drive parameters to the
-		 * kernel yourself.
-		 */
-		printk("hd: no drives specified - use hd=cyl,head,sectors"
-			" on kernel command line\n");
-	}
-#endif
-
-	for (drive=0 ; drive < NR_HD ; drive++) {
-		sector_t size = hd_info[drive].head *
-			hd_info[drive].sect * hd_info[drive].cyl;
-		set_capacity(hd_gendisk + drive, size);
-		printk ("%s: %ldMB, CHS=%d/%d/%d\n", hd_gendisk[drive].major_name,
-			size / 2048, hd_info[drive].cyl,
-			hd_info[drive].head, hd_info[drive].sect);
-	}
-	if (!NR_HD)
-		return;
-
-	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
-		printk("hd: unable to get IRQ%d for the hard disk driver\n",
-			HD_IRQ);
-		NR_HD = 0;
-		return;
-	}
-	if (!request_region(HD_DATA, 8, "hd")) {
-		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
-		NR_HD = 0;
-		free_irq(HD_IRQ, NULL);
-		return;
-	}
-	if (!request_region(HD_CMD, 1, "hd(cmd)")) {
-		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
-		NR_HD = 0;
-		free_irq(HD_IRQ, NULL);
-		release_region(HD_DATA, 8);
-		return;
-	}
-
-	for(drive=0; drive < NR_HD; drive++) {
-		add_gendisk(hd_gendisk + drive);
-		register_disk(hd_gendisk + drive,
-			mk_kdev(MAJOR_NR,drive<<6), 1<<6,
-			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
-			hd_info[drive].cyl);
-	}
-}
-
-int __init hd_init(void)
-{
-	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
-		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
-		return -1;
-	}
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
-	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
-	return 0;
-}
-
-static int parse_hd_setup (char *line) {
-	int ints[6];
-
-	(void) get_options(line, ARRAY_SIZE(ints), ints);
-	hd_setup(NULL, ints);
-
-	return 1;
-}
-__setup("hd=", parse_hd_setup);
-
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Sun Sep 15 19:19:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,491 +0,0 @@
-/*
- * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
- *
- * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * ide-pci.c reference
- *
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO		0
-
-#undef DISPLAY_HPT34X_TIMINGS
-
-#define HPT34X_MAX_DEVS			8
-static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
-static int n_hpt34x_devs;
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int hpt34x_get_info(char *, char **, off_t, int);
-extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	p += sprintf(p, "\n                             "
-			"HPT34X Chipset.\n");
-	for (i = 0; i < n_hpt34x_devs; i++) {
-		struct pci_dev *dev = hpt34x_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
-		u8  c0 = 0, c1 = 0;
-
-		/*
-		 * at that point bibma+0x2 et bibma+0xa are byte registers
-		 * to investigate:
-		 */
-		c0 = inb_p((unsigned short)bibma + 0x02);
-		c1 = inb_p((unsigned short)bibma + 0x0a);
-		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "--------------- Primary Channel "
-				"---------------- Secondary Channel "
-				"-------------\n");
-		p += sprintf(p, "                %sabled "
-				"                        %sabled\n",
-				(c0&0x80) ? "dis" : " en",
-				(c1&0x80) ? "dis" : " en");
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"-------- drive0 ---------- drive1 ------\n");
-		p += sprintf(p, "DMA enabled:    %s              %s"
-				"             %s               %s\n",
-				(c0&0x20) ? "yes" : "no ",
-				(c0&0x40) ? "yes" : "no ",
-				(c1&0x20) ? "yes" : "no ",
-				(c1&0x40) ? "yes" : "no " );
-
-		p += sprintf(p, "UDMA\n");
-		p += sprintf(p, "DMA\n");
-		p += sprintf(p, "PIO\n");
-	}
-	p += sprintf(p, "\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte hpt34x_proc = 0;
-
-static byte hpt34x_ratemask (ide_drive_t *drive)
-{
-	byte mode = 0x00;
-
-	mode |= 0x01;
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte hpt34x_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-# ifdef CONFIG_HPT34X_AUTODMA
-byte mode = hpt34x_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	// while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-# else /* !CONFIG_HPT34X_AUTODMA */
-	while (speed > XFER_PIO_4) speed--;
-# endif /* CONFIG_HPT34X_AUTODMA */
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(dev, 0x44, &reg1);
-	pci_read_config_dword(dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(dev, 0x44, tmp1);
-	pci_write_config_dword(dev, 0x48, tmp2);
-}
-
-static int hpt34x_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte speed		= hpt34x_ratefilter(drive, xferspeed);
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-	byte			hi_speed, lo_speed;
-
-	SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-	if (hi_speed & 7) {
-		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-	} else {
-		lo_speed <<= 5;
-		lo_speed >>= 5;
-	}
-
-	pci_read_config_dword(dev, 0x44, &reg1);
-	pci_read_config_dword(dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = ((hi_speed << drive->dn) | reg2);
-	pci_write_config_dword(dev, 0x44, tmp1);
-	pci_write_config_dword(dev, 0x48, tmp2);
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x)\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-	return(ide_config_drive_speed(drive, speed));
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-	hpt34x_clear_chipset(drive);
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= hpt34x_ratemask(drive);
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	switch(mode) {
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-
-	hpt34x_clear_chipset(drive);
-	(void) hpt34x_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x0007) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		hpt34x_tune_drive(drive, 255);
-	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	if (dma_func == ide_dma_on)
-		dma_func = ide_dma_off;
-#endif /* CONFIG_HPT34X_AUTODMA */
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT343 UDMA bios-less chipset
- * and HPT345 UDMA bios chipset (stamped HPT363)
- * by HighPoint|Triones Technologies, Inc.
- */
-
-int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-//	ide_task_t *args = HWGROUP(drive)->rq->special;
-	unsigned long dma_base = hwif->dma_base;
-	unsigned int count, reading = 0;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;
-				/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4);
-			/* PRD table */
-			reading |= 0x01;
-			OUT_BYTE(reading, dma_base);
-			/* specify r/w */
-			OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2);
-			/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			/* issue cmd to drive */
-			/*
-			 * FIX ME to use only ACB ide_task_t args Struct
-			 */
-#if 0
-		{
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		{
-#else
-			if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing == 1)
-				OUT_BYTE((reading == 9) ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-			else
-				OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-#endif
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
-			/* get DMA status */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* clear the INTR & ERROR bits */
-			OUT_BYTE(dma_stat|6, dma_base+2);
-			/* purge DMA mappings */
-			ide_destroy_dmatable(drive);
-			/* verify good DMA status */
-			return (dma_stat & 7) != 4;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define	HPT34X_PCI_INIT_REG		0x80
-
-unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
-{
-	int i = 0;
-	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
-	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
-	unsigned short cmd;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	if (cmd & PCI_COMMAND_MEMORY) {
-		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
-				dev->resource[PCI_ROM_RESOURCE].start);
-		}
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-	} else {
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
-
-	/*
-	 * Since 20-23 can be assigned and are R/W, we correct them.
-	 */
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	for(i=0; i<4; i++) {
-		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-		pci_write_config_dword(dev,
-				(PCI_BASE_ADDRESS_0 + (i * 4)),
-				dev->resource[i].start);
-	}
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	local_irq_restore(flags);
-
-	hpt34x_devs[n_hpt34x_devs++] = dev;
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt34x_proc) {
-		hpt34x_proc = 1;
-		hpt34x_display_info = &hpt34x_get_info;
-	}
-#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
-{
-	unsigned short pcicmd = 0;
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &hpt34x_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_hpt343 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	char *chipset_names[] = {"HPT343", "HPT345"};
-	unsigned short pcicmd = 0;
-
-	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
-
-	strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
-	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Sun Sep 15 19:19:50 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1695 +0,0 @@
-/*
- * linux/drivers/ide/hpt366.c		Version 0.33	April 17, 2002
- *
- * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
- *
- * Thanks to HighPoint Technologies for their assistance, and hardware.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- * Note that final HPT370 support was done by force extraction of GPL.
- *
- * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma 
- *   xfer to prevent that from happening.
- * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma. 
- * - use new highpoint timings.
- * - detect bus speed using highpoint register.
- * - use pll if we don't have a clock table. added a 66MHz table that's
- *   just 2x the 33MHz table.
- * - removed turnaround. NOTE: we never want to switch between pll and
- *   pci clocks as the chip can glitch in those cases. the highpoint
- *   approved workaround slows everything down too much to be useful. in
- *   addition, we would have to serialize access to each chip.
- * 	Adrian Sun <a.sun@sun.com>
- *
- * add drive timings for 66MHz PCI bus,
- * fix ATA Cable signal detection, fix incorrect /proc info
- * add /proc display for per-drive PIO/DMA/UDMA mode and
- * per-channel ATA-33/66 Cable detect.
- * 	Duncan Laurie <void@sun.com>
- *
- * fixup /proc output for multiple controllers
- *	Tim Hockin <thockin@sun.com>
- *
- * On hpt366: 
- * Reset the hpt366 on error, reset on dma
- * Fix disabling Fast Interrupt hpt366.
- * 	Mike Waychison <crlf@sun.com>
- */
-
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_HPT366_TIMINGS
-
-/* various tuning parameters */
-#define HPT_RESET_STATE_ENGINE
-#undef HPT_DELAY_INTERRUPT
-#undef HPT_SERIALIZE_IO
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-const char *quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP LM20.5",
-        NULL
-};
-
-const char *bad_ata100_5[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_4[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_3[] = {
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata33[] = {
-	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
-	"Maxtor 90510D4",
-	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
-	NULL
-};
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	unsigned int	chipset_settings;
-};
-
-/* key for bus clock timings
- * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
- *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
- *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
- *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
- * 31     FIFO enable.
- */
-struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
-	{	XFER_UDMA_4,	0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9	},
-	{	0,		0x0120d9d9	}
-};
-
-struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
-	{	XFER_UDMA_4,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7	}
-};
-
-struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
-
-	{	XFER_UDMA_4,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585	},
-	{	0,		0x01208585	}
-};
-
-/* from highpoint documentation. these are old values */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
-	{	XFER_UDMA_5,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57	},
-	{	0,		0x06514e57	}
-};
-
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x14846231      },
-	{       XFER_UDMA_4,    0x14886231      },
-	{       XFER_UDMA_3,    0x148c6231      },
-	{       XFER_UDMA_2,    0x148c6231      },
-	{       XFER_UDMA_1,    0x14906231      },
-	{       XFER_UDMA_0,    0x14986231      },
-	
-	{       XFER_MW_DMA_2,  0x26514e21      },
-	{       XFER_MW_DMA_1,  0x26514e33      },
-	{       XFER_MW_DMA_0,  0x26514e97      },
-	
-	{       XFER_PIO_4,     0x06514e21      },
-	{       XFER_PIO_3,     0x06514e22      },
-	{       XFER_PIO_2,     0x06514e33      },
-	{       XFER_PIO_1,     0x06914e43      },
-	{       XFER_PIO_0,     0x06914e57      },
-	{       0,              0x06514e57      }
-};
-
-/* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
-        {       XFER_UDMA_5,    0x12446231      },
-        {       XFER_UDMA_4,    0x12446231      },
-        {       XFER_UDMA_3,    0x126c6231      },
-        {       XFER_UDMA_2,    0x12486231      },
-        {       XFER_UDMA_1,    0x124c6233      },
-        {       XFER_UDMA_0,    0x12506297      },
-
-        {       XFER_MW_DMA_2,  0x22406c31      },
-        {       XFER_MW_DMA_1,  0x22406c33      },
-        {       XFER_MW_DMA_0,  0x22406c97      },
-
-        {       XFER_PIO_4,     0x06414e31      },
-        {       XFER_PIO_3,     0x06414e42      },
-        {       XFER_PIO_2,     0x06414e53      },
-        {       XFER_PIO_1,     0x06814e93      },
-        {       XFER_PIO_0,     0x06814ea7      },
-        {       0,              0x06814ea7      }
-};
-
-/* 2x 33MHz timings */
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
-	{       XFER_UDMA_5,    0x1488e673       },
-	{       XFER_UDMA_4,    0x1488e673       },
-	{       XFER_UDMA_3,    0x1498e673       },
-	{       XFER_UDMA_2,    0x1490e673       },
-	{       XFER_UDMA_1,    0x1498e677       },
-	{       XFER_UDMA_0,    0x14a0e73f       },
-
-	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       }, 
-	{       XFER_MW_DMA_0,  0x2480fb3f       },
-
-	{       XFER_PIO_4,     0x0c82be73       },
-	{       XFER_PIO_3,     0x0c82be95       },
-	{       XFER_PIO_2,     0x0c82beb7       },
-	{       XFER_PIO_1,     0x0d02bf37       },
-	{       XFER_PIO_0,     0x0d02bf5f       },
-	{       0,              0x0d02bf5f       }
-};
-
-struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
-	{       XFER_UDMA_5,    0x12848242      },
-	{       XFER_UDMA_4,    0x12ac8242      },
-	{       XFER_UDMA_3,    0x128c8242      },
-	{       XFER_UDMA_2,    0x120c8242      },
-	{       XFER_UDMA_1,    0x12148254      },
-	{       XFER_UDMA_0,    0x121882ea      },
-
-	{       XFER_MW_DMA_2,  0x22808242      },
-	{       XFER_MW_DMA_1,  0x22808254      },
-	{       XFER_MW_DMA_0,  0x228082ea      },
-
-	{       XFER_PIO_4,     0x0a81f442      },
-	{       XFER_PIO_3,     0x0a81f443      },
-	{       XFER_PIO_2,     0x0a81f454      },
-	{       XFER_PIO_1,     0x0ac1f465      },
-	{       XFER_PIO_0,     0x0ac1f48a      },
-	{       0,              0x0ac1f48a      }
-};
-
-struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
-	{	XFER_UDMA_6,	0x1c81dc62	},
-	{	XFER_UDMA_5,	0x1c6ddc62	},
-	{	XFER_UDMA_4,	0x1c8ddc62	},
-	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
-	{	XFER_UDMA_2,	0x1c91dc62	},
-	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
-	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
-
-	{	XFER_MW_DMA_2,	0x2c829262	},
-	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
-	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
-
-	{	XFER_PIO_4,	0x0c829c62	},
-	{	XFER_PIO_3,	0x0c829c84	},
-	{	XFER_PIO_2,	0x0c829ca6	},
-	{	XFER_PIO_1,	0x0d029d26	},
-	{	XFER_PIO_0,	0x0d029d5e	},
-	{	0,		0x0d029d5e	}
-};
-
-struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
-	{	XFER_UDMA_5,	0x12848242	},
-	{	XFER_UDMA_4,	0x12ac8242	},
-	{	XFER_UDMA_3,	0x128c8242	},
-	{	XFER_UDMA_2,	0x120c8242	},
-	{	XFER_UDMA_1,	0x12148254	},
-	{	XFER_UDMA_0,	0x121882ea	},
-
-	{	XFER_MW_DMA_2,	0x22808242	},
-	{	XFER_MW_DMA_1,	0x22808254	},
-	{	XFER_MW_DMA_0,	0x228082ea	},
-
-	{	XFER_PIO_4,	0x0a81f442	},
-	{	XFER_PIO_3,	0x0a81f443	},
-	{	XFER_PIO_2,	0x0a81f454	},
-	{	XFER_PIO_1,	0x0ac1f465	},
-	{	XFER_PIO_0,	0x0ac1f48a	},
-	{	0,		0x0a81f443	}
-};
-
-struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
-	{	XFER_UDMA_6,	0x1c869c62	},
-	{	XFER_UDMA_5,	0x1cae9c62	},
-	{	XFER_UDMA_4,	0x1c8a9c62	},
-	{	XFER_UDMA_3,	0x1c8e9c62	},
-	{	XFER_UDMA_2,	0x1c929c62	},
-	{	XFER_UDMA_1,	0x1c9a9c62	},
-	{	XFER_UDMA_0,	0x1c829c62	},
-
-	{	XFER_MW_DMA_2,	0x2c829c62	},
-	{	XFER_MW_DMA_1,	0x2c829c66	},
-	{	XFER_MW_DMA_0,	0x2c829d2e	},
-
-	{	XFER_PIO_4,	0x0c829c62	},
-	{	XFER_PIO_3,	0x0c829c84	},
-	{	XFER_PIO_2,	0x0c829ca6	},
-	{	XFER_PIO_1,	0x0d029d26	},
-	{	XFER_PIO_0,	0x0d029d5e	},
-	{	0,		0x0d029d26	}
-};
-
-struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
-	{	XFER_UDMA_6,	0x12808242	},
-	{	XFER_UDMA_5,	0x12848242	},
-	{	XFER_UDMA_4,	0x12ac8242	},
-	{	XFER_UDMA_3,	0x128c8242	},
-	{	XFER_UDMA_2,	0x120c8242	},
-	{	XFER_UDMA_1,	0x12148254	},
-	{	XFER_UDMA_0,	0x121882ea	},
-
-	{	XFER_MW_DMA_2,	0x22808242	},
-	{	XFER_MW_DMA_1,	0x22808254	},
-	{	XFER_MW_DMA_0,	0x228082ea	},
-
-	{	XFER_PIO_4,	0x0a81f442	},
-	{	XFER_PIO_3,	0x0a81f443	},
-	{	XFER_PIO_2,	0x0a81f454	},
-	{	XFER_PIO_1,	0x0ac1f465	},
-	{	XFER_PIO_0,	0x0ac1f48a	},
-	{	0,		0x06814e93	}
-};
-
-#if 0
-struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
-	{	XFER_UDMA_6,	},
-	{	XFER_UDMA_5,	},
-	{	XFER_UDMA_4,	},
-	{	XFER_UDMA_3,	},
-	{	XFER_UDMA_2,	},
-	{	XFER_UDMA_1,	},
-	{	XFER_UDMA_0,	},
-	{	XFER_MW_DMA_2,	},
-	{	XFER_MW_DMA_1,	},
-	{	XFER_MW_DMA_0,	},
-	{	XFER_PIO_4,	},
-	{	XFER_PIO_3,	},
-	{	XFER_PIO_2,	},
-	{	XFER_PIO_1,	},
-	{	XFER_PIO_0,	},
-	{	0,	}
-};
-#endif
-#if 0
-struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
-	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
-	{	XFER_UDMA_5,	0x12446231	},
-				0x14846231
-	{	XFER_UDMA_4,		0x16814ea7	},
-				0x14886231
-	{	XFER_UDMA_3,		0x16814ea7	},
-				0x148c6231
-	{	XFER_UDMA_2,		0x16814ea7	},
-				0x148c6231
-	{	XFER_UDMA_1,		0x16814ea7	},
-				0x14906231
-	{	XFER_UDMA_0,		0x16814ea7	},
-				0x14986231
-	{	XFER_MW_DMA_2,		0x16814ea7	},
-				0x26514e21
-	{	XFER_MW_DMA_1,		0x16814ea7	},
-				0x26514e97
-	{	XFER_MW_DMA_0,		0x16814ea7	},
-				0x26514e97
-	{	XFER_PIO_4,		0x06814ea7	},
-				0x06514e21
-	{	XFER_PIO_3,		0x06814ea7	},
-				0x06514e22
-	{	XFER_PIO_2,		0x06814ea7	},
-				0x06514e33
-	{	XFER_PIO_1,		0x06814ea7	},
-				0x06914e43
-	{	XFER_PIO_0,		0x06814ea7	},
-				0x06914e57
-	{	0,		0x06814ea7	}
-};
-#endif
-
-#define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT374_ALLOW_ATA133_6		0
-#define HPT371_ALLOW_ATA133_6		0
-#define HPT302_ALLOW_ATA133_6		0
-#define HPT372_ALLOW_ATA133_6		1
-#define HPT370_ALLOW_ATA100_5		1
-#define HPT366_ALLOW_ATA66_4		1
-#define HPT366_ALLOW_ATA66_3		1
-#define HPT366_MAX_DEVS			8
-
-#define F_LOW_PCI_33      0x23
-#define F_LOW_PCI_40      0x29
-#define F_LOW_PCI_50      0x2d
-#define F_LOW_PCI_66      0x42
-
-static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
-static int n_hpt_devs;
-
-static unsigned int hpt_revision(struct pci_dev *dev);
-static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
-
-byte hpt366_proc = 0;
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-static int hpt366_get_info(char *, char **, off_t, int);
-extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p	= buffer;
-	char *chipset_nums[] = {"366", "366",  "368",
-				"370", "370A", "372",
-				"302", "371",  "374" };
-	int i;
-
-	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370/372/374\n");
-	for (i = 0; i < n_hpt_devs; i++) {
-		struct pci_dev *dev = hpt_devs[i];
-		unsigned long iobase = dev->resource[4].start;
-		u32 class_rev = hpt_revision(dev);
-		u8 c0, c1;
-
-		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
-		p += sprintf(p, "--------------- Primary Channel "
-				"--------------- Secondary Channel "
-				"--------------\n");
-
-		/* get the bus master status registers */
-		c0 = inb_p(iobase + 0x2);
-		c1 = inb_p(iobase + 0xa);
-		p += sprintf(p, "Enabled:        %s"
-				"                             %s\n",
-			(c0 & 0x80) ? "no" : "yes",
-			(c1 & 0x80) ? "no" : "yes");
-
-		if (hpt_minimum_revision(dev, 3)) {
-			u8 cbl;
-			cbl = inb_p(iobase + 0x7b);
-			outb_p(cbl | 1, iobase + 0x7b);
-			outb_p(cbl & ~1, iobase + 0x7b);
-			cbl = inb_p(iobase + 0x7a);
-			p += sprintf(p, "Cable:          ATA-%d"
-					"                          ATA-%d\n",
-				(cbl & 0x02) ? 33 : 66,
-				(cbl & 0x01) ? 33 : 66);
-			p += sprintf(p, "\n");
-		}
-
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"------- drive0 ---------- drive1 -------\n");
-		p += sprintf(p, "DMA capable:    %s              %s" 
-				"            %s               %s\n",
-			(c0 & 0x20) ? "yes" : "no ", 
-			(c0 & 0x40) ? "yes" : "no ",
-			(c1 & 0x20) ? "yes" : "no ", 
-			(c1 & 0x40) ? "yes" : "no ");
-
-		{
-			u8 c2, c3;
-			/* older revs don't have these registers mapped 
-			 * into io space */
-			pci_read_config_byte(dev, 0x43, &c0);
-			pci_read_config_byte(dev, 0x47, &c1);
-			pci_read_config_byte(dev, 0x4b, &c2);
-			pci_read_config_byte(dev, 0x4f, &c3);
-
-			p += sprintf(p, "Mode:           %s             %s"
-					"           %s              %s\n",
-				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
-					(c0 & 0x80) ? "PIO " : "off ",
-				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
-					(c1 & 0x80) ? "PIO " : "off ",
-				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
-					(c2 & 0x80) ? "PIO " : "off ",
-				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
-					(c3 & 0x80) ? "PIO " : "off ");
-		}
-	}
-	p += sprintf(p, "\n");
-	
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static unsigned int hpt_revision (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT374:
-			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
-		case PCI_DEVICE_ID_TTI_HPT371:
-			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
-		case PCI_DEVICE_ID_TTI_HPT302:
-			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
-		case PCI_DEVICE_ID_TTI_HPT372:
-			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-		default:
-			break;
-	}
-	return class_rev;
-}
-
-static unsigned int hpt_minimum_revision (struct pci_dev *dev, int revision)
-{
-	unsigned int class_rev = hpt_revision(dev);
-	revision--;
-	return ((int) (class_rev > revision) ? 1 : 0);
-}
-
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
-
-static byte hpt3xx_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	byte mode = 0x00;
-
-	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
-		mode |= (HPT374_ALLOW_ATA133_6) ? 0x04 : 0x03;
-	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
-		mode |= (HPT371_ALLOW_ATA133_6) ? 0x04 : 0x03;
-	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
-		mode |= (HPT302_ALLOW_ATA133_6) ? 0x04 : 0x03;
-	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
-		mode |= (HPT372_ALLOW_ATA133_6) ? 0x04 : 0x03;
-	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
-		mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
-	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
-		mode |= (HPT370_ALLOW_ATA100_5) ? 0x03 : 0x02;
-		if (check_in_drive_lists(drive, bad_ata33))
-			return (mode &= ~0xFF);
-	} else {					/* HPT366 and HPT368 */
-		mode |= 0x02;
-		if (check_in_drive_lists(drive, bad_ata33))
-			return (mode &= ~0xFF);
-	}
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte hpt3xx_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= hpt3xx_ratemask(drive);
-
-	if (drive->media != ide_disk)
-		while (speed > XFER_PIO_4) speed--;
-
-	switch(mode) {
-		case 0x04:
-			while (speed > XFER_UDMA_6) speed--;
-			break;
-		case 0x03:
-			while (speed > XFER_UDMA_5) speed--;
-			if (hpt_minimum_revision(dev, 5))
-				break;
-			if (check_in_drive_lists(drive, bad_ata100_5))
-				while (speed > XFER_UDMA_4) speed--;
-			break;
-		case 0x02:
-			while (speed > XFER_UDMA_4) speed--;
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (hpt_minimum_revision(dev, 3))
-				break;
-			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
-			    (!(HPT366_ALLOW_ATA66_4)))
-				while (speed > XFER_UDMA_3) speed--;
-			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
-			    (!(HPT366_ALLOW_ATA66_3)))
-				while (speed > XFER_UDMA_2) speed--;
-			break;
-		case 0x01:
-			while (speed > XFER_UDMA_2) speed--;
-	/*
-	 * CHECK ME, Does this need to be set to 5 ??
-	 */
-			if (hpt_minimum_revision(dev, 3))
-				break;
-			if (check_in_drive_lists(drive, bad_ata33))
-				while (speed > XFER_MW_DMA_2) speed--;
-			break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 1;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
-		}
-	return chipset_table->chipset_settings;
-}
-
-static void hpt366_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
-	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	byte drive_fast		= 0;
-	unsigned int reg1	= 0;
-	unsigned int reg2	= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-#if 0
-	if (drive_fast & 0x02)
-		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
-#else
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-#endif
-
-	reg2 = pci_bus_clock_list(speed,
-		(struct chipset_bus_clock_list_entry *) dev->driver_data);
-	/*
-	 * Disable on-chip PIO FIFO/buffer
-	 *  (to avoid problems handling I/O errors later)
-	 */
-	pci_read_config_dword(dev, regtime, &reg1);
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(dev, regtime, reg2);
-}
-
-static void hpt368_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	hpt366_tune_chipset(drive, speed);
-}
-
-static void hpt370_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	unsigned int list_conf	= 0;
-	unsigned int drive_conf = 0;
-	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0x40 + (drive->dn * 4);
-	byte new_fast, drive_fast		= 0;
-	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	new_fast = drive_fast;
-	if (new_fast & 0x02)
-		new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-	if (new_fast & 0x01)
-		new_fast &= ~0x01;
-#else
-	if ((new_fast & 0x01) == 0)
-		new_fast |= 0x01;
-#endif
-	if (new_fast != drive_fast)
-		pci_write_config_byte(dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, 
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->driver_data);
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	
-	if (speed < XFER_MW_DMA_0) {
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	}
-
-	pci_write_config_dword(dev, drive_pci, list_conf);
-}
-
-static void hpt372_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	byte speed		= hpt3xx_ratefilter(drive, xferspeed);
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	unsigned int list_conf	= 0;
-	unsigned int drive_conf	= 0;
-	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0x40 + (drive->dn * 4);
-	byte drive_fast		= 0;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	drive_fast &= ~0x07;
-	pci_write_config_byte(dev, regfast, drive_fast);
-					
-	list_conf = pci_bus_clock_list(speed,
-			(struct chipset_bus_clock_list_entry *)
-					dev->driver_data);
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	if (speed < XFER_MW_DMA_0)
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	pci_write_config_dword(dev, drive_pci, list_conf);
-}
-
-static void hpt374_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	hpt372_tune_chipset(drive, speed);
-}
-
-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-
-	if (hpt_minimum_revision(dev, 8))
-		hpt374_tune_chipset(drive, speed);
-#if 0
-	else if (hpt_minimum_revision(dev, 7))
-		hpt371_tune_chipset(drive, speed);
-	else if (hpt_minimum_revision(dev, 6))
-		hpt302_tune_chipset(drive, speed);
-#endif
-	else if (hpt_minimum_revision(dev, 5))
-		hpt372_tune_chipset(drive, speed);
-	else if (hpt_minimum_revision(dev, 3))
-		hpt370_tune_chipset(drive, speed);
-	else if (hpt_minimum_revision(dev, 2))
-		hpt368_tune_chipset(drive, speed);
-	else
-                hpt366_tune_chipset(drive, speed);
-
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= hpt3xx_ratemask(drive);
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		mode |= 0x08;
-
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-int hpt3xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, quirk_drives));
-}
-
-void hpt3xx_intrproc (ide_drive_t *drive)
-{
-	if (drive->quirk_list)
-		return;
-	/* drives in the quirk_list may not like intr setups/cleanups */
-	OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-}
-
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-
-	if (drive->quirk_list) {
-		if (hpt_minimum_revision(dev,3)) {
-			byte reg5a = 0;
-			pci_read_config_byte(dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
-		} else {
-			if (mask) {
-				disable_irq(HWIF(drive)->irq);
-			} else {
-				enable_irq(HWIF(drive)->irq);
-			}
-		}
-	} else {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
-	}
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if (id->dma_mword & 0x0007) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		hpt3xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT366 UDMA bios chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:
-				/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* return 1 if INTR asserted */
-			return (dma_stat & 4) == 4;
-		case ide_dma_lostirq:
-			pci_read_config_byte(dev, 0x50, &reg50h);
-			pci_read_config_byte(dev, 0x52, &reg52h);
-			pci_read_config_byte(dev, 0x5a, &reg5ah);
-			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x,"
-				" reg5ah=0x%02x\n",
-				drive->name,
-				ide_dmafunc_verbose(func),
-				reg50h, reg52h, reg5ah);
-			if (reg5ah & 0x10)
-				pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-#if 0
-			/* how about we flush and reset, mmmkay? */
-			pci_write_config_byte(dev, 0x51, 0x1F);
-			/* fall through to a reset */
-		case ide_dma_begin:
-		case ide_dma_end:
-			/* reset the chips state over and over.. */
-			pci_write_config_byte(dev, 0x51, 0x13);
-#endif
-			break;
-		case ide_dma_timeout:
-		default:
-			break;
-	}
-	/* use standard DMA stuff */
-	return ide_dmaproc(func, drive);
-}
-
-int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long dma_base	= hwif->dma_base;
-	byte regstate		= hwif->channel ? 0x54 : 0x50;
-	byte reginfo		= hwif->channel ? 0x56 : 0x52;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:
-				/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* return 1 if INTR asserted */
-			return (dma_stat & 4) == 4;
-
-		case ide_dma_end:
-			dma_stat = IN_BYTE(dma_base + 2);
-			if (dma_stat & 0x01) {
-				/* wait a little */
-				udelay(20);
-				dma_stat = IN_BYTE(dma_base + 2);
-			}
-			if ((dma_stat & 0x01) == 0) 
-				break;
-
-			func = ide_dma_timeout;
-			/* fallthrough */
-
-		case ide_dma_timeout:
-		case ide_dma_lostirq:
-			pci_read_config_byte(dev, reginfo, &dma_stat);
-			printk("%s: %d bytes in FIFO\n", drive->name, 
-			       dma_stat);
-			pci_write_config_byte(dev, regstate, 0x37);
-			udelay(10);
-			dma_stat = IN_BYTE(dma_base);
-			/* stop dma */
-			OUT_BYTE(dma_stat & ~0x1, dma_base);
-			dma_stat = IN_BYTE(dma_base + 2);
-			/* clear errors */
-			OUT_BYTE(dma_stat | 0x6, dma_base+2);
-			/* fallthrough */
-
-#ifdef HPT_RESET_STATE_ENGINE
-	        case ide_dma_begin:
-#endif
-			pci_write_config_byte(dev, regstate, 0x37);
-			udelay(10);
-			break;
-
-		default:
-			break;
-	}
-	/* use standard DMA stuff */
-	return ide_dmaproc(func, drive);
-}
-
-int hpt374_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long dma_base	= hwif->dma_base;
-	byte mscreg		= hwif->channel ? 0x54 : 0x50;
-//	byte reginfo		= hwif->channel ? 0x56 : 0x52;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:
-				/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-#if 0  /* do not set unless you know what you are doing */
-			if (dma_stat & 4) {
-				byte stat = GET_STAT();
-				OUT_BYTE(dma_base+2, dma_stat & 0xE4);
-			}
-#endif
-			/* return 1 if INTR asserted */
-			return (dma_stat & 4) == 4;
-		case ide_dma_end:
-		{
-			byte bwsr_mask = hwif->channel ? 0x02 : 0x01;
-			byte bwsr_stat, msc_stat;
-			pci_read_config_byte(dev, 0x6a, &bwsr_stat);
-			pci_read_config_byte(dev, mscreg, &msc_stat);
-			if ((bwsr_stat & bwsr_mask) == bwsr_mask)
-				pci_write_config_byte(dev, mscreg, msc_stat|0x30);
-		}
-		default:
-			break;
-	}
-	/* use standard DMA stuff */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-void hpt3xx_reset (ide_drive_t *drive)
-{
-#if 0
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
-	byte reg59h		= 0;
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
-}
-
-static int hpt3xx_tristate (ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte reset		= (hwif->channel) ? 0x80 : 0x40;
-	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
-	byte reg59h		= 0;
-	byte regXXh		= 0;
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	pci_read_config_byte(dev, 0x59, &reg59h);
-	pci_read_config_byte(dev, state_reg, &regXXh);
-
-	if (state) {
-		(void) ide_do_reset(drive);
-		pci_write_config_byte(dev, state_reg, regXXh|0x80);
-		pci_write_config_byte(dev, 0x59, reg59h|reset);
-	} else {
-		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
-		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
-		(void) ide_do_reset(drive);
-	}
-	return 0;
-}
-
-/* 
- * set/get power state for a drive.
- * turning the power off does the following things:
- *   1) soft-reset the drive
- *   2) tri-states the ide bus
- *
- * when we turn things back on, we need to re-initialize things.
- */
-#define TRISTATE_BIT  0x8000
-static int hpt370_busproc(ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte tristate, resetmask, bus_reg;
-	u16 tri_reg;
-
-	if (!hwif)
-		return -EINVAL;
-
-	hwif->bus_state = state;
-
-	if (hwif->channel) { 
-		/* secondary channel */
-		tristate = 0x56;
-		resetmask = 0x80; 
-	} else { 
-		/* primary channel */
-		tristate = 0x52;
-		resetmask = 0x40;
-	}
-
-	/* grab status */
-	pci_read_config_word(dev, tristate, &tri_reg);
-	pci_read_config_byte(dev, 0x59, &bus_reg);
-
-	/* set the state. we don't set it if we don't need to do so.
-	 * make sure that the drive knows that it has failed if it's off */
-	switch (state) {
-	case BUSSTATE_ON:
-		hwif->drives[0].failures = 0;
-		hwif->drives[1].failures = 0;
-		if ((bus_reg & resetmask) == 0)
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg &= ~resetmask;
-		break;
-	case BUSSTATE_OFF:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	case BUSSTATE_TRISTATE:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
-			return 0;
-		tri_reg |= TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	}
-	pci_write_config_byte(dev, 0x59, bus_reg);
-	pci_write_config_word(dev, tristate, tri_reg);
-
-	return 0;
-}
-
-static void __init init_hpt37x(struct pci_dev *dev)
-{
-	int adjust, i;
-	u16 freq;
-	u32 pll;
-	byte reg5bh;
-
-#if 1
-	byte reg5ah = 0;
-	pci_read_config_byte(dev, 0x5a, &reg5ah);
-	/* interrupt force enable */
-	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-#endif
-
-	/*
-	 * default to pci clock. make sure MA15/16 are set to output
-	 * to prevent drives having problems with 40-pin cables.
-	 */
-	pci_write_config_byte(dev, 0x5b, 0x23);
-
-	/*
-	 * set up the PLL. we need to adjust it so that it's stable. 
-	 * freq = Tpll * 192 / Tpci
-	 */
-	pci_read_config_word(dev, 0x78, &freq);
-	freq &= 0x1FF;
-	if (freq < 0x9c) {
-		pll = F_LOW_PCI_33;
-		if (hpt_minimum_revision(dev,8))
-			dev->driver_data = (void *) thirty_three_base_hpt374;
-		else if (hpt_minimum_revision(dev,5))
-			dev->driver_data = (void *) thirty_three_base_hpt372;
-		else if (hpt_minimum_revision(dev,4))
-			dev->driver_data = (void *) thirty_three_base_hpt370a;
-		else
-			dev->driver_data = (void *) thirty_three_base_hpt370;
-		printk("HPT37X: using 33MHz PCI clock\n");
-	} else if (freq < 0xb0) {
-		pll = F_LOW_PCI_40;
-	} else if (freq < 0xc8) {
-		pll = F_LOW_PCI_50;
-		if (hpt_minimum_revision(dev,8))
-			BUG();
-		else if (hpt_minimum_revision(dev,5))
-			dev->driver_data = (void *) fifty_base_hpt372;
-		else if (hpt_minimum_revision(dev,4))
-			dev->driver_data = (void *) fifty_base_hpt370a;
-		else
-			dev->driver_data = (void *) fifty_base_hpt370a;
-		printk("HPT37X: using 50MHz PCI clock\n");
-	} else {
-		pll = F_LOW_PCI_66;
-		if (hpt_minimum_revision(dev,8))
-			BUG();
-		else if (hpt_minimum_revision(dev,5))
-			dev->driver_data = (void *) sixty_six_base_hpt372;
-		else if (hpt_minimum_revision(dev,4))
-			dev->driver_data = (void *) sixty_six_base_hpt370a;
-		else
-			dev->driver_data = (void *) sixty_six_base_hpt370;
-		printk("HPT37X: using 66MHz PCI clock\n");
-	}
-	
-	/*
-	 * only try the pll if we don't have a table for the clock
-	 * speed that we're running at. NOTE: the internal PLL will
-	 * result in slow reads when using a 33MHz PCI clock. we also
-	 * don't like to use the PLL because it will cause glitches
-	 * on PRST/SRST when the HPT state engine gets reset.
-	 */
-	if (dev->driver_data) 
-		goto init_hpt37X_done;
-	
-	/*
-	 * adjust PLL based upon PCI clock, enable it, and wait for
-	 * stabilization.
-	 */
-	adjust = 0;
-	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
-	while (adjust++ < 6) {
-		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
-				       pll | 0x100);
-
-		/* wait for clock stabilization */
-		for (i = 0; i < 0x50000; i++) {
-			pci_read_config_byte(dev, 0x5b, &reg5bh);
-			if (reg5bh & 0x80) {
-				/* spin looking for the clock to destabilize */
-				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b, 
-							     &reg5bh);
-					if ((reg5bh & 0x80) == 0)
-						goto pll_recal;
-				}
-				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c, 
-						       pll & ~0x100);
-				pci_write_config_byte(dev, 0x5b, 0x21);
-				if (hpt_minimum_revision(dev,8))
-					BUG();
-				else if (hpt_minimum_revision(dev,5))
-					dev->driver_data = (void *) fifty_base_hpt372;
-				else if (hpt_minimum_revision(dev,4))
-					dev->driver_data = (void *) fifty_base_hpt370a;
-				else
-					dev->driver_data = (void *) fifty_base_hpt370a;
-				printk("HPT37X: using 50MHz internal PLL\n");
-				goto init_hpt37X_done;
-			}
-		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
-
-init_hpt37X_done:
-	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
-	pci_write_config_byte(dev, 0x54, 0x37); 
-	udelay(100);
-}
-
-static void __init init_hpt366 (struct pci_dev *dev)
-{
-	unsigned int reg1	= 0;
-	byte drive_fast		= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 */
-	pci_read_config_byte(dev, 0x51, &drive_fast);
-	if (drive_fast & 0x80)
-		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
-	pci_read_config_dword(dev, 0x40, &reg1);
-									
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			dev->driver_data = (void *) forty_base_hpt366;
-			break;
-		case 9:
-			dev->driver_data = (void *) twenty_five_base_hpt366;
-			break;
-		case 7:
-		default:
-			dev->driver_data = (void *) thirty_three_base_hpt366;
-			break;
-	}
-
-	if (!dev->driver_data)
-		BUG();
-}
-
-unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
-{
-	byte test = 0;
-
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-
-	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-	if (test != (L1_CACHE_BYTES / 4))
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-	if (test != 0x78)
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-
-	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-	if (hpt_minimum_revision(dev, 3)) {
-		init_hpt37x(dev);
-		hpt_devs[n_hpt_devs++] = dev;
-	} else {
-		init_hpt366(dev);
-		hpt_devs[n_hpt_devs++] = dev;
-	}
-	
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt366_proc) {
-		hpt366_proc = 1;
-		hpt366_display_info = &hpt366_get_info;
-	}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
-{
-	byte ata66 = 0;
-	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
-
-	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
-#ifdef DEBUG
-	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-	return ((ata66 & regmask) ? 0 : 1);
-}
-
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev		= hwif->pci_dev;
-	hwif->tuneproc			= &hpt3xx_tune_drive;
-	hwif->speedproc			= &hpt3xx_tune_chipset;
-	hwif->quirkproc			= &hpt3xx_quirkproc;
-	hwif->intrproc			= &hpt3xx_intrproc;
-	hwif->maskproc			= &hpt3xx_maskproc;
-
-#ifdef HPT_SERIALIZE_IO
-	/* serialize access to this device */
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-#endif
-
-	if (hpt_minimum_revision(dev,3)) {
-		byte reg5ah = 0;
-			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-		/*
-		 * set up ioctl for power status.
-		 * note: power affects both
-		 * drives on each channel
-		 */
-		hwif->resetproc	= &hpt3xx_reset;
-		hwif->busproc	= &hpt370_busproc;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	} else if (hpt_minimum_revision(dev,2)) {
-		hwif->resetproc	= &hpt3xx_reset;
-		hwif->busproc	= &hpt3xx_tristate;
-	} else {
-		hwif->resetproc = &hpt3xx_reset;
-		hwif->busproc   = &hpt3xx_tristate;
-	}
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hpt_minimum_revision(dev,8))
-		hwif->dmaproc   = &hpt374_dmaproc;
-	else if (hpt_minimum_revision(dev,5))
-		hwif->dmaproc   = &hpt374_dmaproc;
-	else if (hpt_minimum_revision(dev,3))
-		hwif->dmaproc   = &hpt370_dmaproc;
-	else if (hpt_minimum_revision(dev,2))
-		hwif->dmaproc   = &hpt366_dmaproc;
-	else
-		hwif->dmaproc   = &hpt366_dmaproc;
-
-
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = IN_BYTE(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
-
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) OUT_BYTE(dma_new, dmabase+2);
-
-	local_irq_restore(flags);
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			break;
-		}
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2) {
-		return;
-	} else {
-		byte irq = 0, irq2 = 0;
-		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-		pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-		if (irq != irq2) {
-			pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-			dev2->irq = dev->irq;
-			printk("%s: pci-config space interrupt fixed.\n",
-				d->name);
-		}
-	}
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-
-}
-
-void __init fixup_device_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-	unsigned char pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
-				 "HPT370", "HPT370A", "HPT372"};
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	strcpy(d->name, chipset_names[class_rev]);
-
-	switch(class_rev) {
-		case 5:
-		case 4:
-		case 3:	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-				d->name, dev->bus->number, dev->devfn);
-			ide_setup_pci_device(dev, d);
-			return;
-		default:	break;
-	}
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-			hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
-			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
-			if (hpt363_shared_pin && hpt363_shared_irq) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, "
-					"pin1=%d pin2=%d\n", d->name,
-					pin1, pin2);
-#if 0
-				/*
-				 * This is the third undocumented detection
-				 * method and is generally required for the
-				 * ABIT-BP6 boards.
-				 */
-				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
-				printk("PCI: %s: Fixing interrupt %d pin %d "
-					"to ZERO \n", d->name, dev2->irq, pin2);
-				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
-			}
-			break;
-		}
-	}
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
-
diff -Nru a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
--- a/drivers/ide/ht6560b.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,341 +0,0 @@
-/*
- *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
- *
- *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
- *
- *  Version 0.01        Initial version hacked out of ide.c
- *
- *  Version 0.02        Added support for PIO modes, auto-tune
- *
- *  Version 0.03        Some cleanups
- *
- *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
- *
- *  Version 0.06        Prefetch mode now defaults no OFF. To set
- *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
- *                      Unmask irq is disabled when prefetch mode
- *                      is enabled.
- *
- *  Version 0.07        Trying to fix CD-ROM detection problem.
- *                      "Prefetch" mode bit OFF for ide disks and
- *                      ON for anything else.
- *
- *
- *  HT-6560B EIDE-controller support
- *  To activate controller support use kernel parameter "ide0=ht6560b".
- *  Use hdparm utility to enable PIO mode support.
- *
- *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
- *             Jan Evert van Grootheest   <janevert@iae.nl>
- *
- *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
- */
-
-#define HT6560B_VERSION "v0.07"
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* #define DEBUG */  /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit2 (0x04): "1" enables FIFO function
- *    bit5 (0x20): "1" enables prefetched data read function  (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit1 (0x02): "1" enables prefetched data read function
- *    bit2 (0x04): "0" enables multi-master system	      (?)
- *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
- */
-#define HT_CONFIG_PORT	  0x3e6
-#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF	  0x01
-#define HT_PREFETCH_MODE  0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use IDE_SELECT_REG to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives.   [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
- * of the value is the Active Time  (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- *	High nibble:  Recovery Cycle Time  (rt)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- *	Low nibble:   Active Cycle Time	   (at)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_selectproc (ide_drive_t *drive)
-{
-	unsigned long flags;
-	static byte current_select = 0;
-	static byte current_timing = 0;
-	byte select, timing;
-	
-	local_irq_save(flags);
-	
-	select = HT_CONFIG(drive);
-	timing = HT_TIMING(drive);
-	
-	if (select != current_select || timing != current_timing) {
-		current_select = select;
-		current_timing = timing;
-		if (drive->media != ide_disk || !drive->present)
-			select |= HT_PREFETCH_MODE;
-		(void) IN_BYTE(HT_CONFIG_PORT);
-		(void) IN_BYTE(HT_CONFIG_PORT);
-		(void) IN_BYTE(HT_CONFIG_PORT);
-		(void) IN_BYTE(HT_CONFIG_PORT);
-		OUT_BYTE(select, HT_CONFIG_PORT);
-		/*
-		 * Set timing for this drive:
-		 */
-		OUT_BYTE(timing, IDE_SELECT_REG);
-		(void) IN_BYTE(IDE_STATUS_REG);
-#ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n",
-			drive->name, select, timing);
-#endif
-	}
-	local_irq_restore(flags);
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-	byte orig_value;
-	int i;
-	
-	/* Autodetect ht6560b */
-	if ((orig_value = IN_BYTE(HT_CONFIG_PORT)) == 0xff)
-		return 0;
-	
-	for (i=3;i>0;i--) {
-		OUT_BYTE(0x00, HT_CONFIG_PORT);
-		if (!( (~IN_BYTE(HT_CONFIG_PORT)) & 0x3f )) {
-			OUT_BYTE(orig_value, HT_CONFIG_PORT);
-			return 0;
-		}
-	}
-	OUT_BYTE(0x00, HT_CONFIG_PORT);
-	if ((~IN_BYTE(HT_CONFIG_PORT))& 0x3f) {
-		OUT_BYTE(orig_value, HT_CONFIG_PORT);
-		return 0;
-	}
-	/*
-	 * Ht6560b autodetected
-	 */
-	OUT_BYTE(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-	OUT_BYTE(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
-	(void) IN_BYTE(0x1f7);               /* IDE_STATUS_REG */
-	
-	printk("\nht6560b " HT6560B_VERSION
-	       ": chipset detected and initialized"
-#ifdef DEBUG
-	       " with debug enabled"
-#endif
-		);
-	return 1;
-}
-
-static byte ht_pio2timings(ide_drive_t *drive, byte pio)
-{
-	int active_time, recovery_time;
-	int active_cycles, recovery_cycles;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-	
-        if (pio) {
-		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-		
-		/*
-		 *  Just like opti621.c we try to calculate the
-		 *  actual cycle time for recovery and activity
-		 *  according system bus speed.
-		 */
-		active_time = ide_pio_timings[pio].active_time;
-		recovery_time = d.cycle_time 
-			- active_time
-			- ide_pio_timings[pio].setup_time;
-		/*
-		 *  Cycle times should be Vesa bus cycles
-		 */
-		active_cycles   = (active_time   * bus_speed + 999) / 1000;
-		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
-		/*
-		 *  Upper and lower limits
-		 */
-		if (active_cycles   < 2)  active_cycles   = 2;
-		if (recovery_cycles < 2)  recovery_cycles = 2;
-		if (active_cycles   > 15) active_cycles   = 15;
-		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-		
-		return (byte)((recovery_cycles << 4) | active_cycles);
-	} else {
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-		
-		return HT_TIMING_DEFAULT;    /* default setting */
-	}
-}
-
-/*
- *  Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, byte state)
-{
-	unsigned long flags;
-	int t = HT_PREFETCH_MODE << 8;
-	
-	spin_lock_irqsave(&ide_lock, flags);
-	
-	/*
-	 *  Prefetch mode and unmask irq seems to conflict
-	 */
-	if (state) {
-		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-	} else {
-		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->no_unmask = 0;
-	}
-	
-	spin_unlock_irqrestore(&ide_lock, flags);
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void tune_ht6560b (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	byte timing;
-	
-	switch (pio) {
-	case 8:         /* set prefetch off */
-	case 9:         /* set prefetch on */
-		ht_set_prefetch(drive, pio & 1);
-		return;
-	}
-	
-	timing = ht_pio2timings(drive, pio);
-	
-	spin_lock_irqsave(&ide_lock, flags);
-	
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	
-	spin_unlock_irqrestore(&ide_lock, flags);
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-void __init init_ht6560b (void)
-{
-	int t;
-	
-	if (check_region(HT_CONFIG_PORT,1)) {
-		printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
-	} else {
-		if (try_to_init_ht6560b()) {
-			request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
-			ide_hwifs[0].chipset = ide_ht6560b;
-			ide_hwifs[1].chipset = ide_ht6560b;
-			ide_hwifs[0].selectproc = &ht6560b_selectproc;
-			ide_hwifs[1].selectproc = &ht6560b_selectproc;
-			ide_hwifs[0].tuneproc = &tune_ht6560b;
-			ide_hwifs[1].tuneproc = &tune_ht6560b;
-			ide_hwifs[0].serialized = 1;  /* is this needed? */
-			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].mate = &ide_hwifs[1];
-			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].channel = 1;
-			
-			/*
-			 * Setting default configurations for drives
-			 */
-			t = (HT_CONFIG_DEFAULT << 8);
-			t |= HT_TIMING_DEFAULT;
-			ide_hwifs[0].drives[0].drive_data = t;
-			ide_hwifs[0].drives[1].drive_data = t;
-			t |= (HT_SECONDARY_IF << 8);
-			ide_hwifs[1].drives[0].drive_data = t;
-			ide_hwifs[1].drives[1].drive_data = t;
-		} else
-			printk(KERN_ERR "ht6560b: not found\n");
-	}
-}
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Sun Sep 15 19:19:46 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,782 +0,0 @@
-/*
- * linux/drivers/ide/icside.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- *  08-Jun-1996	RMK	Created
- *  12-Sep-1997	RMK	Added interrupt enable/disable
- *  17-Apr-1999	RMK	Added support for V6 EASI
- *  22-May-1999	RMK	Added support for V6 DMA
- */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS	2
-
-#define ICS_IDENT_OFFSET		0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT		0x000
-#define ICS_ARCIN_V5_INTROFFSET		0x001
-#define ICS_ARCIN_V5_IDEOFFSET		0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
-#define ICS_ARCIN_V5_IDESTEPPING	4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
-#define ICS_ARCIN_V6_INTROFFSET_1	0x880
-#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
-#define ICS_ARCIN_V6_IDESTEPPING	4
-
-struct cardinfo {
-	unsigned int dataoffset;
-	unsigned int ctrloffset;
-	unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
-	ICS_ARCIN_V5_IDEOFFSET,
-	ICS_ARCIN_V5_IDEALTOFFSET,
-	ICS_ARCIN_V5_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
-	ICS_ARCIN_V6_IDEOFFSET_1,
-	ICS_ARCIN_V6_IDEALTOFFSET_1,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
-	ICS_ARCIN_V6_IDEOFFSET_2,
-	ICS_ARCIN_V6_IDEALTOFFSET_2,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static const card_ids icside_cids[] = {
-	{ MANU_ICS,  PROD_ICS_IDE  },
-	{ MANU_ICS2, PROD_ICS2_IDE },
-	{ 0xffff, 0xffff }
-};
-
-typedef enum {
-	ics_if_unknown,
-	ics_if_arcin_v5,
-	ics_if_arcin_v6
-} iftype_t;
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	OUT_BYTE(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	IN_BYTE(memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-	icside_irqenable_arcin_v5,
-	icside_irqdisable_arcin_v5,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	OUT_BYTE(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose  : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	return IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-	       IN_BYTE(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-	icside_irqenable_arcin_v6,
-	icside_irqdisable_arcin_v6,
-	icside_irqpending_arcin_v6,
-	NULL,
-	NULL,
-	NULL
-};
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t __init icside_identifyif (struct expansion_card *ec)
-{
-	unsigned int addr;
-	iftype_t iftype;
-	int id = 0;
-
-	iftype = ics_if_unknown;
-
-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-	id = IN_BYTE(addr) & 1;
-	id |= (IN_BYTE(addr + 1) & 1) << 1;
-	id |= (IN_BYTE(addr + 2) & 1) << 2;
-	id |= (IN_BYTE(addr + 3) & 1) << 3;
-
-	switch (id) {
-	case 0: /* A3IN */
-		printk("icside: A3IN unsupported\n");
-		break;
-
-	case 1: /* A3USER */
-		printk("icside: A3USER unsupported\n");
-		break;
-
-	case 3:	/* ARCIN V6 */
-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v6;
-		break;
-
-	case 15:/* ARCIN V5 (no id) */
-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v5;
-		break;
-
-	default:/* we don't know - complain very loudly */
-		printk("icside: ***********************************\n");
-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-		printk("icside: ***********************************\n");
-		printk("icside: please report this to linux@arm.linux.org.uk\n");
-		printk("icside: defaulting to ARCIN V5\n");
-		iftype = ics_if_arcin_v5;
-		break;
-	}
-
-	return iftype;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time.  NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-#define NR_ENTRIES 256
-#define TABLE_SIZE (NR_ENTRIES * 8)
-
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
-{
-	struct buffer_head *bh;
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
-
-	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
-}
-
-static int
-icside_build_dmatable(ide_drive_t *drive, int reading)
-{
-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void icside_destroy_dmatable(ide_drive_t *drive)
-{
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
-
-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
-}
-
-static int
-icside_config_if(ide_drive_t *drive, int xfer_mode)
-{
-	int func = ide_dma_off;
-
-	switch (xfer_mode) {
-	case XFER_MW_DMA_2:
-		/*
-		 * The cycle time is limited to 250ns by the r/w
-		 * pulse width (90ns), however we should still
-		 * have a maximum burst transfer rate of 8MB/s.
-		 */
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_1:
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_0:
-		drive->drive_data = 480;
-		break;
-
-	default:
-		drive->drive_data = 0;
-		break;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = (byte) xfer_mode;
-
-	if (drive->drive_data &&
-	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
-		func = ide_dma_on;
-	else
-		drive->drive_data = 480;
-
-	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
-		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
-	drive->current_speed = (byte) xfer_mode;
-
-	return func;
-}
-
-static int
-icside_set_speed(ide_drive_t *drive, byte speed)
-{
-	return icside_config_if(drive, speed);
-}
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
-{
-	int i;
-	byte stat, dma_stat;
-
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				DRIVER(drive)->end_request(drive, 1);
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
-	}
-	return DRIVER(drive)->error(drive, "dma_intr", stat);
-}
-
-/*
- * The following is a sick duplication from ide-dma.c ;(
- *
- * This should be defined in one place only.
- */
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-static struct drive_list_entry drive_whitelist [] = {
-	{ "Micropolis 2112A",			"ALL"		},
-	{ "CONNER CTMA 4000",			"ALL"		},
-	{ "CONNER CTT8000-A",			"ALL"		},
-	{ "ST34342A",				"ALL"		},
-	{ NULL,					0		}
-};
-
-static struct drive_list_entry drive_blacklist [] = {
-	{ "WDC AC11000H",			"ALL"		},
-	{ "WDC AC22100H",			"ALL"		},
-	{ "WDC AC32500H",			"ALL"		},
-	{ "WDC AC33100H",			"ALL"		},
-	{ "WDC AC31600H",			"ALL"		},
-	{ "WDC AC32100H",			"24.09P07"	},
-	{ "WDC AC23200L",			"21.10N21"	},
-	{ "Compaq CRD-8241B",			"ALL"		},
-	{ "CRD-8400B",				"ALL"		},
-	{ "CRD-8480B",				"ALL"		},
-	{ "CRD-8480C",				"ALL"		},
-	{ "CRD-8482B",				"ALL"		},
- 	{ "CRD-84",				"ALL"		},
-	{ "SanDisk SDP3B",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SANYO CD-ROM CRD",			"ALL"		},
-	{ "HITACHI CDR-8",			"ALL"		},
-	{ "HITACHI CDR-8335",			"ALL"		},
-	{ "HITACHI CDR-8435",			"ALL"		},
-	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
-	{ "CD-532E-A",				"ALL"		},
-	{ "E-IDE CD-ROM CR-840",		"ALL"		},
-	{ "CD-ROM Drive/F5A",			"ALL"		},
-	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
-	{ "WPI CDD-820",			"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
-	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
-	{ "_NEC DV5800A",			"ALL"		},
-	{ NULL,					0		}
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!strcmp(drive_table->id_firmware, "ALL"))))
-			return 1;
-	return 0;
-}
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-static int check_drive_lists(ide_drive_t *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-	return 0;
-}
-
-static int
-icside_dma_check(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	int autodma = hwif->autodma;
-	int xfer_mode = XFER_PIO_2;
-	int func = ide_dma_off_quietly;
-
-	if (!id || !(id->capability & 1) || !autodma)
-		goto out;
-
-	/*
-	 * Consult the list of known "bad" drives
-	 */
-	if (check_drive_lists(drive, 0)) {
-		func = ide_dma_off;
-		goto out;
-	}
-
-	/*
-	 * Enable DMA on any drive that has multiword DMA
-	 */
-	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
-			func = ide_dma_on;
-		}
-		goto out;
-	}
-
-	/*
-	 * Consult the list of known "good" drives
-	 */
-	if (check_drive_lists(drive, 1)) {
-		if (id->eide_dma_time > 150)
-			goto out;
-		xfer_mode = XFER_MW_DMA_1;
-		func = ide_dma_on;
-	}
-
-out:
-	func = icside_config_if(drive, xfer_mode);
-
-	return hwif->dmaproc(func, drive);
-}
-
-static int
-icside_dma_verbose(ide_drive_t *drive)
-{
-	printk(", DMA");
-	return 1;
-}
-
-static int
-icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-//	ide_task_t *args = HWGROUP(drive)->rq->special;
-	int count, reading = 0;
-
-	switch (func) {
-	case ide_dma_off:
-		printk("%s: DMA disabled\n", drive->name);
-		/*FALLTHROUGH*/
-
-	case ide_dma_off_quietly:
-	case ide_dma_on:
-		drive->using_dma = (func == ide_dma_on);
-		return 0;
-
-	case ide_dma_check:
-		return icside_dma_check(drive);
-
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		count = icside_build_dmatable(drive, reading);
-		if (!count)
-			return 1;
-		disable_dma(hwif->hw.dma);
-
-		/* Route the DMA signals to
-		 * to the correct interface.
-		 */
-		OUT_BYTE(hwif->select_data, hwif->config_data);
-
-		/* Select the correct timing
-		 * for this drive
-		 */
-		set_dma_speed(hwif->hw.dma, drive->drive_data);
-
-		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
-		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
-			     : DMA_MODE_WRITE);
-
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-			BUG();
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		/*
-		 * FIX ME to use only ACB ide_task_t args Struct
-		 */
-#if 0
-	{
-		ide_task_t *args = HWGROUP(drive)->rq->special;
-		OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-	}
-#else
-		if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		} else if (drive->addressing == 1)
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		else
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-#endif
-		return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-	case ide_dma_begin:
-		enable_dma(hwif->hw.dma);
-		return 0;
-
-	case ide_dma_end:
-		drive->waiting_for_dma = 0;
-		disable_dma(hwif->hw.dma);
-		icside_destroy_dmatable(drive);
-		return get_dma_residue(hwif->hw.dma) != 0;
-
-	case ide_dma_test_irq:
-		return IN_BYTE((unsigned long)hwif->hw.priv) & 1;
-
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-
-	case ide_dma_verbose:
-		return icside_dma_verbose(drive);
-
-	case ide_dma_timeout:
-	default:
-		printk("icside_dmaproc: unsupported %s func: %d\n",
-			ide_dmafunc_verbose(func), func);
-	}
-	return 1;
-}
-
-static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
-{
-	printk("    %s: SG-DMA", hwif->name);
-
-	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
-				 GFP_KERNEL);
-	if (!hwif->sg_table)
-		goto failed;
-
-	hwif->dmatable_cpu = NULL;
-	hwif->dmatable_dma = 0;
-	hwif->speedproc = icside_set_speed;
-	hwif->dmaproc = icside_dmaproc;
-	hwif->autodma = autodma;
-
-	printk(" capable%s\n", autodma ?
-		", auto-enable" : "");
-
-	return 1;
-
-failed:
-	printk(" -- ERROR, unable to allocate DMA table\n");
-	return 0;
-}
-#endif
-
-static ide_hwif_t *
-icside_find_hwif(unsigned long dataport)
-{
-	ide_hwif_t *hwif;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
-			goto found;
-	}
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (!hwif->io_ports[IDE_DATA_OFFSET])
-			goto found;
-	}
-
-	return NULL;
-found:
-	return hwif;
-}
-
-static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, int irq)
-{
-	unsigned long port = base + info->dataoffset;
-	ide_hwif_t *hwif;
-
-	hwif = icside_find_hwif(base);
-	if (hwif) {
-		int i;
-
-		memset(&hwif->hw, 0, sizeof(hw_regs_t));
-
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
-			hwif->io_ports[i] = (ide_ioreg_t)port;
-			port += 1 << info->stepping;
-		}
-		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->hw.irq  = irq;
-		hwif->irq     = irq;
-		hwif->hw.dma  = NO_DMA;
-		hwif->noprobe = 0;
-		hwif->chipset = ide_acorn;
-	}
-
-	return hwif;
-}
-
-static int __init icside_register_v5(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port;
-	ide_hwif_t *hwif;
-
-	slot_port = ecard_address(ec, ECARD_MEMC, 0);
-
-	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
-	ec->irqmask  = 1;
-	ec->irq_data = (void *)slot_port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	IN_BYTE(slot_port + ICS_ARCIN_V5_INTROFFSET);
-
-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
-
-	return hwif ? 0 : -1;
-}
-
-static int __init icside_register_v6(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port, port;
-	ide_hwif_t *hwif, *mate;
-	int sel = 0;
-
-	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
-
-	if (port == 0)
-		port = slot_port;
-	else
-		sel = 1 << 5;
-
-	OUT_BYTE(sel, slot_port);
-
-	ec->irq_data = (void *)port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_1);
-	IN_BYTE(port + ICS_ARCIN_V6_INTROFFSET_2);
-
-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-	if (ec->dma != NO_DMA) {
-		if (request_dma(ec->dma, hwif->name))
-			goto no_dma;
-
-		if (hwif) {
-			hwif->config_data = slot_port;
-			hwif->select_data = sel;
-			hwif->hw.dma  = ec->dma;
-			hwif->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_1);
-			hwif->channel = 0;
-			icside_setup_dma(hwif, autodma);
-		}
-		if (mate) {
-			mate->config_data = slot_port;
-			mate->select_data = sel | 1;
-			mate->hw.dma  = ec->dma;
-			mate->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_2);
-			mate->channel = 1;
-			icside_setup_dma(mate, autodma);
-		}
-	}
-no_dma:
-#endif
-	return hwif || mate ? 0 : -1;
-}
-
-int __init icside_init(void)
-{
-	int autodma = 0;
-
-#ifdef CONFIG_IDEDMA_ICS_AUTO
-	autodma = 1;
-#endif
-
-	ecard_startfind ();
-
-	do {
-		struct expansion_card *ec;
-		int result;
-
-		ec = ecard_find(0, icside_cids);
-		if (ec == NULL)
-			break;
-
-		ecard_claim(ec);
-
-		switch (icside_identifyif(ec)) {
-		case ics_if_arcin_v5:
-			result = icside_register_v5(ec, autodma);
-			break;
-
-		case ics_if_arcin_v6:
-			result = icside_register_v6(ec, autodma);
-			break;
-
-		default:
-			result = -1;
-			break;
-		}
-
-		if (result)
-			ecard_release(ec);
-	} while (1);
-
-	return 0;
-}
diff -Nru a/drivers/ide/ide-adma.c b/drivers/ide/ide-adma.c
--- a/drivers/ide/ide-adma.c	Sun Sep 15 19:20:24 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- *  linux/drivers/ide/ide-adma.c         Version 0.00	June 24, 2001
- *
- *  Copyright (c) 2001		Andre Hedrick <andre@linux-ide.org>
- *
- *  Asynchronous DMA -- TBA, this is a holding file.
- *
- */
-
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/ide/ide-cd.c	Sun Sep 15 19:19:37 2002
@@ -541,72 +541,49 @@
 
 
 /*
- * This is our end_request replacement function.
- */
-static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
-{
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
-		add_blkdev_randomness(major(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-		HWGROUP(drive)->rq = NULL;
-		end_that_request_last(rq);
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return ret;
-}
-
-/*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
 byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
 {
 	unsigned long flags;
-	byte err = 0;
 
+	atapi_status_t status;
+	atapi_error_t error;
+
+	status.all = stat;
 	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (status.b.bsy)
 		printk("Busy ");
 	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
+		if (status.b.drdy)	printk("DriveReady ");
+		if (status.b.df)	printk("DeviceFault ");
+		if (status.b.dsc)	printk("SeekComplete ");
+		if (status.b.drq)	printk("DataRequest ");
+		if (status.b.corr)	printk("CorrectedError ");
+		if (status.b.idx)	printk("Index ");
+		if (status.b.check)	printk("Error ");
 	}
 	printk("}");
 #endif	/* FANCY_STATUS_DUMPS */
 	printk("\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
-		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
+		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
 #if FANCY_STATUS_DUMPS
+		if (error.b.ili)	printk("IllegalLengthIndication ");
+		if (error.b.eom)	printk("EndOfMedia ");
+		if (error.b.abrt)	printk("Aborted Command ");
+		if (error.b.mcr)	printk("MediaChangeRequested ");
+		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
+						error.b.sense_key);
 #endif	/* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
 	local_irq_restore(flags);
-	return err;
+	return error.all;
 }
 
 /*
@@ -630,12 +607,14 @@
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
 		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
+	} else {
+		/* add decoding error stuff */
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
 		/* force an abort */
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
 	if (rq->errors >= ERROR_MAX) {
-		DRIVER(drive)->end_request(drive, 0);
+		DRIVER(drive)->end_request(drive, 0, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -656,10 +635,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors)
-			uptodate = 1;
+	if (blk_fs_request(rq) && !rq->current_nr_sectors)
+		uptodate = 1;
 
-	ide_cdrom_end_request(drive, uptodate);
+	ide_end_request(drive, uptodate, rq->hard_cur_sectors);
 }
 
 
@@ -673,14 +652,13 @@
 	struct packet_command *pc;
 	
 	/* Check for errors. */
-	stat = GET_STAT();
-	*stat_ret = stat;
+	*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
 	/* Get the IDE error register. */
-	err = GET_ERR();
+	err = HWIF(drive)->INB(IDE_ERROR_REG);
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
@@ -737,7 +715,7 @@
 
 		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
-	} else if (rq->flags & REQ_CMD) {
+	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
@@ -767,6 +745,11 @@
 			   for other errors. */
 			*startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
 			return 1;
+		} else if (sense_key == MEDIUM_ERROR) {
+			/* No point in re-trying a zillion times on a bad 
+			 * sector...  If we got here the error is not correctable */
+			ide_dump_status (drive, "media error (bad sector)", stat);
+			cdrom_end_request(drive, 0);
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
 			cdrom_end_request(drive, 0);
@@ -829,35 +812,37 @@
 
 	if (info->dma) {
 		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+			info->dma = !HWIF(drive)->ide_dma_read(drive);
 		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+			info->dma = !HWIF(drive)->ide_dma_write(drive);
 		} else {
 			printk("ide-cd: DMA set, but not allowed\n");
 		}
 	}
 
 	/* Set up the controller registers. */
-	OUT_BYTE(info->dma, IDE_FEATURE_REG);
-	OUT_BYTE(0, IDE_NSECTOR_REG);
-	OUT_BYTE(0, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
 
-	OUT_BYTE(xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE(xferlen >> 8  , IDE_HCYL_REG);
+	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
 	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		if (HWGROUP(drive)->handler != NULL)
 			BUG();
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*handler) (drive);
 	}
 }
@@ -880,17 +865,18 @@
 	unsigned int timeout	= pc->timeout;
 	ide_startstop_t startstop;
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+	if (CDROM_CONFIG_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 (&startstop, drive, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+				BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
@@ -898,10 +884,10 @@
 		BUG();
 
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
+	ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
-	atapi_output_bytes (drive, cmd_buf, cmd_len);
+	HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len);
 	return ide_started;
 }
 
@@ -939,7 +925,7 @@
 	/* Read the data into the buffer. */
 	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
-		atapi_input_bytes (drive, dest, SECTOR_SIZE);
+		HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
 		--sectors_to_transfer;
 		++info->nsectors_buffered;
@@ -949,7 +935,7 @@
 	/* Throw away any remaining data. */
 	while (sectors_to_transfer > 0) {
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 		--sectors_to_transfer;
 	}
 }
@@ -975,14 +961,14 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
 		 * info is available. just get it and ignore.
 		 */
-		GET_STAT();
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
 		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -1002,7 +988,8 @@
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
-	int i, dma = info->dma, dma_error = 0;
+	u8 lowcyl = 0, highcyl = 0;
+	int dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1010,8 +997,8 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
+			HWIF(drive)->ide_dma_off(drive);
 	}
 
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -1019,18 +1006,18 @@
  
 	if (dma) {
 		if (!dma_error) {
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_cdrom_end_request(drive, 1);
-			}
+			ide_end_request(drive, 1, rq->nr_sectors);
 			return ide_stopped;
 		} else
 			return DRIVER(drive)->error(drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE(IDE_NSECTOR_REG);
-	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -1055,11 +1042,11 @@
 	if ((len % SECTOR_SIZE) != 0) {
 		printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
 			drive->name, len);
-		if (CDROM_CONFIG_FLAGS (drive)->limit_nframes)
+		if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
 			printk ("  This drive is not supported by this version of the driver\n");
 		else {
 			printk ("  Trying to limit transfer sizes\n");
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		}
 		cdrom_end_request(drive, 0);
 		return ide_stopped;
@@ -1075,7 +1062,7 @@
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 
 		--rq->current_nr_sectors;
 		--nskip;
@@ -1106,7 +1093,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+				HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -1172,7 +1159,7 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < bio_sectors(rq->bio) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+		printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
 			drive->name, rq->sector);
 		cdrom_end_request(drive, 0);
 		return -1;
@@ -1297,7 +1284,7 @@
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
 }
 
 /* Fix up a possibly partially-processed request so that we can
@@ -1364,14 +1351,18 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
+	u8 lowcyl = 0, highcyl = 0;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed.
 	   Complain if we still have data left to transfer. */
@@ -1410,14 +1401,14 @@
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
 		/* Transfer the data. */
-		atapi_output_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1429,14 +1420,14 @@
 	else if ((ireason & 3) == 2) {
 
 		/* Transfer the data. */
-		atapi_input_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_input_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1449,11 +1440,11 @@
 		pc->stat = 1;
 	}
 
-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
 		BUG();
 
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
@@ -1484,7 +1475,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1516,7 +1507,7 @@
 		ide_init_drive_cmd (&req);
 		req.flags = REQ_PC;
 		req.buffer = (char *)pc;
-		ide_do_drive_cmd (drive, &req, ide_wait);
+		ide_do_drive_cmd(drive, &req, ide_wait);
 		/* FIXME: we should probably abort/retry or something 
 		 * in case of failure */
 		if (pc->stat != 0) {
@@ -1526,7 +1517,7 @@
 			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
-				cdrom_saw_media_change (drive);
+				cdrom_saw_media_change(drive);
 			else if (reqbuf->sense_key == NOT_READY &&
 				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
@@ -1567,7 +1558,7 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes(drive, &dum, sizeof(dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
 			len -= sizeof(dum);
 		}
 	} else {
@@ -1584,7 +1575,8 @@
 {
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
-	int i, dma_error = 0, dma = info->dma;
+	int dma_error = 0, dma = info->dma;
+	u8 lowcyl = 0, highcyl = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1592,9 +1584,9 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
 			printk("ide-cd: write dma error\n");
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			HWIF(drive)->ide_dma_off(drive);
 		}
 	}
 
@@ -1610,17 +1602,16 @@
 		if (dma_error)
 			return DRIVER(drive)->error(drive, "dma error", stat);
 
-		rq = HWGROUP(drive)->rq;
-		for (i = rq->nr_sectors; i > 0;) {
-			i -= rq->current_nr_sectors;
-			ide_cdrom_end_request(drive, 1);
-		}
+		ide_end_request(drive, 1, rq->nr_sectors);
 		return ide_stopped;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE(IDE_NSECTOR_REG);
-	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -1661,7 +1652,7 @@
 		this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);
 
 		while (this_transfer > 0) {
-			atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+			HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
 			rq->buffer += SECTOR_SIZE;
 			--rq->nr_sectors;
 			--rq->current_nr_sectors;
@@ -1761,10 +1752,10 @@
 	ide_startstop_t action;
 	struct cdrom_info *info = drive->driver_data;
 
-	if (rq->flags & REQ_CMD) {
+	if (blk_fs_request(rq)) {
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
 			unsigned long elpased = jiffies - info->start_seek;
-			int stat = GET_STAT();
+			int stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 			if ((stat & SEEK_STAT) != SEEK_STAT) {
 				if (elpased < IDECD_SEEK_TIMEOUT) {
@@ -1898,7 +1889,7 @@
 		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command (drive, &pc);
+		stat = cdrom_queue_packet_command(drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1908,7 +1899,7 @@
 	    (sense->asc == 0x24 || sense->asc == 0x20)) {
 		printk ("%s: door locking not supported\n",
 			drive->name);
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 		stat = 0;
 	}
 	
@@ -1917,7 +1908,7 @@
 		stat = 0;
 
 	if (stat == 0)
-		CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
+		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
 
 	return stat;
 }
@@ -1942,7 +1933,7 @@
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1991,7 +1982,7 @@
 	if (msf_flag)
 		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -2031,9 +2022,9 @@
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
@@ -2071,7 +2062,7 @@
 			return stat;
 		}
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
+		if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
 			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
 			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
 		} else
@@ -2088,18 +2079,18 @@
 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
 	for (i=0; i<=ntracks; i++) {
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) {
-			if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd)
-				toc->ent[i].track = bcd2bin (toc->ent[i].track);
-			msf_from_bcd (&toc->ent[i].addr.msf);
+		if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+			if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+				toc->ent[i].track = bcd2bin(toc->ent[i].track);
+			msf_from_bcd(&toc->ent[i].addr.msf);
 		}
 #endif  /* not STANDARD_ATAPI */
 		toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
@@ -2121,7 +2112,7 @@
 	}
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
+	if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
 		msf_from_bcd (&ms_tmp.ent.addr.msf);
 #endif  /* not STANDARD_ATAPI */
 
@@ -2141,7 +2132,7 @@
 	set_capacity(drive->disk, toc->capacity * SECTORS_PER_FRAME);
 
 	/* Remember that we've read this stuff. */
-	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid = 1;
 
 	return 0;
 }
@@ -2368,7 +2359,7 @@
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
-		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce);
+		stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
 		if (stat) return stat;
 
 		tocentry->cdte_ctrl = toce->control;
@@ -2440,10 +2431,10 @@
 	struct request_sense sense;
 	int stat;
 
-	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
+	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
 		return stat;
 
-        cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
         return 0;
 }
 
@@ -2536,8 +2527,8 @@
 	
 	if (slot_nr == CDSL_CURRENT) {
 		(void) cdrom_check_status(drive, NULL);
-		retval = CDROM_STATE_FLAGS (drive)->media_changed;
-		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		retval = CDROM_STATE_FLAGS(drive)->media_changed;
+		CDROM_STATE_FLAGS(drive)->media_changed = 0;
 		return retval;
 	} else {
 		return -EINVAL;
@@ -2597,27 +2588,27 @@
 	devinfo->dev = mk_kdev(drive->disk->major, drive->disk->first_minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
-	*(int *)&devinfo->capacity = nslots;
+	devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+	devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
 	
 	/* set capability mask to match the probe. */
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
 		devinfo->mask |= CDC_CD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
 		devinfo->mask |= CDC_CD_RW;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd)
 		devinfo->mask |= CDC_DVD;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
 		devinfo->mask |= CDC_DVD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		devinfo->mask |= CDC_DVD_RAM;
-	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
+	if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
 		devinfo->mask |= CDC_SELECT_DISC;
-	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
+	if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
 		devinfo->mask |= CDC_PLAY_AUDIO;
-	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+	if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
@@ -2672,9 +2663,9 @@
 	struct atapi_capabilities_page cap;
 	int nslots = 1;
 
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
+	if (CDROM_CONFIG_FLAGS(drive)->nec260) {
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;       
 		return nslots;
 	}
 
@@ -2682,38 +2673,38 @@
 		return 0;
 
 	if (cap.lock == 0)
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 	if (cap.eject)
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
 	if (cap.cd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
 	if (cap.cd_rw_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
 	if (cap.test_write)
-		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
+		CDROM_CONFIG_FLAGS(drive)->test_write = 1;
 	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
-		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
 	if (cap.dvd_ram_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
 	if (cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
 	if (cap.audio_play)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
-		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
+		CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
 
 	/* Some drives used by Apple don't advertise audio play
 	 * but they do support reading TOC & audio datas
 	 */
-	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+	if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
 	if (cdi->sanyo_slot > 0) {
-		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
+		CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
 		nslots = 3;
 	}
 
@@ -2722,21 +2713,22 @@
 	if (cap.mechtype == mechtype_individual_changer ||
 	    cap.mechtype == mechtype_cartridge_changer) {
 		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
-			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
-			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
+			CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+			CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
 		}
 	}
 
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+	if (drive->id && !drive->id->model[0] &&
+	    !strncmp(drive->id->fw_rev, "241N", 4)) {
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(((unsigned int)cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(ntohs(cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
 
@@ -2747,26 +2739,26 @@
 		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-        	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
-        	printk (" CD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+	if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+        	printk(" DVD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+
+        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+        	printk(" CD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
 
-        if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
-        	printk (" changer w/%d slots", nslots);
+        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
+        	printk(" changer w/%d slots", nslots);
         else 	
-        	printk (" drive");
+        	printk(" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
+	printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -2836,42 +2828,42 @@
 	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
-	CDROM_STATE_FLAGS (drive)->media_changed = 1;
-	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
-	CDROM_STATE_FLAGS (drive)->door_locked   = 0;
+	CDROM_STATE_FLAGS(drive)->media_changed = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
+	CDROM_STATE_FLAGS(drive)->door_locked   = 0;
 
 #if NO_DOOR_LOCKING
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 #else
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
 #endif
 
 	if (drive->id != NULL)
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt =
 			((drive->id->config & 0x0060) == 0x20);
 	else
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0;
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->is_changer = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
-	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
-	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
-	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
-	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
-	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
+	CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+	CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
 	
 	/* limit transfer size per interrupt. */
-	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
+	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
 	if (drive->id != NULL) {
 		/* a testament to the nice quality of Samsung drives... */
 		if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		/* the 3231 model does not support the SET_CD_SPEED command */
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
 			cdi->mask |= CDC_SELECT_SPEED;
@@ -2882,11 +2874,11 @@
            ATAPI Rev 2.2+ standard support for CD changers is used */
 	cdi->sanyo_slot = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->nec260 = 0;
-	CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+	CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
 
 	if (drive->id != NULL) {
 		if (strcmp (drive->id->model, "V003S0DS") == 0 &&
@@ -2894,36 +2886,36 @@
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 300.
 			   Some versions of this drive like to talk BCD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
 		else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
 		    drive->id->fw_rev[4] == '1' &&
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 600 ESD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
 		}
 
-		else if (strcmp (drive->id->model,
+		else if (strcmp(drive->id->model,
 				 "NEC CD-ROM DRIVE:260") == 0 &&
-			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+			 strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
 			/* Old NEC260 (not R).
 			   This drive was released before the 1.2 version
 			   of the spec. */
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->nec260         = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
 		}
 
-		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
-			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+		else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+			 strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
 			/* Wearnes */
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
                 /* Sanyo 3 CD changer uses a non-standard command
@@ -2952,7 +2944,16 @@
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		set_device_ro(mk_kdev(drive->disk->major, drive->disk->first_minor), 0);
 
-	if (ide_cdrom_register (drive, nslots)) {
+#if 0
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
+			drive->name);
+		drive->dsc_overlap = 0;
+	}
+#endif
+
+	if (ide_cdrom_register(drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
 		info->devinfo.handle = NULL;
 		return 1;
@@ -2967,7 +2968,7 @@
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	return cdrom_ioctl (inode, file, cmd, arg);
+	return cdrom_ioctl(inode, file, cmd, arg);
 }
 
 static
@@ -3026,23 +3027,26 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	struct gendisk *g = drive->disk;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to ide_unregister_subdriver\n",
+			__FUNCTION__, drive->name);
 		return 1;
+	}
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
 		kfree(info->toc);
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
-	if (devinfo->handle == drive && unregister_cdrom (devinfo))
-		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
+	if (devinfo->handle == drive && unregister_cdrom(devinfo))
+		printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree(info);
 	drive->driver_data = NULL;
 	del_gendisk(g);
 	return 0;
 }
 
-static int ide_cdrom_reinit (ide_drive_t *drive);
+static int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	owner:			THIS_MODULE,
@@ -3062,7 +3066,7 @@
 	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
-	end_request:		ide_cdrom_end_request,
+	end_request:		NULL,
 	sense:			ide_cdrom_dump_status,
 	error:			ide_cdrom_error,
 	ioctl:			ide_cdrom_ioctl,
@@ -3074,7 +3078,7 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			ide_cdrom_reinit,
+	attach:			ide_cdrom_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 	drives:			LIST_HEAD_INIT(ide_cdrom_driver.drives),
@@ -3086,7 +3090,7 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cdrom_reinit (ide_drive_t *drive)
+static int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	struct gendisk *g = drive->disk;
@@ -3111,28 +3115,29 @@
 	}
 	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 	if (info == NULL) {
-		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		printk("%s: Can't allocate a cdrom structure\n", drive->name);
 		goto failed;
 	}
-	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (info);
+	if (ide_register_subdriver(drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk("%s: Failed to register the driver with ide.c\n",
+			drive->name);
+		kfree(info);
 		goto failed;
 	}
-	memset (info, 0, sizeof (struct cdrom_info));
+	memset(info, 0, sizeof (struct cdrom_info));
 	drive->driver_data = info;
 	DRIVER(drive)->busy++;
-	if (ide_cdrom_setup (drive)) {
+	if (ide_cdrom_setup(drive)) {
 		struct cdrom_device_info *devinfo = &info->devinfo;
 		DRIVER(drive)->busy--;
-		ide_unregister_subdriver (drive);
+		ide_unregister_subdriver(drive);
 		if (info->buffer != NULL)
 			kfree(info->buffer);
 		if (info->toc != NULL)
 			kfree(info->toc);
 		if (info->changer_info != NULL)
 			kfree(info->changer_info);
-		if (devinfo->handle == drive && unregister_cdrom (devinfo))
+		if (devinfo->handle == drive && unregister_cdrom(devinfo))
 			printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 		kfree(info);
 		drive->driver_data = NULL;
diff -Nru a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
--- a/drivers/ide/ide-cs.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,492 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA IDE/ATA disk cards
-
-    ide_cs.c 1.26 1999/11/16 02:10:49
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/major.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static const char ide_major[] = {
-    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
-#ifdef IDE4_MAJOR
-    IDE4_MAJOR, IDE5_MAJOR
-#endif
-};
-
-typedef struct ide_info_t {
-    dev_link_t	link;
-    int		ndev;
-    dev_node_t	node;
-    int		hd;
-} ide_info_t;
-
-static void ide_config(dev_link_t *link);
-static void ide_release(u_long arg);
-static int ide_event(event_t event, int priority,
-		     event_callback_args_t *args);
-
-static dev_info_t dev_info = "ide-cs";
-
-static dev_link_t *ide_attach(void);
-static void ide_detach(dev_link_t *);
-
-static dev_link_t *dev_list = NULL;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
-static dev_link_t *ide_attach(void)
-{
-    ide_info_t *info;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int i, ret;
-    
-    DEBUG(0, "ide_attach()\n");
-
-    /* Create new ide device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
-    if (!info) return NULL;
-    memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
-
-    link->release.function = &ide_release;
-    link->release.data = (u_long)link;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-    link->io.IOAddrLines = 3;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-	link->irq.IRQInfo2 = irq_mask;
-    else
-	for (i = 0; i < 4; i++)
-	    link->irq.IRQInfo2 |= 1 << irq_list[i];
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ide_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = CardServices(RegisterClient, &link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-	cs_error(link->handle, RegisterClient, ret);
-	ide_detach(link);
-	return NULL;
-    }
-    
-    return link;
-} /* ide_attach */
-
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
-static void ide_detach(dev_link_t *link)
-{
-    dev_link_t **linkp;
-    int ret;
-
-    DEBUG(0, "ide_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
-
-    del_timer(&link->release);
-    if (link->state & DEV_CONFIG)
-	ide_release((u_long)link);
-    
-    if (link->handle) {
-	ret = CardServices(DeregisterClient, link->handle);
-	if (ret != CS_SUCCESS)
-	    cs_error(link->handle, DeregisterClient, ret);
-    }
-    
-    /* Unlink, free device structure */
-    *linkp = link->next;
-    kfree(link->priv);
-    
-} /* ide_detach */
-
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-#define CFG_CHECK(fn, args...) \
-if (CardServices(fn, args) != 0) goto next_entry
-
-int idecs_register (int arg1, int arg2, int irq)
-{
-        hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
-        hw.irq = irq;
-        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
-        return ide_register_hw(&hw, NULL);
-}
-
-void ide_config(dev_link_t *link)
-{
-    client_handle_t handle = link->handle;
-    ide_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    config_info_t conf;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
-    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
-
-    DEBUG(0, "ide_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    CS_CHECK(GetTupleData, handle, &tuple);
-    CS_CHECK(ParseTuple, handle, &tuple, &parse);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, handle, &conf);
-    link->conf.Vcc = conf.Vcc;
-    
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    while (1) {
-	CFG_CHECK(GetTupleData, handle, &tuple);
-	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-	/* Check for matching Vcc, unless we're desperate */
-	if (!pass) {
-	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    }
-	}
-	
-	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-	
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	    if (io->nwin == 2) {
-		link->io.NumPorts1 = 8;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = 1;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort2;
-	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-		link->io.NumPorts1 = io->win[0].len;
-		link->io.NumPorts2 = 0;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort1+0x0e;
-	    } else goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-	
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	if (pass) {
-	    CS_CHECK(GetNextTuple, handle, &tuple);
-	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, handle, &tuple);
-	    memset(&dflt, 0, sizeof(dflt));
-	    pass++;
-	}
-    }
-    
-    CS_CHECK(RequestIRQ, handle, &link->irq);
-    CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-    /* deal with brain dead IDE resource management */
-    release_region(link->io.BasePort1, link->io.NumPorts1);
-    if (link->io.NumPorts2)
-	release_region(link->io.BasePort2, link->io.NumPorts2);
-
-    /* retry registration in case device is still spinning up */
-    for (i = 0; i < 10; i++) {
-	if (ctl_base)
-	    OUT_BYTE(0x02, ctl_base); /* Set nIEN = disable device interrupts */
-	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
-	if (hd >= 0) break;
-	if (link->io.NumPorts1 == 0x20) {
-	    if (ctl_base)
-		OUT_BYTE(0x02, ctl_base+0x10);
-	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
-			      link->irq.AssignedIRQ);
-	    if (hd >= 0) {
-		io_base += 0x10; ctl_base += 0x10;
-		break;
-	    }
-	}
-	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/10);
-    }
-    
-    if (hd < 0) {
-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
-	       ", irq %u failed\n", io_base, ctl_base,
-	       link->irq.AssignedIRQ);
-	goto failed;
-    }
-
-    MOD_INC_USE_COUNT;
-    info->ndev = 1;
-    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
-    info->node.major = ide_major[hd];
-    info->node.minor = 0;
-    info->hd = hd;
-    link->dev = &info->node;
-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
-	   link->conf.Vpp1/10, link->conf.Vpp1%10);
-
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
-cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
-failed:
-    ide_release((u_long)link);
-
-} /* ide_config */
-
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
-void ide_release(u_long arg)
-{
-    dev_link_t *link = (dev_link_t *)arg;
-    ide_info_t *info = link->priv;
-    
-    DEBUG(0, "ide_release(0x%p)\n", link);
-
-    if (info->ndev) {
-	ide_unregister(info->hd);
-	MOD_DEC_USE_COUNT;
-    }
-
-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
-    if (link->io.NumPorts2)
-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-    
-    info->ndev = 0;
-    link->dev = NULL;
-    
-    CardServices(ReleaseConfiguration, link->handle);
-    CardServices(ReleaseIO, link->handle, &link->io);
-    CardServices(ReleaseIRQ, link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
-
-} /* ide_release */
-
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-    
-======================================================================*/
-
-int ide_event(event_t event, int priority,
-	      event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-
-    DEBUG(1, "ide_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-	    mod_timer(&link->release, jiffies + HZ/20);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	ide_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG)
-	    CardServices(ReleaseConfiguration, link->handle);
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (DEV_OK(link))
-	    CardServices(RequestConfiguration, link->handle, &link->conf);
-	break;
-    }
-    return 0;
-} /* ide_event */
-
-/*====================================================================*/
-
-static int __init init_ide_cs(void)
-{
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
-}
-
-static void __exit exit_ide_cs(void)
-{
-    DEBUG(0, "ide_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
-}
-
-module_init(init_ide_cs);
-module_exit(exit_ide_cs);
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/ide/ide-disk.c	Sun Sep 15 19:19:37 2002
@@ -57,32 +57,31 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/suspend.h>
 #include <linux/buffer_head.h>
 
+#define _IDE_DISK
+
+#include <linux/ide.h>
+
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
-#else
-#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
-#endif
+/* FIXME: soem day we shouldnt need to look in here! */
+
+#include "legacy/pdc4030.h"
 
 static int driver_blocked;
 
 static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
 }
 
-static int idedisk_end_request(ide_drive_t *drive, int uptodate);
-
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
  * value for this drive (from its reported identification information).
@@ -111,7 +110,7 @@
 	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
 	    id->sectors == 63 &&
 	    (id->heads == 15 || id->heads == 16) &&
-	    id->lba_capacity >= 16383*63*id->heads)
+	    (id->lba_capacity >= 16383*63*id->heads))
 		return 1;
 
 	lba_sects   = id->lba_capacity;
@@ -140,15 +139,15 @@
  */
 static ide_startstop_t read_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
+	ide_hwif_t *hwif	= HWIF(drive);
+	int i = 0, nsect	= 0, msect = drive->mult_count;
 	struct request *rq;
 	unsigned long flags;
+	u8 stat;
 	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat=hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			return DRIVER(drive)->error(drive, "read_intr", stat);
 		}
@@ -158,8 +157,7 @@
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
-	msect = drive->mult_count;
-	
+
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -175,12 +173,12 @@
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
-	ide_unmap_buffer(to, &flags);
+	ide_unmap_buffer(rq, to, &flags);
 	rq->sector += nsect;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		idedisk_end_request(drive, 1);
+		ide_end_request(drive, 1, rq->hard_cur_sectors);
 	/*
 	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
 	 * If passed back up on multimode read, BAD DATA could be ACKED
@@ -189,7 +187,7 @@
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		if (HWGROUP(drive)->handler != NULL)
 			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
                 return ide_started;
@@ -202,13 +200,16 @@
  */
 static ide_startstop_t write_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= hwgroup->rq;
+	int i = 0;
+	u8 stat;
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n",
+			drive->name, rq->nr_sectors, stat);
         } else {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
@@ -221,12 +222,12 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
-				idedisk_end_request(drive, 1);
+				ide_end_request(drive, 1, rq->hard_cur_sectors);
 			if (i > 0) {
 				unsigned long flags;
 				char *to = ide_map_buffer(rq, &flags);
 				taskfile_output_data(drive, to, SECTOR_WORDS);
-				ide_unmap_buffer(to, &flags);
+				ide_unmap_buffer(rq, to, &flags);
 				if (HWGROUP(drive)->handler != NULL)
 					BUG();
 				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
@@ -234,7 +235,8 @@
 			}
                         return ide_stopped;
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
 	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
@@ -257,8 +259,8 @@
  */
 int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
+ 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+ 	struct request *rq	= &hwgroup->wrq;
  
   	do {
   		char *buffer;
@@ -268,8 +270,8 @@
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
-
 		buffer = ide_map_buffer(rq, &flags);
+
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -302,7 +304,7 @@
 		 * re-entering us on the last transfer.
 		 */
 		taskfile_output_data(drive, buffer, nsect<<7);
-		ide_unmap_buffer(buffer, &flags);
+		ide_unmap_buffer(rq, buffer, &flags);
 	} while (mcount);
 
         return 0;
@@ -313,12 +315,13 @@
  */
 static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= &hwgroup->wrq;
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	stat = hwif->INB(IDE_STATUS_REG);
+	if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			/*
 			 *	The drive wants data. Remember rq is the copy
@@ -339,24 +342,200 @@
 			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
-				for (i = rq->nr_sectors; i > 0;){
-					i -= rq->current_nr_sectors;
-					idedisk_end_request(drive, 1);
-				}
+				ide_end_request(drive, 1, rq->nr_sectors);
 				return ide_stopped;
 			}
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
 	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
-#endif /* CONFIG_IDE_TASKFILE_IO */
 
-#ifdef CONFIG_IDE_TASKFILE_IO
 
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+	ata_nsector_t		nsectors;
+
+	nsectors.all		= (u16) rq->nr_sectors;
+
+	if (driver_blocked)
+		panic("Request while ide driver is blocked?");
+
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+	if (IS_PDC4030_DRIVE)
+		return promise_rw_disk(drive, rq, block);
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+	if (drive->select.b.lba) {
+		if (drive->addressing == 1) {
+			task_ioreg_t tasklets[10];
+
+			tasklets[0] = 0;
+			tasklets[1] = 0;
+			tasklets[2] = nsectors.b.low;
+			tasklets[3] = nsectors.b.high;
+			tasklets[4] = (task_ioreg_t) block;
+			tasklets[5] = (task_ioreg_t) (block>>8);
+			tasklets[6] = (task_ioreg_t) (block>>16);
+			tasklets[7] = (task_ioreg_t) (block>>24);
+			tasklets[8] = (task_ioreg_t) 0;
+			tasklets[9] = (task_ioreg_t) 0;
+//			tasklets[8] = (task_ioreg_t) (block>>32);
+//			tasklets[9] = (task_ioreg_t) (block>>40);
+#ifdef DEBUG
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
+				"buffer=0x%08lx, LBAsect=0x%012lx\n",
+				drive->name,
+				(rq->cmd==READ)?"read":"writ",
+				block,
+				rq->nr_sectors,
+				(unsigned long) rq->buffer,
+				block);
+			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+				drive->name, tasklets[3], tasklets[2],
+				tasklets[9], tasklets[8], tasklets[7],
+				tasklets[6], tasklets[5], tasklets[4]);
+#endif
+			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
+
+			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
+		} else {
+#ifdef DEBUG
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+				"buffer=0x%08lx\n",
+				drive->name, (rq->cmd==READ)?"read":"writ",
+				block, rq->nr_sectors,
+				(unsigned long) rq->buffer);
+#endif
+			hwif->OUTB(0x00, IDE_FEATURE_REG);
+			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			hwif->OUTB(block, IDE_SECTOR_REG);
+			hwif->OUTB(block>>=8, IDE_LCYL_REG);
+			hwif->OUTB(block>>=8, IDE_HCYL_REG);
+			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+		}
+	} else {
+		unsigned int sect,head,cyl,track;
+		track = block / drive->sect;
+		sect  = block % drive->sect + 1;
+		hwif->OUTB(sect, IDE_SECTOR_REG);
+		head  = track % drive->head;
+		cyl   = track / drive->head;
+
+		hwif->OUTB(0x00, IDE_FEATURE_REG);
+		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		hwif->OUTB(cyl, IDE_LCYL_REG);
+		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
+#ifdef DEBUG
+		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
+			drive->name, (rq->cmd==READ)?"read":"writ", cyl,
+			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+	}
+
+	if (rq_data_dir(rq) == READ) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (drive->using_dma && !hwif->ide_dma_read(drive))
+			return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTREAD_EXT : WIN_MULTREAD) :
+			   ((lba48) ? WIN_READ_EXT : WIN_READ));
+		hwif->OUTB(command, IDE_COMMAND_REG);
+		return ide_started;
+	} else if (rq_data_dir(rq) == WRITE) {
+		ide_startstop_t startstop;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
+			return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) :
+			   ((lba48) ? WIN_WRITE_EXT : WIN_WRITE));
+		hwif->OUTB(command, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+				drive->name,
+				drive->mult_count ? "MULTWRITE" : "WRITE");
+			return startstop;
+		}
+		if (!drive->unmask)
+			local_irq_disable();
+		if (drive->mult_count) {
+			ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	/*
+	 * Ugh.. this part looks ugly because we MUST set up
+	 * the interrupt handler before outputting the first block
+	 * of data to be written.  If we hit an error (corrupted buffer list)
+	 * in ide_multwrite(), then we need to remove the handler/timer
+	 * before returning.  Fortunately, this NEVER happens (right?).
+	 *
+	 * Except when you get an error it seems...
+	 *
+	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
+	 */
+			hwgroup->wrq = *rq; /* scratchpad */
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
+			if (ide_multwrite(drive, drive->mult_count)) {
+				unsigned long flags;
+				spin_lock_irqsave(&ide_lock, flags);
+				hwgroup->handler = NULL;
+				del_timer(&hwgroup->timer);
+				spin_unlock_irqrestore(&ide_lock, flags);
+				return ide_stopped;
+			}
+		} else {
+			unsigned long flags;
+			char *to = ide_map_buffer(rq, &flags);
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+			taskfile_output_data(drive, to, SECTOR_WORDS);
+			ide_unmap_buffer(rq, to, &flags);
+		}
+		return ide_started;
+	}
+	blk_dump_rq_flags(rq, "do_rw_disk - bad command");
+	ide_end_request(drive, 0, 0);
+	return ide_stopped;
+}
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long);
 
 /*
  * do_rw_disk() issues READ and WRITE commands to a disk,
@@ -365,21 +544,24 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (!(rq->flags & REQ_CMD)) {
+	if (!blk_fs_request(rq)) {
 		blk_dump_rq_flags(rq, "do_rw_disk - bad command");
-		idedisk_end_request(drive, 0);
+		ide_end_request(drive, 0, 0);
 		return ide_stopped;
 	}
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
-		return promise_rw_disk(drive, rq, block);
-	}
+	/*
+	 * 268435455  == 137439 MB or 28bit limit
+	 *
+	 * need to add split taskfile operations based on 28bit threshold.
+	 */
+
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+        if (IS_PDC4030_DRIVE)
+                return promise_rw_disk(drive, rq, block);
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
-	if ((drive->id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1))		/* 48-bit LBA */
+	if (drive->addressing == 1)		/* 48-bit LBA */
 		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
 	if (drive->select.b.lba)		/* 28-bit LBA */
 		return lba_28_rw_disk(drive, rq, (unsigned long) block);
@@ -416,12 +598,15 @@
 {
 	ide_task_t		args;
 	int			sectors;
+	ata_nsector_t		nsectors;
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 	unsigned int track	= (block / drive->sect);
 	unsigned int sect	= (block % drive->sect) + 1;
 	unsigned int head	= (track % drive->head);
 	unsigned int cyl	= (track / drive->head);
 
+	nsectors.all = (u16) rq->nr_sectors;
+
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
 	printk("CHS=%d/%d/%d, ", cyl, head, sect);
@@ -449,8 +634,11 @@
 {
 	ide_task_t		args;
 	int			sectors;
+	ata_nsector_t		nsectors;
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
+	nsectors.all = (u16) rq->nr_sectors;
+
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
 	printk("LBAsect=%lld, ", block);
@@ -484,8 +672,11 @@
 {
 	ide_task_t		args;
 	int			sectors;
+	ata_nsector_t		nsectors;
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
+	nsectors.all = (u16) rq->nr_sectors;
+
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
 	printk("LBAsect=%lld, ", block);
@@ -514,189 +705,6 @@
 	return do_rw_taskfile(drive, &args);
 }
 
-#else /* !CONFIG_IDE_TASKFILE_IO */
-
-/*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
- */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "do_rw_disk - bad command");
-		return ide_stopped;
-	}
-
-	if (driver_blocked)
-		panic("Request while ide driver is blocked?");
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
-	if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-
-		if ((drive->id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task_ioreg_t tasklets[10];
-
-			tasklets[0] = 0;
-			tasklets[1] = 0;
-			tasklets[2] = rq->nr_sectors;
-			tasklets[3] = (rq->nr_sectors>>8);
-			if (rq->nr_sectors == 65536) {
-				tasklets[2] = 0x00;
-				tasklets[3] = 0x00;
-			}
-			tasklets[4] = (task_ioreg_t) block;
-			tasklets[5] = (task_ioreg_t) (block>>8);
-			tasklets[6] = (task_ioreg_t) (block>>16);
-			tasklets[7] = (task_ioreg_t) (block>>24);
-			tasklets[8] = (task_ioreg_t) 0;
-			tasklets[9] = (task_ioreg_t) 0;
-//			tasklets[8] = (task_ioreg_t) (block>>32);
-//			tasklets[9] = (task_ioreg_t) (block>>40);
-#ifdef DEBUG
-			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
-				drive->name,
-				(rq_data_dir(rq)==READ)?"read":"writ",
-				block,
-				rq->nr_sectors,
-				(unsigned long) rq->buffer,
-				block);
-			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
-				drive->name, tasklets[3], tasklets[2],
-				tasklets[9], tasklets[8], tasklets[7],
-				tasklets[6], tasklets[5], tasklets[4]);
-#endif
-			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
-
-			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
-			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
-		} else {
-#ifdef DEBUG
-			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
-				drive->name, (rq_data_dir(rq)==READ)?"read":"writ",
-				block, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
-			OUT_BYTE(0x00, IDE_FEATURE_REG);
-			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-			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 / drive->sect;
-		sect  = block % drive->sect + 1;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
-		head  = track % drive->head;
-		cyl   = track / drive->head;
-
-		OUT_BYTE(0x00, IDE_FEATURE_REG);
-		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-		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",
-			drive->name, (rq_data_dir(rq)==READ)?"read":"writ", cyl,
-			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
-#endif
-	}
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
-		return do_pdc4030_io (drive, rq);
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	if (rq_data_dir(rq) == READ) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		if (HWGROUP(drive)->handler != NULL)
-			BUG();
-		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		if ((drive->id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		}
-		return ide_started;
-	} else if (rq_data_dir(rq) == WRITE) {
-		ide_startstop_t startstop;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
-			return ide_started;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((drive->id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		}
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		if (!drive->unmask)
-			local_irq_disable();
-		if (drive->mult_count) {
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	/*
-	 * Ugh.. this part looks ugly because we MUST set up
-	 * the interrupt handler before outputting the first block
-	 * of data to be written.  If we hit an error (corrupted buffer list)
-	 * in ide_multwrite(), then we need to remove the handler/timer
-	 * before returning.  Fortunately, this NEVER happens (right?).
-	 *
-	 * Except when you get an error it seems...
-	 *
-	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
-	 */
-			hwgroup->wrq = *rq; /* scratchpad */
-			if (HWGROUP(drive)->handler != NULL)
-				BUG();
-			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
-			if (ide_multwrite(drive, drive->mult_count)) {
-				unsigned long flags;
-				spin_lock_irqsave(&ide_lock, flags);
-				hwgroup->handler = NULL;
-				del_timer(&hwgroup->timer);
-				spin_unlock_irqrestore(&ide_lock, flags);
-				return ide_stopped;
-			}
-		} else {
-			unsigned long flags;
-			char *buffer = ide_map_buffer(rq, &flags);
-			if (HWGROUP(drive)->handler != NULL)
-				BUG();
-			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
-			taskfile_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &flags);
-		}
-		return ide_started;
-	}
-	printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
-	idedisk_end_request(drive, 0);
-	return ide_stopped;
-}
-
 #endif /* CONFIG_IDE_TASKFILE_IO */
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -741,7 +749,8 @@
 
 static int idedisk_media_change (ide_drive_t *drive)
 {
-	return drive->removable;	/* if removable, always assume it was changed */
+	/* if removable, always assume it was changed */
+	return drive->removable;
 }
 
 static void idedisk_revalidate (ide_drive_t *drive)
@@ -749,39 +758,11 @@
 	ide_revalidate_drive(drive);
 }
 
-static int idedisk_end_request (ide_drive_t *drive, int uptodate)
-{
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
-		add_blkdev_randomness(major(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-		HWGROUP(drive)->rq = NULL;
-		end_that_request_last(rq);
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return ret;
-}
-
-static byte idedisk_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
 	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
@@ -802,48 +783,49 @@
 #endif	/* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
 		printk(" { ");
 		if (err & ABRT_ERR)	printk("DriveStatusError ");
-		if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+		if (err & ICRC_ERR)
+			printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
 		if (err & ECC_ERR)	printk("UncorrectableError ");
 		if (err & ID_ERR)	printk("SectorIdNotFound ");
 		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
 		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
 		printk("}");
-		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-			if ((drive->id->command_set_2 & 0x0400) &&
-			    (drive->id->cfs_enable_2 & 0x0400) &&
-			    (drive->addressing == 1)) {
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
 				__u64 sectors = 0;
 				u32 low = 0, high = 0;
 				low = idedisk_read_24(drive);
-				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
 				high = idedisk_read_24(drive);
 				sectors = ((__u64)high << 24) | low;
 				printk(", LBAsect=%llu, high=%d, low=%d",
 				       (unsigned long long) sectors,
 				       high, low);
 			} else {
-				byte cur = IN_BYTE(IDE_SELECT_REG);
+				u8 cur = hwif->INB(IDE_SELECT_REG);
 				if (cur & 0x40) {	/* using LBA? */
 					printk(", LBAsect=%ld", (unsigned long)
 					 ((cur&0xf)<<24)
-					 |(IN_BYTE(IDE_HCYL_REG)<<16)
-					 |(IN_BYTE(IDE_LCYL_REG)<<8)
-					 | IN_BYTE(IDE_SECTOR_REG));
+					 |(hwif->INB(IDE_HCYL_REG)<<16)
+					 |(hwif->INB(IDE_LCYL_REG)<<8)
+					 | hwif->INB(IDE_SECTOR_REG));
 				} else {
 					printk(", CHS=%d/%d/%d",
-					 (IN_BYTE(IDE_HCYL_REG)<<8) +
-					  IN_BYTE(IDE_LCYL_REG),
+					 (hwif->INB(IDE_HCYL_REG)<<8) +
+					  hwif->INB(IDE_LCYL_REG),
 					  cur & 0xf,
-					  IN_BYTE(IDE_SECTOR_REG));
+					  hwif->INB(IDE_SECTOR_REG));
 				}
 			}
 			if (HWGROUP(drive) && HWGROUP(drive)->rq)
-				printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+				printk(", sector=%ld",
+					HWGROUP(drive)->rq->sector);
 		}
 	}
 #endif	/* FANCY_STATUS_DUMPS */
@@ -852,16 +834,19 @@
 	return err;
 }
 
-ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
 	err = idedisk_dump_status(drive, msg, stat);
 
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
 	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
 		rq->errors = 1;
@@ -883,17 +868,18 @@
 		if (err == ABRT_ERR) {
 			if (drive->select.b.lba &&
 			    /* some newer drives don't support WIN_SPECIFY */
-			    IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)
 				return ide_stopped;
-		} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
+		} else if ((err & BAD_CRC) == BAD_CRC) {
 			/* UDMA crc error, just retry the operation */
 			drive->crc_count++;
-		} else if (err & (BBD_ERR | ECC_ERR))
+		} else if (err & (BBD_ERR | ECC_ERR)) {
 			/* retries won't help these */
 			rq->errors = ERROR_MAX;
-		else if (err & TRK0_ERR)
+		} else if (err & TRK0_ERR) {
 			/* help it find track zero */
 			rq->errors |= ERROR_RECAL;
+		}
 	}
 	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
 		/*
@@ -908,14 +894,15 @@
 			u32 buffer[16];
 			unsigned int wcount = (i > 16) ? 16 : i;
 			i -= wcount;
-			ata_input_data(drive, buffer, wcount);
+			taskfile_input_data(drive, buffer, wcount);
 		}
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
 		/* force an abort */
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX)
-		DRIVER(drive)->end_request(drive, 0);
+		DRIVER(drive)->end_request(drive, 0, 0);
 	else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -937,12 +924,6 @@
 	ide_task_t args;
 	unsigned long addr = 0;
 
-#if 0
-	if (!(drive->id->command_set_1 & 0x0400) &&
-	    !(drive->id->cfs_enable_2 & 0x0100))
-		return addr;
-#endif
-
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
@@ -1099,9 +1080,9 @@
 
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
-		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->head		= drive->bios_head = 255;
 		drive->sect		= drive->bios_sect = 63;
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->select.b.lba	= 1;
 		set_max_ext = idedisk_read_native_max_address_ext(drive);
 		if (set_max_ext > capacity_2) {
@@ -1115,7 +1096,7 @@
 				drive->id->lba_capacity_2 = capacity_2;
                         }
 #else /* !CONFIG_IDEDISK_STROKE */
-			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+			printk(KERN_INFO "%s: setmax_ext LBA %llu, native  %llu\n",
 				drive->name, set_max_ext, capacity_2);
 #endif /* CONFIG_IDEDISK_STROKE */
 		}
@@ -1142,7 +1123,7 @@
 			drive->id->lba_capacity = capacity;
 		}
 #else /* !CONFIG_IDEDISK_STROKE */
-		printk("%s: setmax LBA %lu, native  %lu\n",
+		printk(KERN_INFO "%s: setmax LBA %lu, native  %lu\n",
 			drive->name, set_max, capacity);
 #endif /* CONFIG_IDEDISK_STROKE */
 	}
@@ -1243,7 +1224,7 @@
 	return ide_raw_taskfile(drive, &args, NULL);
 }
 
-static int get_smart_values(ide_drive_t *drive, byte *buf)
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
 {
 	ide_task_t args;
 
@@ -1258,7 +1239,7 @@
 	return ide_raw_taskfile(drive, &args, buf);
 }
 
-static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+static int get_smart_thresholds(ide_drive_t *drive, u8 *buf)
 {
 	ide_task_t args;
 	memset(&args, 0, sizeof(ide_task_t));
@@ -1387,7 +1368,7 @@
 static int call_idedisk_standby (ide_drive_t *drive, int arg)
 {
 	ide_task_t args;
-	byte standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
+	u8 standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_COMMAND_OFFSET]	= standby;
 	args.command_type			= ide_cmd_type_parser(&args);
@@ -1402,7 +1383,7 @@
 static int call_idedisk_suspend (ide_drive_t *drive, int arg)
 {
 	ide_task_t args;
-	byte suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
+	u8 suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_COMMAND_OFFSET]	= suspend;
 	args.command_type			= ide_cmd_type_parser(&args);
@@ -1421,7 +1402,7 @@
 static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
 {
 	ide_task_t args;
-	byte ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
+	u8 ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_COMMAND_OFFSET]	= ckpw;
 	args.command_type			= ide_cmd_type_parser(&args);
@@ -1514,10 +1495,33 @@
  	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
+static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
+		struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+HDIO_GET_ADDRESS
+HDIO_SET_ADDRESS
+HDIO_GET_WCACHE
+HDIO_SET_WCACHE
+HDIO_GET_ACOUSTIC
+HDIO_SET_ACOUSTIC
+HDIO_GET_MULTCOUNT
+HDIO_SET_MULTCOUNT
+HDIO_GET_NOWERR
+HDIO_SET_NOWERR
+#endif
+	return -EINVAL;
+}
+
 static void idedisk_setup (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity;
+
+#if 0
+	if (IS_PDC4030_DRIVE)
+		DRIVER(drive)->do_request = promise_rw_disk;
+#endif
 	
 	idedisk_add_settings(drive);
 
@@ -1528,7 +1532,7 @@
 	 * CompactFlash cards and their brethern look just like hard drives
 	 * to us, but they are removable and don't have a doorlock mechanism.
 	 */
-	if (drive->removable && !drive_is_flashcard(drive)) {
+	if (drive->removable && !(drive->is_flash)) {
 		/*
 		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
 		 */
@@ -1592,7 +1596,7 @@
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -1629,7 +1633,7 @@
 	return 0;
 }
 
-static int idedisk_reinit(ide_drive_t *drive);
+static int idedisk_attach(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
@@ -1648,10 +1652,10 @@
 	resume:			do_idedisk_resume,
 	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
-	end_request:		idedisk_end_request,
+	end_request:		NULL,
 	sense:			idedisk_dump_status,
 	error:			idedisk_error,
-	ioctl:			NULL,
+	ioctl:			idedisk_ioctl,
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
@@ -1660,7 +1664,7 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	reinit:			idedisk_reinit,
+	attach:			idedisk_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 	drives:			LIST_HEAD_INIT(idedisk_driver.drives),
@@ -1668,7 +1672,7 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-static int idedisk_reinit(ide_drive_t *drive)
+static int idedisk_attach(ide_drive_t *drive)
 {
 	struct gendisk *g = drive->disk;
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Sun Sep 15 19:19:46 2002
+++ b/drivers/ide/ide-dma.c	Sun Sep 15 19:19:46 2002
@@ -70,14 +70,13 @@
  *
  * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
  *
- * check_drive_lists(ide_drive_t *drive, int good_bad)
- *
  * ATA-66/100 and recovery functions, I forgot the rest......
- * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
  *
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -86,21 +85,11 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed.  Oh the things we forget.  I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
 #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 struct drive_list_entry {
@@ -205,19 +194,15 @@
  */
 ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
-	int i;
-	byte stat, dma_stat;
+	u8 stat = 0, dma_stat = 0;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				DRIVER(drive)->end_request(drive, 1);
-			}
+
+			DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
 			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
@@ -251,7 +236,7 @@
 	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
 	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
+	u8 *virt_addr = rq->buffer;
 	int sector_count = rq->nr_sectors;
 
 	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
@@ -297,27 +282,24 @@
  * Returns 0 if all went okay, returns 1 otherwise.
  * May also be invoked from trm290.c
  */
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
+int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
 {
-	unsigned int *table = HWIF(drive)->dmatable_cpu;
-#ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
-#else
-	const int is_trm290_chipset = 0;
-#endif
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned int *table	= hwif->dmatable_cpu;
+	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
 	unsigned int count = 0;
 	int i;
 	struct scatterlist *sg;
 
 	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
-		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(drive, HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_raw_build_sglist(drive, rq);
 	else
-		HWIF(drive)->sg_nents = i = ide_build_sglist(drive, HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_build_sglist(drive, rq);
 
 	if (!i)
 		return 0;
 
-	sg = HWIF(drive)->sg_table;
+	sg = hwif->sg_table;
 	while (i) {
 		u32 cur_addr;
 		u32 cur_len;
@@ -342,14 +324,14 @@
 					bcount = cur_len;
 				*table++ = cpu_to_le32(cur_addr);
 				xcount = bcount & 0xffff;
-				if (is_trm290_chipset)
+				if (is_trm290)
 					xcount = ((xcount >> 2) - 1) << 16;
 				if (xcount == 0x0000) {
-					/* 
-					 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
-					 * but at least one (e.g. CS5530) misinterprets it as zero (!).
-					 * So here we break the 64KB entry into two 32KB entries instead.
-					 */
+	/* 
+	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+	 * but at least one (e.g. CS5530) misinterprets it as zero (!).
+	 * So here we break the 64KB entry into two 32KB entries instead.
+	 */
 					if (count++ >= PRD_ENTRIES) {
 						printk("%s: DMA table too small\n", drive->name);
 						goto use_pio_instead;
@@ -369,17 +351,17 @@
 	}
 
 	if (count) {
-		if (!is_trm290_chipset)
+		if (!is_trm290)
 			*--table |= cpu_to_le32(0x80000000);
 		return count;
 	}
 	printk("%s: empty DMA table?\n", drive->name);
 use_pio_instead:
-	pci_unmap_sg(HWIF(drive)->pci_dev,
-		     HWIF(drive)->sg_table,
-		     HWIF(drive)->sg_nents,
-		     HWIF(drive)->sg_dma_direction);
-	HWIF(drive)->sg_dma_active = 0;
+	pci_unmap_sg(hwif->pci_dev,
+		     hwif->sg_table,
+		     hwif->sg_nents,
+		     hwif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
 	return 0; /* revert to PIO for this request */
 }
 
@@ -394,86 +376,6 @@
 	HWIF(drive)->sg_dma_active = 0;
 }
 
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-int check_drive_lists (ide_drive_t *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	const char **list;
-
-	if (good_bad) {
-		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
-	}
-#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	return 0;
-}
-
-int report_drive_dmaing (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
-		if ((id->dma_ultra >> 15) & 1) {
-			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-		if ((id->dma_ultra >> 13) & 1) {
-			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4) {
-		printk(", (U)DMA");	/* Can be BIOS-enabled! */
-	} else {
-		printk(", DMA");
-	}
-	return 1;
-}
-
 static int config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -481,291 +383,443 @@
 
 	if (id && (id->capability & 1) && hwif->autodma) {
 		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive))
-			return hwif->dmaproc(ide_dma_off, drive);
+		if (hwif->ide_dma_bad_drive(drive))
+			return hwif->ide_dma_off(drive);
 
-		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		/*
+		 * Enable DMA on any drive that has
+		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+		 */
+		if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+			return hwif->ide_dma_on(drive);
+		/*
+		 * Enable DMA on any drive that has mode2 DMA
+		 * (multi or single) enabled
+		 */
 		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
+			if ((id->dma_mword & 0x404) == 0x404 ||
+			    (id->dma_1word & 0x404) == 0x404)
+				return hwif->ide_dma_on(drive);
+
 		/* Consult the list of known "good" drives */
-		if (ide_dmaproc(ide_dma_good_drive, drive))
-			return hwif->dmaproc(ide_dma_on, drive);
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+//	if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
+	return hwif->ide_dma_off_quietly(drive);
 }
 
-#ifndef __IDEDMA_TIMEOUT
 /*
  * 1 dmaing, 2 error, 4 intr
  */
 static int dma_timer_expiry (ide_drive_t *drive)
 {
-	byte dma_stat = IN_BYTE(HWIF(drive)->dma_base+2);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif /* DEBUG */
+	printk("%s: dma_timer_expiry: dma status == 0x%02x\n",
+		drive->name, dma_stat);
+
+	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
+		return WAIT_CMD;
 
-#if 0
 	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
-#endif
 
 	if (dma_stat & 2) {	/* ERROR */
-		byte stat = GET_STAT();
-		return DRIVER(drive)->error(drive, "dma_timer_expiry", stat);
+		(void) hwif->ide_dma_end(drive);
+		return DRIVER(drive)->error(drive,
+			"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
 	}
 	if (dma_stat & 1)	/* DMAing */
 		return WAIT_CMD;
+
+	if (dma_stat & 4)	/* Got an Interrupt */
+		HWGROUP(drive)->handler(drive);
+
 	return 0;
 }
-#else /* __IDEDMA_TIMEOUT */
-static int ide_dma_timeout_recovery (ide_drive_t *drive)
+
+static void ide_toggle_bounce(ide_drive_t *drive, int on)
 {
-	struct request *rq	= HWGROUP(drive)->rq;
-	int enable_dma		= drive->using_dma;
-	int speed		= drive->current_speed;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	HWGROUP(drive)->handler	= NULL;
-	del_timer(&HWGROUP(drive)->timer);
-	HWGROUP(drive)->expiry	= NULL;
-	HWGROUP(drive)->rq	= NULL;
-	spin_unlock_irqrestore(&ide_lock, flags);
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
 
-	(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	drive->waiting_for_dma = 0;
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
 
-	(void) ide_do_reset(drive);
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
 
-	if (!(drive_is_ready(drive))) {
-		/* FIXME: Replace hard-coded 100, error handling? */
-		int i;
-		for (i=0; i<100; i++) {
-			if (drive_is_ready(drive))
-				break;
-		}
-	}
+int __ide_dma_host_off (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	if ((HWIF(drive)->speedproc) != NULL) {
-		HWIF(drive)->speedproc(drive, speed);
-		drive->current_speed = speed;
-	}
+	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	return 0;
+}
 
-	if ((enable_dma) && !(drive->using_dma))
-		(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
+EXPORT_SYMBOL(__ide_dma_host_off);
 
-	return restart_request(drive, rq);
+int __ide_dma_off_quietly (ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	ide_toggle_bounce(drive, 0);
+	return HWIF(drive)->ide_dma_host_off(drive);
 }
-#endif /* __IDEDMA_TIMEOUT */
 
-static void ide_toggle_bounce(ide_drive_t *drive, int on)
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+
+int __ide_dma_off (ide_drive_t *drive)
 {
-	u64 addr = BLK_BOUNCE_HIGH;
+	printk("%s: DMA disabled\n", drive->name);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
 
-	if (on && drive->media == ide_disk && !HWIF(drive)->no_highmem) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+EXPORT_SYMBOL(__ide_dma_off);
+
+int __ide_dma_host_on (ide_drive_t *drive)
+{
+	if (drive->using_dma) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u8 unit			= (drive->select.b.unit & 0x01);
+		u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+		return 0;
 	}
+	return 1;
+}
 
-	blk_queue_bounce_limit(&drive->queue, addr);
+EXPORT_SYMBOL(__ide_dma_host_on);
+
+int __ide_dma_on (ide_drive_t *drive)
+{
+	drive->using_dma = 1;
+	ide_toggle_bounce(drive, 1);
+	return HWIF(drive)->ide_dma_host_on(drive);
 }
 
-/*
- * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * ide_dma_begin afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- * May also be invoked from trm290.c
- */
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+EXPORT_SYMBOL(__ide_dma_on);
+
+int __ide_dma_check (ide_drive_t *drive)
+{
+	return config_drive_for_dma(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_check);
+
+int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
 {
-	ide_hwif_t *hwif		= HWIF(drive);
-//	ide_task_t *args		= HWGROUP(drive)->rq->special;
-	unsigned long dma_base		= hwif->dma_base;
-	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading	= 0;
-	unsigned int set_high		= 1;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_off:
-			printk("%s: DMA disabled\n", drive->name);
-		case ide_dma_off_quietly:
-		case ide_dma_host_off:
-			OUT_BYTE(IN_BYTE(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-			if (func == ide_dma_host_off)
-				return 0;
-			set_high = 0;
-		case ide_dma_on:
-			drive->using_dma = (func == ide_dma_on);
-			if (!drive->using_dma)
-				return 0;
-		case ide_dma_host_on:
-			if (drive->using_dma)
-				OUT_BYTE(IN_BYTE(dma_base+2)|(1<<(5+unit)), dma_base+2);
-			ide_toggle_bounce(drive, set_high);
-			return 0;
-		case ide_dma_check:
-			return config_drive_for_dma (drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			SELECT_READ_WRITE(hwif,drive,func);
-			if (!(count = ide_build_dmatable(drive, func)))
-				/* try PIO instead of DMA */
-				return 1;
-			/* PRD table */
-			outl(hwif->dmatable_dma, dma_base + 4);
-			/* specify r/w */
-			OUT_BYTE(reading, dma_base);
-			/* clear INTR & ERROR flags */
-			OUT_BYTE(IN_BYTE(dma_base+2)|6, dma_base+2);
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			/* paranoia check */
-			if (HWGROUP(drive)->handler != NULL)
-				BUG();
-#ifndef __IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
-#else /* __IDEDMA_TIMEOUT */
-			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);
-#endif /* __IDEDMA_TIMEOUT */
-			/* issue cmd to drive */
-			/*
-			 * FIX ME to use only ACB ide_task_t args Struct
-			 */
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 1 << 3;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
 #if 0
-		{
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		}
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #else
-			if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing == 1)
-				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-			else
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-#endif
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			/* start DMA */
-			OUT_BYTE(IN_BYTE(dma_base)|1, dma_base);
-			return 0;
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
-			/* get DMA status */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* clear the INTR & ERROR bits */
-			OUT_BYTE(dma_stat|6, dma_base+2);
-			/* purge DMA mappings */
-			ide_destroy_dmatable(drive);
-			/* verify good DMA status */
-			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
-		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-#if 0  /* do not set unless you know what you are doing */
-			if (dma_stat & 4) {
-				byte stat = GET_STAT();
-				OUT_BYTE(dma_base+2, dma_stat & 0xE4);
-			}
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #endif
-			/* return 1 if INTR asserted */
-			return (dma_stat & 4) == 4;
-		case ide_dma_bad_drive:
-		case ide_dma_good_drive:
-			return check_drive_lists(drive, (func == ide_dma_good_drive));
-		case ide_dma_verbose:
-			return report_drive_dmaing(drive);
-		case ide_dma_timeout:
-	// FIXME: Many IDE chipsets do not permit command file register access
-	// FIXME: while the bus-master function is still active.
-	// FIXME: To prevent deadlock with those chipsets, we must be extremely
-	// FIXME: careful here (and in ide_intr() as well) to NOT access any
-	// FIXME: registers from the 0x1Fx/0x17x sets before terminating the
-	// FIXME: bus-master operation via the bus-master control reg.
-	// FIXME: Otherwise, chipset deadlock will occur, and some systems will
-	// FIXME: lock up completely!!
-#ifdef __IDEDMA_TIMEOUT
-			/*
-			 * Have to issue an abort and requeue the request
-			 * DMA engine got turned off by a goofy ASIC, and
-			 * we have to clean up the mess, and here is as good
-			 * as any.  Do it globally for all chipsets.
-			 */
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_read);
+
+int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 0;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
 #if 0
-			dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #else
-			drive->waiting_for_dma = 0;
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(dma_base)&~1, dma_base);
-//			OUT_BYTE(0x00, dma_base);
-			/* get DMA status */
-			dma_stat = IN_BYTE(dma_base+2);
-			/* clear the INTR & ERROR bits */
-			OUT_BYTE(dma_stat|6, dma_base+2);
-			/* purge DMA mappings */
-			ide_destroy_dmatable(drive);
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #endif
-			printk("%s: %s: Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			if (dma_stat & 0xF0)
-				return ide_dma_timeout_recovery(drive);
-#endif /* __IDEDMA_TIMEOUT */
-		case ide_dma_retune:
-		case ide_dma_lostirq:
-			printk("ide_dmaproc: chipset supported %s "
-				"func only: %d\n",
-				ide_dmafunc_verbose(func),  func);
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_write);
+
+int __ide_dma_begin (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+	/* Note that this is done *after* the cmd has
+	 * been issued to the drive, as per the BM-IDE spec.
+	 * The Promise Ultra33 doesn't work correctly when
+	 * we do this part before issuing the drive cmd.
+	 */
+	/* start DMA */
+	hwif->OUTB(dma_cmd|1, hwif->dma_command);
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_begin);
+
+/* returns 1 on error, 0 otherwise */
+int __ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	/* get dma_command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd&~1, hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_end);
+
+/* returns 1 if dma irq issued, 0 otherwise */
+int __ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+#if 0  /* do not set unless you know what you are doing */
+	if (dma_stat & 4) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+	}
+#endif
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+			drive->name, __FUNCTION__);
+	drive->waiting_for_dma++;
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_test_irq);
+
+int __ide_dma_bad_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist) {
+		printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "bad" drives */
+	list = bad_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model)) {
+			printk("%s: Disabling (U)DMA for %s\n",
+				drive->name, id->model);
 			return 1;
-		default:
-			printk("ide_dmaproc: unsupported %s func: %d\n",
-				ide_dmafunc_verbose(func), func);
+		}
+	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+int __ide_dma_good_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	return in_drive_list(id, drive_whitelist);
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "good" drives */
+	list = good_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model))
 			return 1;
 	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_good_drive);
+
+/*
+ * Used for HOST FIFO counters for VDMA
+ * PIO over DMA, effective ATA-Bridge operator.
+ */
+int __ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_count);
+
+int __ide_dma_verbose (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (id->field_valid & 4) {
+		if ((id->dma_ultra >> 8) && (id->dma_mword >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
+			if (((id->dma_ultra >> 11) & 0x1F) &&
+			    eighty_ninty_three(drive)) {
+				if ((id->dma_ultra >> 15) & 1) {
+					printk(", UDMA(mode 7)");
+				} else if ((id->dma_ultra >> 14) & 1) {
+					printk(", UDMA(133)");
+				} else if ((id->dma_ultra >> 13) & 1) {
+					printk(", UDMA(100)");
+				} else if ((id->dma_ultra >> 12) & 1) {
+					printk(", UDMA(66)");
+				} else if ((id->dma_ultra >> 11) & 1) {
+					printk(", UDMA(44)");
+				} else
+					goto mode_two;
+			} else {
+		mode_two:
+				if ((id->dma_ultra >> 10) & 1) {
+					printk(", UDMA(33)");
+				} else if ((id->dma_ultra >> 9) & 1) {
+					printk(", UDMA(25)");
+				} else if ((id->dma_ultra >> 8) & 1) {
+					printk(", UDMA(16)");
+				}
+			}
+		} else {
+			printk(", (U)DMA");	/* Can be BIOS-enabled! */
+		}
+	} else if (id->field_valid & 2) {
+		if ((id->dma_mword >> 8) && (id->dma_1word >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		printk(", DMA");
+	} else if (id->field_valid & 1) {
+		printk(", BUG");
+	}
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_verbose);
+
+int __ide_dma_retune (ide_drive_t *drive)
+{
+	printk("%s: chipset supported call only\n", __FUNCTION__);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_retune);
+
+int __ide_dma_lostirq (ide_drive_t *drive)
+{
+	printk("%s: DMA interrupt recovery\n", drive->name);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_lostirq);
+
+int __ide_dma_timeout (ide_drive_t *drive)
+{
+	printk("%s: timeout waiting for DMA\n", drive->name);
+	if (HWIF(drive)->ide_dma_test_irq(drive))
+		return 0;
+
+	return HWIF(drive)->ide_dma_end(drive);
 }
 
+EXPORT_SYMBOL(__ide_dma_timeout);
+
 /*
  * Needed for allowing full modular support of ide-driver
  */
-int ide_release_dma (ide_hwif_t *hwif)
+int ide_release_dma_engine (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
 		pci_free_consistent(hwif->pci_dev,
@@ -778,129 +832,191 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
+	return 1;
+}
+
+int ide_release_mmio_dma (ide_hwif_t *hwif)
+{
+	if ((hwif->dma_extra) && (hwif->channel == 0))
+		release_mem_region((hwif->dma_base + 16), hwif->dma_extra);
+	release_mem_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_mem_region(hwif->dma_base, 8);
+	return 1;
+}
+
+int ide_release_iomio_dma (ide_hwif_t *hwif)
+{
 	if ((hwif->dma_extra) && (hwif->channel == 0))
 		release_region((hwif->dma_base + 16), hwif->dma_extra);
 	release_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_region(hwif->dma_base, 8);
 	return 1;
 }
 
 /*
- * This can be called for a dynamically installed interface. Don't __init it
+ * Needed for allowing full modular support of ide-driver
  */
- 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+int ide_release_dma (ide_hwif_t *hwif)
+{
+	if (hwif->chipset == ide_etrax100)
+		return 1;
+
+	ide_release_dma_engine(hwif);
+	if (hwif->mmio)
+		return ide_release_mmio_dma(hwif);
+	return ide_release_iomio_dma(hwif);
+}
+
+int ide_allocate_dma_engine (ide_hwif_t *hwif)
 {
-	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
-	if (check_region(dma_base, num_ports)) {
-		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
-		return;
-	}
-	request_region(dma_base, num_ports, hwif->name);
-	hwif->dma_base = dma_base;
 	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
 						  PRD_ENTRIES * PRD_BYTES,
 						  &hwif->dmatable_dma);
-	if (hwif->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
-
 	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (hwif->sg_table == NULL) {
-		pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
-		goto dma_alloc_failure;
-	}
+				GFP_KERNEL);
 
-	hwif->dmaproc = &ide_dmaproc;
+	if ((hwif->dmatable_cpu) && (hwif->sg_table))
+		return 0;
 
-	if (hwif->chipset != ide_trm290) {
-		byte dma_stat = IN_BYTE(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	printk("%s: -- Error, unable to allocate%s%s table(s).\n",
+		(hwif->dmatable_cpu == NULL) ? " CPU" : "",
+		(hwif->sg_table == NULL) ?  " SG DMA" : " DMA",
+		hwif->cds->name);
+
+	ide_release_dma_engine(hwif);
+	return 1;
+}
+
+int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk("    %s: MMIO-DMA at 0x%08lx-0x%08lx",
+		hwif->name, base, base + ports - 1);
+	if (check_mem_region(base, ports)) {
+		printk(" -- Error, MMIO ports already in use.\n");
+		return 1;
+	}
+	request_mem_region(base, ports, hwif->name);
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!check_mem_region(hwif->dma_base2, ports))
+			request_mem_region(hwif->dma_base2, ports, hwif->name);
 	}
-	printk("\n");
-	return;
+	return 0;
+}
 
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+int ide_iomio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk("    %s: BM-DMA at 0x%04lx-0x%04lx",
+		hwif->name, base, base + ports - 1);
+	if (!request_region(base, ports, hwif->name)) {
+		printk(" -- Error, ports in use.\n");
+		return 1;
+	}
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!request_region(hwif->dma_base2, ports, hwif->name))
+		{
+			printk(" -- Error, secondary ports in use.\n");
+			release_region(base, ports);
+			return 1;
+		}
+	}
+	return 0;
 }
 
 /*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ * 
  */
-unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
+int ide_dma_iobase (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
 {
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
+	if (hwif->mmio)
+		return ide_mmio_dma(hwif, base, ports);
+	return ide_iomio_dma(hwif, base, ports);
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (hwif->mate && hwif->mate->dma_base) {
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-	} else {
-		dma_base = pci_resource_start(dev, 4);
-		if (!dma_base) {
-			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
-			dma_base = 0;
-		}
-	}
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+	if (ide_dma_iobase(hwif, dma_base, num_ports))
+		return;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	if ((!dma_base) && (!second_chance)) {
-		unsigned long set_bmiba = 0;
-		second_chance++;
-		switch(dev->vendor) {
-			case PCI_VENDOR_ID_AL:
-				set_bmiba = DEFAULT_BMALIBA; break;
-			case PCI_VENDOR_ID_VIA:
-				set_bmiba = DEFAULT_BMCRBA; break;
-			case PCI_VENDOR_ID_INTEL:
-				set_bmiba = DEFAULT_BMIBA; break;
-			default:
-				return dma_base;
-		}
-		pci_write_config_dword(dev, 0x20, set_bmiba|1);
-		goto second_chance_to_dma;
+	if (ide_allocate_dma_engine(hwif)) {
+		ide_release_dma(hwif);
+		return;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
 
-	if (dma_base) {
-		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
-			request_region(dma_base+16, extra, name);
-		dma_base += hwif->channel ? 8 : 0;
-		hwif->dma_extra = extra;
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AMD_VIPER_7409:
-			case PCI_DEVICE_ID_CMD_643:
-			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-				OUT_BYTE(IN_BYTE(dma_base+2) & 0x60, dma_base+2);
-				if (IN_BYTE(dma_base+2) & 0x80) {
-					printk("%s: simplex device: DMA forced\n", name);
-				}
-				break;
-			default:
-				/*
-				 * If the device claims "simplex" DMA,
-				 * this means only one of the two interfaces
-				 * can be trusted with DMA at any point in time.
-				 * So we should enable DMA only on one of the
-				 * two interfaces.
-				 */
-				if ((IN_BYTE(dma_base+2) & 0x80)) {	/* simplex device? */
-					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					    (hwif->mate && hwif->mate->dma_base)) {
-						printk("%s: simplex device:  DMA disabled\n", name);
-						dma_base = 0;
-					}
-				}
-		}
+	if (!(hwif->dma_command))
+		hwif->dma_command	= hwif->dma_base;
+	if (!(hwif->dma_vendor1))
+		hwif->dma_vendor1	= (hwif->dma_base + 1);
+	if (!(hwif->dma_status))
+		hwif->dma_status	= (hwif->dma_base + 2);
+	if (!(hwif->dma_vendor3))
+		hwif->dma_vendor3	= (hwif->dma_base + 3);
+	if (!(hwif->dma_prdtable))
+		hwif->dma_prdtable	= (hwif->dma_base + 4);
+
+	if (!hwif->ide_dma_off)
+		hwif->ide_dma_off = &__ide_dma_off;
+	if (!hwif->ide_dma_off_quietly)
+		hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+	if (!hwif->ide_dma_host_off)
+		hwif->ide_dma_host_off = &__ide_dma_host_off;
+	if (!hwif->ide_dma_on)
+		hwif->ide_dma_on = &__ide_dma_on;
+	if (!hwif->ide_dma_host_on)
+		hwif->ide_dma_host_on = &__ide_dma_host_on;
+	if (!hwif->ide_dma_check)
+		hwif->ide_dma_check = &__ide_dma_check;
+	if (!hwif->ide_dma_read)
+		hwif->ide_dma_read = &__ide_dma_read;
+	if (!hwif->ide_dma_write)
+		hwif->ide_dma_write = &__ide_dma_write;
+	if (!hwif->ide_dma_count)
+		hwif->ide_dma_count = &__ide_dma_count;
+	if (!hwif->ide_dma_begin)
+		hwif->ide_dma_begin = &__ide_dma_begin;
+	if (!hwif->ide_dma_end)
+		hwif->ide_dma_end = &__ide_dma_end;
+	if (!hwif->ide_dma_test_irq)
+		hwif->ide_dma_test_irq = &__ide_dma_test_irq;
+	if (!hwif->ide_dma_bad_drive)
+		hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
+	if (!hwif->ide_dma_good_drive)
+		hwif->ide_dma_good_drive = &__ide_dma_good_drive;
+	if (!hwif->ide_dma_verbose)
+		hwif->ide_dma_verbose = &__ide_dma_verbose;
+	if (!hwif->ide_dma_timeout)
+		hwif->ide_dma_timeout = &__ide_dma_timeout;
+	if (!hwif->ide_dma_retune)
+		hwif->ide_dma_retune = &__ide_dma_retune;
+	if (!hwif->ide_dma_lostirq)
+		hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+	if (hwif->chipset != ide_trm290) {
+		u8 dma_stat = hwif->INB(hwif->dma_status);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 	}
-	return dma_base;
+	printk("\n");
+
+	if (!(hwif->dma_master))
+		BUG();
 }
+
+
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Sun Sep 15 19:19:46 2002
+++ b/drivers/ide/ide-floppy.c	Sun Sep 15 19:19:46 2002
@@ -153,10 +153,10 @@
 	char *b_data;				/* Pointer which runs on the buffers */
 	int b_count;				/* Missing/Available data on the current buffer */
 	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idefloppy_pc_t;
 
@@ -272,29 +272,41 @@
 typedef struct {
 	ide_drive_t *drive;
 
-	idefloppy_pc_t *pc;			/* Current packet command */
-	idefloppy_pc_t *failed_pc; 		/* Last failed packet command */
-	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idefloppy_pc_t *pc;
+	/* Last failed packet command */
+	idefloppy_pc_t *failed_pc;
+	/* Packet command stack */
+	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDEFLOPPY_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
-	byte ticks;		/* delay this long before sending packet command */
+	u8 sense_key, asc, ascq;
+	/* delay this long before sending packet command */
+	u8 ticks;
 	int progress_indication;
 
 	/*
 	 *	Device information
 	 */
-	int blocks, block_size, bs_factor;			/* Current format */
-	idefloppy_capacity_descriptor_t capacity;		/* Last format capacity */
-	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
-	int wp;							/* Write protect */
-	int srfp;			/* Supports format progress report */
-	unsigned long flags;			/* Status/Action flags */
+	/* Current format */
+	int blocks, block_size, bs_factor;
+	/* Last format capacity */
+	idefloppy_capacity_descriptor_t capacity;
+	/* Copy of the flexible disk page */
+	idefloppy_flexible_disk_page_t flexible_disk_page;
+	/* Write protect */
+	int wp;
+	/* Supports format progress report */
+	int srfp;
+	/* Status/Action flags */
+	unsigned long flags;
 } idefloppy_floppy_t;
 
 #define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
@@ -350,20 +362,20 @@
 /*
  *	Special requests for our block device strategy routine.
  */
-#define	IDEFLOPPY_FIRST_RQ		90
+#define	IDEFLOPPY_FIRST_RQ	90
 
 /*
  * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
  */
-#define	IDEFLOPPY_PC_RQ			90
+#define	IDEFLOPPY_PC_RQ		90
 
-#define IDEFLOPPY_LAST_RQ		90
+#define IDEFLOPPY_LAST_RQ	90
 
 /*
  *	A macro which can be used to check if a given request command
  *	originated in the driver or in the buffer cache layer.
  */
-#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
 
 #endif
 
@@ -374,170 +386,6 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bsy		:1;	/* The device has access to the command block */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned check		:1;	/* Error occurred */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned ili		:1;	/* Illegal Length Indication */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA or PIO */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	:6;	/* Reserved */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_ireason_reg_t;
-
-/*
- *	ATAPI floppy Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned sam_lun	:3;	/* Logical unit number */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned one7		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned sam_lun	:3;	/* Logical unit number */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved4567	:4;	/* Reserved */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned zero0		:1;	/* Should be set to zero */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_control_reg_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -671,63 +519,32 @@
 static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE(IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 #if IDEFLOPPY_DEBUG_BUGS
 static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE(0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
 
-static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
-{
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
-
-	BUG_ON(!(rq->flags & REQ_STARTED));
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
-		add_blkdev_randomness(major(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-		HWGROUP(drive)->rq = NULL;
-		end_that_request_last(rq);
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return ret;
-}
-
 /*
  *	idefloppy_do_end_request is used to finish servicing a request.
  *
  *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
+static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_end_request\n");
+	printk(KERN_INFO "Reached idefloppy_end_request\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -742,12 +559,12 @@
 		return 0;
 	if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
 		/* our real local end request function */
-		idefloppy_end_request(drive, uptodate);
+		ide_end_request(drive, uptodate, nsecs);
 		return 0;
 	}
 	rq->errors = error;
 	/* fixme: need to move this local also */
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	return 0;
 }
 
@@ -761,18 +578,21 @@
 		if (pc->b_count == bio->bi_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_do_end_request(drive, 1);
+			idefloppy_do_end_request(drive, 1, 0);
 			if ((bio = rq->bio) != NULL)
 				pc->b_count = 0;
 		}
 		if (bio == NULL) {
-			printk (KERN_ERR "%s: bio == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
+			printk(KERN_ERR "%s: bio == NULL in "
+				"idefloppy_input_buffers, bcount == %d\n",
+				drive->name, bcount);
 			idefloppy_discard_data(drive, bcount);
 			return;
 		}
 		count = IDEFLOPPY_MIN(bio->bi_size - pc->b_count, bcount);
 		atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		bcount -= count;
+		pc->b_count += count;
 	}
 }
 
@@ -786,20 +606,24 @@
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_do_end_request(drive, 1);
+			idefloppy_do_end_request(drive, 1, 0);
 			if ((bio = rq->bio) != NULL) {
 				pc->b_data = bio_data(bio);
 				pc->b_count = bio->bi_size;
 			}
 		}
 		if (bio == NULL) {
-			printk (KERN_ERR "%s: bio == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
-			idefloppy_write_zeros (drive, bcount);
+			printk(KERN_ERR "%s: bio == NULL in "
+				"idefloppy_output_buffers, bcount == %d\n",
+				drive->name, bcount);
+			idefloppy_write_zeros(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		count = IDEFLOPPY_MIN(pc->b_count, bcount);
+		atapi_output_bytes(drive, pc->b_data, count);
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 	}
 }
 
@@ -810,7 +634,7 @@
 	struct bio *bio = rq->bio;
 
 	while ((bio = rq->bio) != NULL)
-		idefloppy_do_end_request(drive, 1);
+		idefloppy_do_end_request(drive, 1, 0);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -821,17 +645,17 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->flags = REQ_SPECIAL;	//rq->cmd = IDEFLOPPY_PC_RQ;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->pc_stack_index==IDEFLOPPY_PC_STACK)
+	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
 		floppy->pc_stack_index=0;
 	return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
@@ -840,8 +664,8 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->rq_stack_index==IDEFLOPPY_PC_STACK)
-		floppy->rq_stack_index=0;
+	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
+		floppy->rq_stack_index = 0;
 	return (&floppy->rq_stack[floppy->rq_stack_index++]);
 }
 
@@ -853,14 +677,20 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv[0] & 0x80 ?
-		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+	floppy->sense_key = result->sense_key;
+	floppy->asc = result->asc;
+	floppy->ascq = result->ascq;
+	floppy->progress_indication = result->sksv[0] & 0x80 ?
+		(u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
-		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
+			result->sense_key, result->asc, result->ascq);
 	else
-		printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
+			"ascq = %x\n", result->sense_key,
+			result->asc, result->ascq);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
@@ -869,14 +699,14 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
+	printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_do_end_request(drive, 1);
+		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1, 0);
 	} else {
-		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_do_end_request(drive, 0);
+		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idefloppy_do_end_request(drive, 0, 0);
 	}
 }
 
@@ -888,10 +718,10 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
+	printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);
 }
 
 /*
@@ -899,7 +729,7 @@
  */
 static void idefloppy_init_pc (idefloppy_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -912,7 +742,7 @@
 
 static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);	
+	idefloppy_init_pc(pc);	
 	pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
 	pc->c[4] = 255;
 	pc->request_transfer = 18;
@@ -928,13 +758,13 @@
 {
 	idefloppy_pc_t *pc;
 	struct request *rq;
-	idefloppy_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
-	pc = idefloppy_next_pc_storage (drive);
-	rq = idefloppy_next_rq_storage (drive);
-	idefloppy_create_request_sense_cmd (pc);
-	idefloppy_queue_pc_head (drive, pc, rq);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	pc = idefloppy_next_pc_storage(drive);
+	rq = idefloppy_next_rq_storage(drive);
+	idefloppy_create_request_sense_cmd(pc);
+	idefloppy_queue_pc_head(drive, pc, rq);
 }
 
 /*
@@ -944,24 +774,25 @@
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_status_reg_t status;
-	idefloppy_bcount_reg_t bcount;
-	idefloppy_ireason_reg_t ireason;
-	idefloppy_pc_t *pc=floppy->pc;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
+	idefloppy_pc_t *pc = floppy->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+		__FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */	
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
-			set_bit (PC_DMA_ERROR, &pc->flags);
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
+			set_bit(PC_DMA_ERROR, &pc->flags);
 		} else {
-			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers (drive, pc);
+			pc->actually_transferred = pc->request_transfer;
+			idefloppy_update_buffers(drive, pc);
 		}
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
@@ -969,83 +800,112 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	status.all = GET_STAT();	/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {		/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 #if IDEFLOPPY_DEBUG_LOG
-		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+		printk(KERN_INFO "Packet command completed, %d bytes "
+			"transferred\n", pc->actually_transferred);
 #endif /* IDEFLOPPY_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
 		local_irq_enable();
 
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
+			printk(KERN_INFO "ide-floppy: %s: I/O error\n",
+				drive->name);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-floppy: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
-			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ide_stopped; /* queued, but not started */
+			/* Retry operation */
+			idefloppy_retry_pc(drive);
+			/* queued, but not started */
+			return ide_stopped;
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
-			floppy->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
+			floppy->failed_pc = NULL;
+		/* Command finished - Call the callback function */
+		pc->callback(drive);
 		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-floppy: The floppy wants to issue "
+			"more interrupts in DMA mode\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "but the floppy wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
-				idefloppy_discard_data (drive,bcount.all);
+				printk(KERN_ERR "ide-floppy: The floppy wants "
+					"to send us more data than expected "
+					"- discarding data\n");
+				idefloppy_discard_data(drive,bcount.all);
 				if (HWGROUP(drive)->handler != NULL)
 					BUG();
-				ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+				ide_set_handler(drive,
+						&idefloppy_pc_intr,
+						IDEFLOPPY_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-floppy: The floppy wants to "
+				"send us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_output_buffers (drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_input_buffers (drive, pc, bcount.all);
+			idefloppy_input_buffers(drive, pc, bcount.all);
 	}
-	pc->actually_transferred+=bcount.all;				/* Update the current position */
-	pc->current_position+=bcount.all;
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
 
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
@@ -1062,23 +922,25 @@
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
 		printk(KERN_ERR "ide-floppy: Strange, packet command "
 				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = IN_BYTE(IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
 				"issuing a packet command\n");
-		return ide_do_reset (drive);
+		return ide_do_reset(drive);
 	}
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
-	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
 	return ide_started;
 }
 
@@ -1099,33 +961,36 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	atapi_output_bytes(drive, floppy->pc->c, 12); /* Send the actual packet */
-	return IDEFLOPPY_WAIT_CMD;	/* Timeout for the packet command */
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+	/* Timeout for the packet command */
+	return IDEFLOPPY_WAIT_CMD;
 }
 
 static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
 		printk(KERN_ERR "ide-floppy: Strange, packet command "
 				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = IN_BYTE(IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
 				"while issuing a packet command\n");
-		return ide_do_reset (drive);
+		return ide_do_reset(drive);
 	}
 	/* 
-	 * The following delay solves a problem with ATAPI Zip 100 drives where the
-	 * Busy flag was apparently being deasserted before the unit was ready to
-	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
-	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
-	 * not be actually used until after the packet is moved in about 50 msec.
+	 * The following delay solves a problem with ATAPI Zip 100 drives
+	 * where the Busy flag was apparently being deasserted before the
+	 * unit was ready to receive data. This was happening on a
+	 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
+	 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
+	 * used until after the packet is moved in about 50 msec.
 	 */
 	if (HWGROUP(drive)->handler != NULL)
 		BUG();
@@ -1142,28 +1007,32 @@
 static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
-	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
+	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
-	if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-		floppy->failed_pc=pc;
-	floppy->pc=pc;							/* Set the current packet command */
+	if (floppy->failed_pc == NULL &&
+	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+		floppy->failed_pc = pc;
+	/* Set the current packet command */
+	floppy->pc = pc;
 
-	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received.
 		 */
-		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
-				;
+		if (!test_bit(PC_ABORT, &pc->flags)) {
+			if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
 				printk(KERN_ERR "ide-floppy: %s: I/O error, "
 						"pc = %2x, key = %2x, "
 						"asc = %2x, ascq = %2x\n",
@@ -1174,56 +1043,73 @@
 			/* Giving up */
 			pc->error = IDEFLOPPY_ERROR_GENERAL;
 		}
-		floppy->failed_pc=NULL;
+		floppy->failed_pc = NULL;
 		pc->callback(drive);
 		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Retry number - %d\n",pc->retries);
+	printk(KERN_INFO "Retry number - %d\n",pc->retries);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;	/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
 	bcount.all = min(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	feature.all = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+		}
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE(dma_ok ? 1:0,IDE_FEATURE_REG);		/* Use PIO/DMA */
-	OUT_BYTE(bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE(bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE(drive->select.all,IDE_SELECT_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {				/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	if (feature.b.dma) {	/* Begin DMA, if necessary */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	/* Can we transfer the packet when we get the interrupt or wait? */
-	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
-		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		/* wait */
+		pkt_xfer_routine = &idefloppy_transfer_pc1;
 	} else {
-		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+		/* immediate */
+		pkt_xfer_routine = &idefloppy_transfer_pc;
 	}
 	
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
 		if (HWGROUP(drive)->handler != NULL)
 			BUG();
-		ide_set_handler(drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		ide_set_handler(drive,
+				pkt_xfer_routine,
+				IDEFLOPPY_WAIT_CMD,
+				NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*pkt_xfer_routine) (drive);
 	}
 }
@@ -1234,24 +1120,25 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_do_end_request(drive, 1);
+	idefloppy_do_end_request(drive, 1, 0);
 	return;
 }
 
 static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
 {
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent);
+	printk(KERN_INFO "ide-floppy: creating prevent removal command, "
+		"prevent = %d\n", prevent);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
 	pc->c[4] = prevent;
 }
 
 static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
@@ -1261,13 +1148,13 @@
 static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
 					      int flags)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
 	pc->c[1] = 0x17;
 
 	memset(pc->buffer, 0, 12);
 	pc->buffer[1] = 0xA2;
-	/* Default format list header, byte 1: FOV/DCRT/IMM bits set */
+	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
 
 	if (flags & 1)				/* Verify bit on... */
 		pc->buffer[1] ^= 0x20;		/* ... turn off DCRT bit */
@@ -1282,11 +1169,11 @@
 /*
  *	A mode sense command is used to "sense" floppy parameters.
  */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, byte page_code, byte type)
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
 {
-	unsigned short length = sizeof (idefloppy_mode_parameter_header_t);
+	u16 length = sizeof(idefloppy_mode_parameter_header_t);
 	
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
 	pc->c[1] = 0;
 	pc->c[2] = page_code + (type << 6);
@@ -1299,15 +1186,16 @@
 			length += 32;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported page code in create_mode_sense_cmd\n");
+			printk(KERN_ERR "ide-floppy: unsupported page code "
+				"in create_mode_sense_cmd\n");
 	}
-	put_unaligned (htons (length), (unsigned short *) &pc->c[7]);
+	put_unaligned(htons(length), (u16 *) &pc->c[7]);
 	pc->request_transfer = length;
 }
 
 static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_START_STOP_CMD;
 	pc->c[4] = start;
 }
@@ -1325,28 +1213,29 @@
 	int cmd = rq_data_dir(rq);
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
-		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
+	printk("create_rw1%d_cmd: block == %d, blocks == %d\n",
+		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags),
+		block, blocks);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
-	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
+	idefloppy_init_pc(pc);
+	if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
-		put_unaligned(htonl (blocks), (unsigned int *) &pc->c[6]);
+		put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
 	} else {
 		pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-		put_unaligned(htons (blocks), (unsigned short *) &pc->c[7]);
+		put_unaligned(htons(blocks), (unsigned short *) &pc->c[7]);
 	}
-	put_unaligned(htonl (block), (unsigned int *) &pc->c[2]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
 	pc->callback = &idefloppy_rw_callback;
 	pc->rq = rq;
 	pc->b_data = rq->buffer;
 	pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
 	if (rq->flags & REQ_RW)
-		set_bit (PC_WRITING, &pc->flags);
+		set_bit(PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-	set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+	set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
@@ -1375,7 +1264,7 @@
 		else
 			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
 				drive->name);
-		idefloppy_do_end_request(drive, 0);
+		idefloppy_do_end_request(drive, 0, 0);
 		return ide_stopped;
 	}
 	if (rq->flags & REQ_CMD) {
@@ -1383,17 +1272,17 @@
 		    (rq->nr_sectors % floppy->bs_factor)) {
 			printk("%s: unsupported r/w request size\n",
 				drive->name);
-			idefloppy_do_end_request(drive, 0);
+			idefloppy_do_end_request(drive, 0, 0);
 			return ide_stopped;
 		}
-		pc = idefloppy_next_pc_storage (drive);
-		idefloppy_create_rw_cmd (floppy, pc, rq, block);
+		pc = idefloppy_next_pc_storage(drive);
+		idefloppy_create_rw_cmd(floppy, pc, rq, block);
 	} else if (rq->flags & REQ_SPECIAL) {
 		pc = (idefloppy_pc_t *) rq->buffer;
 	} else {
 		blk_dump_rq_flags(rq,
 			"ide-floppy: unsupported command in queue");
-		idefloppy_do_end_request(drive, 0);
+		idefloppy_do_end_request(drive, 0, 0);
 		return ide_stopped;
 	}
 
@@ -1413,7 +1302,7 @@
 	rq.buffer = (char *) pc;
 	rq.flags = REQ_SPECIAL;		//	rq.cmd = IDEFLOPPY_PC_RQ;
 
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
@@ -1428,19 +1317,20 @@
 	idefloppy_flexible_disk_page_t *page;
 	int capacity, lba_capacity;
 
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get flexible disk page parameters\n");
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get flexible disk "
+			"page parameters\n");
 		return 1;
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
-	page->transfer_rate = ntohs (page->transfer_rate);
-	page->sector_size = ntohs (page->sector_size);
-	page->cyls = ntohs (page->cyls);
-	page->rpm = ntohs (page->rpm);
+	page->transfer_rate = ntohs(page->transfer_rate);
+	page->sector_size = ntohs(page->sector_size);
+	page->cyls = ntohs(page->cyls);
+	page->rpm = ntohs(page->rpm);
 	capacity = page->cyls * page->heads * page->sectors * page->sector_size;
 	if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
 		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
@@ -1470,18 +1360,18 @@
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_capabilities_page_t *page;
 
-	floppy->srfp=0;
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+	floppy->srfp = 0;
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
 						 MODE_SENSE_CURRENT);
 
 	set_bit(PC_SUPPRESS_ERROR, &pc.flags);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
 		return 1;
 	}
 
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	page= (idefloppy_capabilities_page_t *)(header+1);
-	floppy->srfp=page->srfp;
+	floppy->srfp = page->srfp;
 	return (0);
 }
 
@@ -1502,57 +1392,76 @@
 	floppy->blocks = floppy->bs_factor = 0;
 	set_capacity(drive->disk, 0);
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 		return 1;
 	}
 	header = (idefloppy_capacity_header_t *) pc.buffer;
-	descriptors = header->length / sizeof (idefloppy_capacity_descriptor_t);
+	descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
 	for (i = 0; i < descriptors; i++, descriptor++) {
-                blocks = descriptor->blocks = ntohl (descriptor->blocks);
-                length = descriptor->length = ntohs (descriptor->length);
+		blocks = descriptor->blocks = ntohl(descriptor->blocks);
+		length = descriptor->length = ntohs(descriptor->length);
 
 		if (!i) 
 		{
-          	switch (descriptor->dc) {
-                case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */
-                        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-                                break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */
-                case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */
-                        if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
-                                printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
-                        floppy->capacity = *descriptor;
-                        if (!length || length % 512)
-                                printk (KERN_NOTICE "%s: %d bytes block size not supported\n", drive->name, length);
-                        else {
+		switch (descriptor->dc) {
+		/* Clik! drive returns this instead of CAPACITY_CURRENT */
+		case CAPACITY_UNFORMATTED:
+			if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+                                /*
+				 * If it is not a clik drive, break out
+				 * (maintains previous driver behaviour)
+				 */
+				break;
+		case CAPACITY_CURRENT:
+			/* Normal Zip/LS-120 disks */
+			if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+				printk(KERN_INFO "%s: %dkB, %d blocks, %d "
+					"sector size\n", drive->name,
+					blocks * length / 1024, blocks, length);
+			floppy->capacity = *descriptor;
+			if (!length || length % 512) {
+				printk(KERN_NOTICE "%s: %d bytes block size "
+					"not supported\n", drive->name, length);
+			} else {
                                 floppy->blocks = blocks;
                                 floppy->block_size = length;
                                 if ((floppy->bs_factor = length / 512) != 1)
-                                        printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name);
+                                        printk(KERN_NOTICE "%s: warning: non "
+						"512 bytes block size not "
+						"fully supported\n",
+						drive->name);
                                 rc = 0;
-                        }
-                        break;
-                case CAPACITY_NO_CARTRIDGE:
-                        /* This is a KERN_ERR so it appears on screen for the user to see */
-                        printk (KERN_ERR "%s: No disk in drive\n", drive->name);
-                                        break;
-                case CAPACITY_INVALID:
-                        printk (KERN_ERR "%s: Invalid capacity for disk in drive\n", drive->name);
-                                        break;
+			}
+			break;
+		case CAPACITY_NO_CARTRIDGE:
+			/*
+			 * This is a KERN_ERR so it appears on screen
+			 * for the user to see
+			 */
+			printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+			break;
+		case CAPACITY_INVALID:
+			printk(KERN_ERR "%s: Invalid capacity for disk "
+				"in drive\n", drive->name);
+			break;
 		}
 		}
 		if (!i) {
-		IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", descriptor->dc);
+			IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n",
+				descriptor->dc);
 		}
-		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length);
+		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d "
+			"sector size\n", i, blocks * length / 1024, blocks,
+			length);
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
         if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-		(void) idefloppy_get_flexible_disk_page (drive);
+		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
 	set_capacity(drive->disk, floppy->blocks * floppy->bs_factor);
@@ -1599,18 +1508,18 @@
 	if (u_array_size <= 0)
 		return (-EINVAL);
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                 return (-EIO);
         }
         header = (idefloppy_capacity_header_t *) pc.buffer;
         descriptors = header->length /
-		sizeof (idefloppy_capacity_descriptor_t);
+		sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
-	u_index=0;
-	argp=arg+1;
+	u_index = 0;
+	argp = arg + 1;
 
 	/*
 	** We always skip the first capacity descriptor.  That's the
@@ -1618,18 +1527,17 @@
 	** the formattable capacities.
 	*/
 
-	for (i=0; i<descriptors; i++, descriptor++)
-	{
+	for (i=0; i<descriptors; i++, descriptor++) {
 		if (u_index >= u_array_size)
 			break;	/* User-supplied buffer too small */
 		if (i == 0)
 			continue;	/* Skip the first descriptor */
 
-		blocks = ntohl (descriptor->blocks);
-		length = ntohs (descriptor->length);
+		blocks = ntohl(descriptor->blocks);
+		length = ntohs(descriptor->length);
 
 		if (put_user(blocks, argp))
-			return (-EFAULT);
+			return(-EFAULT);
 		++argp;
 
 		if (put_user(length, argp))
@@ -1670,19 +1578,19 @@
 	int flags;
 	idefloppy_pc_t pc;
 
-	if (get_user(blocks, arg)
-	    || get_user(length, arg+1)
-	    || get_user(flags, arg+2))
-	{
+	if (get_user(blocks, arg) ||
+	    get_user(length, arg+1) ||
+	    get_user(flags, arg+2)) {
 		return (-EFAULT);
 	}
 
-	(void) idefloppy_get_capability_page (drive);	/* Get the SFRP bit */
+	/* Get the SFRP bit */
+	(void) idefloppy_get_capability_page(drive);
 	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-	if (idefloppy_queue_pc_tail (drive, &pc))
-	{
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
                 return (-EIO);
-        }
+	}
+
 	return (0);
 }
 
@@ -1703,34 +1611,30 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t pc;
-	int progress_indication=0x10000;
+	int progress_indication = 0x10000;
 
-	if (floppy->srfp)
-	{
+	if (floppy->srfp) {
 		idefloppy_create_request_sense_cmd(&pc);
-		if (idefloppy_queue_pc_tail (drive, &pc))
-		{
+		if (idefloppy_queue_pc_tail(drive, &pc)) {
 			return (-EIO);
 		}
 
-		if (floppy->sense_key == 2 && floppy->asc == 4 &&
-		    floppy->ascq == 4)
-		{
-			progress_indication=floppy->progress_indication;
+		if (floppy->sense_key == 2 &&
+		    floppy->asc == 4 &&
+		    floppy->ascq == 4) {
+			progress_indication = floppy->progress_indication;
 		}
 		/* Else assume format_unit has finished, and we're
 		** at 0x10000 */
-	}
-	else
-	{
-		idefloppy_status_reg_t status;
+	} else {
+		atapi_status_t status;
 		unsigned long flags;
 
 		local_irq_save(flags);
-		status.all=GET_STAT();
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 		local_irq_restore(flags);
 
-		progress_indication= !status.b.dsc ? 0:0x10000;
+		progress_indication = !status.b.dsc ? 0 : 0x10000;
 	}
 	if (put_user(progress_indication, arg))
 		return (-EFAULT);
@@ -1760,12 +1664,12 @@
 
 		/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, prevent);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, prevent);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		if (cmd == CDROMEJECT) {
-			idefloppy_create_start_stop_cmd (&pc, 2);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 2);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		return 0;
 	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
@@ -1781,16 +1685,13 @@
 		{
 			idefloppy_floppy_t *floppy = drive->driver_data;
 
-			if (drive->usage > 1)
-			{
+			if (drive->usage > 1) {
 				/* Don't format if someone is using the disk */
 
 				clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
 					  &floppy->flags);
 				return -EBUSY;
-			}
-			else
-			{
+			} else {
 				int rc;
 
 				set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
@@ -1829,7 +1730,7 @@
 	idefloppy_pc_t pc;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_open\n");
+	printk(KERN_INFO "Reached idefloppy_open\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	MOD_INC_USE_COUNT;
@@ -1839,8 +1740,8 @@
 
 		idefloppy_create_test_unit_ready_cmd(&pc);
 		if (idefloppy_queue_pc_tail(drive, &pc)) {
-			idefloppy_create_start_stop_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		if (idefloppy_get_capacity (drive)
@@ -1861,16 +1762,14 @@
 			MOD_DEC_USE_COUNT;
 			return -EROFS;
 		}		
-		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		check_disk_change(inode->i_bdev);
-	}
-	else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags))
-	{
+	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1891,8 +1790,8 @@
 
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 0);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 0);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
@@ -1907,7 +1806,7 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
-	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+	return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
@@ -1937,109 +1836,114 @@
 {
 	struct idefloppy_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
-	unsigned short mask,i;
+	u16 mask,i;
 	char buffer[80];
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
-	*((unsigned short *) &gcw) = id->config;
+	*((u16 *) &gcw) = id->config;
 
 #ifdef CONFIG_PPC
 	/* kludge for Apple PowerBook internal zip */
-	if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
-	    && strstr(id->model, "ZIP"))
+	if ((gcw.device_type == 5) &&
+	    !strstr(id->model, "CD-ROM") &&
+	    strstr(id->model, "ZIP"))
 		gcw.device_type = 0;			
 #endif
 
 #if IDEFLOPPY_DEBUG_INFO
-	printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
+	printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
 	switch (gcw.protocol) {
-		case 0: case 1: sprintf (buffer, "ATA");break;
-		case 2:	sprintf (buffer, "ATAPI");break;
-		case 3: sprintf (buffer, "Reserved (Unknown to ide-floppy)");break;
+		case 0: case 1: sprintf(buffer, "ATA");break;
+		case 2:	sprintf(buffer, "ATAPI");break;
+		case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
 	}
-	printk (KERN_INFO "Protocol Type: %s\n", buffer);
+	printk(KERN_INFO "Protocol Type: %s\n", buffer);
 	switch (gcw.device_type) {
-		case 0: sprintf (buffer, "Direct-access Device");break;
-		case 1: sprintf (buffer, "Streaming Tape Device");break;
+		case 0: sprintf(buffer, "Direct-access Device");break;
+		case 1: sprintf(buffer, "Streaming Tape Device");break;
 		case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
-		case 5: sprintf (buffer, "CD-ROM Device");break;
-		case 6: sprintf (buffer, "Reserved");
-		case 7: sprintf (buffer, "Optical memory Device");break;
-		case 0x1f: sprintf (buffer, "Unknown or no Device type");break;
-		default: sprintf (buffer, "Reserved");
+		case 5: sprintf(buffer, "CD-ROM Device");break;
+		case 6: sprintf(buffer, "Reserved");
+		case 7: sprintf(buffer, "Optical memory Device");break;
+		case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
+		default: sprintf(buffer, "Reserved");
 	}
-	printk (KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
-	printk (KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
+	printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
+	printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
 	switch (gcw.drq_type) {
-		case 0: sprintf (buffer, "Microprocessor DRQ");break;
-		case 1: sprintf (buffer, "Interrupt DRQ");break;
-		case 2: sprintf (buffer, "Accelerated DRQ");break;
-		case 3: sprintf (buffer, "Reserved");break;
+		case 0: sprintf(buffer, "Microprocessor DRQ");break;
+		case 1: sprintf(buffer, "Interrupt DRQ");break;
+		case 2: sprintf(buffer, "Accelerated DRQ");break;
+		case 3: sprintf(buffer, "Reserved");break;
 	}
-	printk (KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
+	printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
 	switch (gcw.packet_size) {
-		case 0: sprintf (buffer, "12 bytes");break;
-		case 1: sprintf (buffer, "16 bytes");break;
-		default: sprintf (buffer, "Reserved");break;
-	}
-	printk (KERN_INFO "Command Packet Size: %s\n", buffer);
-	printk (KERN_INFO "Model: %.40s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "Single Word DMA supported modes:\n");
+		case 0: sprintf(buffer, "12 bytes");break;
+		case 1: sprintf(buffer, "16 bytes");break;
+		default: sprintf(buffer, "Reserved");break;
+	}
+	printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+	printk(KERN_INFO "Model: %.40s\n",id->model);
+	printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "Single Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_1word & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_1word & (mask << 8)) ? " (active)" : "");
 	}
-	printk (KERN_INFO "Multi Word DMA supported modes:\n");
+	printk(KERN_INFO "Multi Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_mword & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_mword & (mask << 8)) ? " (active)" : "");
 	}
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		if (id->eide_dma_min == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_min);
-		printk (KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_min);
+		printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
 		if (id->eide_dma_time == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_time);
-		printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_time);
+		printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
 		if (id->eide_pio == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio);
-		printk (KERN_INFO "Minimum PIO cycle without IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio);
+		printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+			buffer);
 		if (id->eide_pio_iordy == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio_iordy);
-		printk (KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio_iordy);
+		printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
 	} else
-		printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
 	if (gcw.protocol != 2)
-		printk (KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 0)
-		printk (KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+		printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-floppy: The removable flag is not set\n");
+		printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
 	else if (gcw.drq_type == 3) {
-		printk (KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+		printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
 	} else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
 	} else
 		return 1;
 	return 0;
@@ -2056,7 +1960,6 @@
 	ide_add_setting(drive,	"bios_head",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&drive->bios_head,		NULL);
 	ide_add_setting(drive,	"bios_sect",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	63,				1,	1,	&drive->bios_sect,		NULL);
 	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
-
 }
 
 /*
@@ -2066,14 +1969,14 @@
 {
 	struct idefloppy_id_gcw gcw;
 
-	*((unsigned short *) &gcw) = drive->id->config;
+	*((u16 *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
 	drive->ready_stat = 0;
-	memset (floppy, 0, sizeof (idefloppy_floppy_t));
+	memset(floppy, 0, sizeof(idefloppy_floppy_t));
 	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
-		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
 	/*
 	 *	We used to check revisions here. At this point however
 	 *	I'm giving up. Just assume they are all broken, its easier.
@@ -2085,8 +1988,7 @@
 	 *	we'll leave the limitation below for the 2.2.x tree.
 	 */
 
-	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
-	{
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) {
 		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
 		/* This value will be visible in the /proc/ide/hdx/settings */
 		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
@@ -2098,14 +2000,13 @@
 	*      above fix.  It makes nasty clicking noises without
 	*      it, so please don't remove this.
 	*/
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
-	{
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
 		blk_queue_max_sectors(&drive->queue, 64);
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
 
-	(void) idefloppy_get_capacity (drive);
+	(void) idefloppy_get_capacity(drive);
 	idefloppy_add_settings(drive);
 }
 
@@ -2114,10 +2015,10 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	struct gendisk *g = drive->disk;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
 	drive->driver_data = NULL;
-	kfree (floppy);
+	kfree(floppy);
 	del_gendisk(g);
 	return 0;
 }
@@ -2135,7 +2036,7 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-static int idefloppy_reinit(ide_drive_t *drive);
+static int idefloppy_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2170,13 +2071,13 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	reinit:			idefloppy_reinit,
+	attach:			idefloppy_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 	drives:			LIST_HEAD_INIT(idefloppy_driver.drives),
 };
 
-static int idefloppy_reinit (ide_drive_t *drive)
+static int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
 	struct gendisk *g = drive->disk;
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- a/drivers/ide/ide-geometry.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/ide/ide-geometry.c	Sun Sep 15 19:19:29 2002
@@ -6,8 +6,6 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDE
-
 /*
  * 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
@@ -25,14 +23,12 @@
  * If a drive is not actually on the primary interface, then these parameters
  * will be ignored.  This results in the user having to supply the logical
  * drive geometry as a boot parameter for each drive not on the primary i/f.
- */
-/*
+ *
  * The only "perfect" way to handle this would be to modify the setup.[cS] code
  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-/*
- * I did this, but it doesnt work - there is no reasonable way to find the
+ *
+ * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
  *
@@ -51,14 +47,13 @@
 {
 #ifdef __i386__
 	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	u8 cmos_disks, *BIOS = (u8 *) &drive_info;
 	int unit;
 	unsigned long flags;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
 	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
 		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+
 	spin_lock_irqsave(&rtc_lock, flags);
 	cmos_disks = CMOS_READ(0x12);
 	spin_unlock_irqrestore(&rtc_lock, flags);
@@ -68,7 +63,7 @@
 
 		if ((cmos_disks & (0xf0 >> (unit*4)))
 		   && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
+			u16 cyl = *(u16 *)BIOS;
 			unsigned char head = *(BIOS+2);
 			unsigned char sect = *(BIOS+14);
 			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
@@ -86,10 +81,7 @@
 	}
 #endif
 }
-#endif /* CONFIG_BLK_DEV_IDE */
-
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -98,10 +90,11 @@
  * If heads is nonzero: find a translation with this many heads and S=63.
  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  */
-static void
-ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
-	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const byte *headp = dm_head_vals;
+
+static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) 
+{
+	static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const u8 *headp = dm_head_vals;
 	unsigned long total;
 
 	/*
@@ -153,6 +146,7 @@
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
 {
 	ide_drive_t *drive;
@@ -217,8 +211,7 @@
 	set_capacity(drive->disk, current_capacity(drive));
 
 	if (ret)
-		printk("%s%s [%d/%d/%d]", msg, msg1,
+		printk(KERN_INFO "%s%s [%d/%d/%d]", msg, msg1,
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-iops.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,1254 @@
+/*
+ * linux/drivers/ide/ide-iops.c	Version 0.33	April 11, 2002
+ *
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+
+static inline u8 ide_inb (u32 port)
+{
+	return (u8) IN_BYTE(port);
+}
+
+static inline u8 ide_inb_p (u32 port)
+{
+	return (u8) IN_BYTE_P(port);
+}
+
+static inline u16 ide_inw (u32 port)
+{
+	return (u16) IN_WORD(port);
+}
+
+static inline u16 ide_inw_p (u32 port)
+{
+	return (u16) IN_WORD_P(port);
+}
+
+static inline void ide_insw (u32 port, void *addr, u32 count)
+{
+	while (count--) { *(u16 *)addr = IN_WORD(port); addr += 2; }
+}
+
+static inline void ide_insw_p (u32 port, void *addr, u32 count)
+{
+	while (count--) { *(u16 *)addr = IN_WORD_P(port); addr += 2; }
+}
+
+static inline u32 ide_inl (u32 port)
+{
+	return (u32) IN_LONG(port);
+}
+
+static inline u32 ide_inl_p (u32 port)
+{
+        return (u32) IN_LONG_P(port);
+}
+
+static inline void ide_insl (u32 port, void *addr, u32 count)
+{
+	ide_insw(port, addr, (count)<<1);
+//	while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
+}
+
+static inline void ide_insl_p (u32 port, void *addr, u32 count)
+{
+	ide_insw_p(port, addr, (count)<<1);
+//	while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
+}
+
+static inline void ide_outb (u8 addr, u32 port)
+{
+	OUT_BYTE(addr, port);
+}
+
+static inline void ide_outb_p (u8 addr, u32 port)
+{
+	OUT_BYTE_P(addr, port);
+}
+
+static inline void ide_outw (u16 addr, u32 port)
+{
+	OUT_WORD(addr, port);
+}
+
+static inline void ide_outw_p (u16 addr, u32 port)
+{
+	OUT_WORD_P(addr, port);
+}
+
+static inline void ide_outsw (u32 port, void *addr, u32 count)
+{
+	while (count--) { OUT_WORD(*(u16 *)addr, port); addr += 2; }
+}
+
+static inline void ide_outsw_p (u32 port, void *addr, u32 count)
+{
+	while (count--) { OUT_WORD_P(*(u16 *)addr, port); addr += 2; }
+}
+
+static inline void ide_outl (u32 addr, u32 port)
+{
+	OUT_LONG(addr, port);
+}
+
+static inline void ide_outl_p (u32 addr, u32 port)
+{
+	OUT_LONG_P(addr, port);
+}
+
+static inline void ide_outsl (u32 port, void *addr, u32 count)
+{
+	ide_outsw(port, addr, (count)<<1);
+//	while (count--) { OUT_LONG(*(u32 *)addr, port); addr += 4; }
+}
+
+static inline void ide_outsl_p (u32 port, void *addr, u32 count)
+{
+	ide_outsw_p(port, addr, (count)<<1);
+//	while (count--) { OUT_LONG_P(*(u32 *)addr, port); addr += 4; }
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_outb;
+	hwif->OUTBP	= ide_outb_p;
+	hwif->OUTW	= ide_outw;
+	hwif->OUTWP	= ide_outw_p;
+	hwif->OUTL	= ide_outl;
+	hwif->OUTLP	= ide_outl_p;
+	hwif->OUTSW	= ide_outsw;
+	hwif->OUTSWP	= ide_outsw_p;
+	hwif->OUTSL	= ide_outsl;
+	hwif->OUTSLP	= ide_outsl_p;
+	hwif->INB	= ide_inb;
+	hwif->INBP	= ide_inb_p;
+	hwif->INW	= ide_inw;
+	hwif->INWP	= ide_inw_p;
+	hwif->INL	= ide_inl;
+	hwif->INLP	= ide_inl_p;
+	hwif->INSW	= ide_insw;
+	hwif->INSWP	= ide_insw_p;
+	hwif->INSL	= ide_insl;
+	hwif->INSLP	= ide_insl_p;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+void default_hwif_transport (ide_hwif_t *hwif)
+{
+	hwif->ata_input_data		= ata_input_data;
+	hwif->ata_output_data		= ata_output_data;
+	hwif->atapi_input_bytes		= atapi_input_bytes;
+	hwif->atapi_output_bytes	= atapi_output_bytes;
+}
+
+EXPORT_SYMBOL(default_hwif_transport);
+
+u32 read_24 (ide_drive_t *drive)
+{
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+}
+
+EXPORT_SYMBOL(read_24);
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+	if (HWIF(drive)->selectproc)
+		HWIF(drive)->selectproc(drive);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+}
+
+EXPORT_SYMBOL(SELECT_DRIVE);
+
+void SELECT_INTERRUPT (ide_drive_t *drive)
+{
+	if (HWIF(drive)->intrproc)
+		HWIF(drive)->intrproc(drive);
+	else
+		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+EXPORT_SYMBOL(SELECT_INTERRUPT);
+
+void SELECT_MASK (ide_drive_t *drive, int mask)
+{
+	if (HWIF(drive)->maskproc)
+		HWIF(drive)->maskproc(drive, mask);
+}
+
+EXPORT_SYMBOL(SELECT_MASK);
+
+void QUIRK_LIST (ide_drive_t *drive)
+{
+	if (HWIF(drive)->quirkproc)
+		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+}
+
+EXPORT_SYMBOL(QUIRK_LIST);
+
+#if SUPPORT_VLB_SYNC
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+void ata_vlb_sync (ide_drive_t *drive, ide_ioreg_t port)
+{
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+}
+
+EXPORT_SYMBOL(ata_vlb_sync);
+#endif /* SUPPORT_VLB_SYNC */
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			u16 *ptr = (u16 *) buffer;
+			while (wcount--) {
+				*ptr++ = hwif->INWP(IDE_DATA_REG);
+				*ptr++ = hwif->INWP(IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+#if SUPPORT_VLB_SYNC
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+#endif /* SUPPORT_VLB_SYNC */
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+#if SUPPORT_SLOW_DATA_PORTS
+		if (drive->slow) {
+			u16 *ptr = (u16 *) buffer;
+			while (wcount--) {
+				hwif->OUTWP(*ptr++, IDE_DATA_REG);
+				hwif->OUTWP(*ptr++, IDE_DATA_REG);
+			}
+		} else
+#endif /* SUPPORT_SLOW_DATA_PORTS */
+			hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_output_data);
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_input_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_input_bytes);
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_output_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_output_bytes);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+void ide_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+	u16 *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (u16 *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (u16 *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (u16 *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; ++i)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; ++i)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth    = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; ++i)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->mprc           = __le16_to_cpu(id->mprc);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+EXPORT_SYMBOL(ide_fix_driveid);
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+	u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+	if (byteswap) {
+		/* convert from big-endian to host byte order */
+		for (p = end ; p != s;) {
+			unsigned short *pp = (unsigned short *) (p -= 2);
+			*pp = ntohs(*pp);
+		}
+	}
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
+	}
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
+}
+
+EXPORT_SYMBOL(ide_fixstring);
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	if (drive->waiting_for_dma)
+		return hwif->ide_dma_test_irq(drive);
+
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+	/*
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
+	 */
+	if (IDE_CONTROL_REG)
+		stat = hwif->INB(IDE_ALTSTATUS_REG);
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		/* Note: this may clear a pending IRQ!! */
+		stat = hwif->INB(IDE_STATUS_REG);
+
+	if (stat & BUSY_STAT)
+		/* drive busy:  definitely not interrupting */
+		return 0;
+
+	/* drive ready: *might* be interrupting */
+	return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * Global for All, and taken from ide-pmac.c. Can be called
+ * with spinlock held & IRQs disabled, so don't schedule !
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	while(--timeout) {
+		stat = hwif->INB(IDE_STATUS_REG);
+		if (!(stat & BUSY_STAT)) {
+			if (drive->ready_stat == 0)
+				break;
+			else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
+				break;
+		}
+		mdelay(1);
+	}
+	if ((stat & ERR_STAT) || timeout <= 0) {
+		if (stat & ERR_STAT) {
+			printk(KERN_ERR "%s: wait_for_ready, "
+				"error status: %x\n", drive->name, stat);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(wait_for_ready);
+
+/*
+ * 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() -- caller should just return.
+ *
+ * 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 timeout is achieved, before timing out.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+	int i;
+	unsigned long flags;
+ 
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		*startstop = ide_stopped;
+		return 1;
+	}
+
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		local_irq_set(flags);
+		timeout += jiffies;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout)) {
+				local_irq_restore(flags);
+				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
+				return 1;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+			return 0;
+	}
+	*startstop = DRIVER(drive)->error(drive, "status error", stat);
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/*
+ *  All hosts that use the 80c ribbon must use!
+ *  The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+u8 eighty_ninty_three (ide_drive_t *drive)
+{
+#if 0
+	if (!HWIF(drive)->udma_four)
+		return 0;
+
+	if (drive->id->major_rev_num) {
+		int hssbd = 0;
+		int i;
+		/*
+		 * Determime highest Supported SPEC
+		 */
+		for (i=1; i<=15; i++)
+			if (drive->id->major_rev_num & (1<<i))
+				hssbd++;
+
+		switch (hssbd) {
+			case 7:
+			case 6:
+			case 5:
+		/* ATA-4 and older do not support above Ultra 33 */
+			default:
+				return 0;
+		}
+	}
+
+	return ((u8) (
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+	return ((u8) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+			(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+			(drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+		if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+		if (((drive->id->hw_config & 0x2000) == 0) ||
+		    ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n", drive->name);
+			return 1;
+		}
+		if (!HWIF(drive)->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n",
+				HWIF(drive)->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_ata66_check);
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	    (drive->id->dma_ultra ||
+	     drive->id->dma_mword ||
+	     drive->id->dma_1word))
+		return 1;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(set_transfer);
+
+u8 ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+	if (!drive->crc_count)
+		return drive->current_speed;
+	drive->crc_count = 0;
+
+	switch(drive->current_speed) {
+		case XFER_UDMA_7:	return XFER_UDMA_6;
+		case XFER_UDMA_6:	return XFER_UDMA_5;
+		case XFER_UDMA_5:	return XFER_UDMA_4;
+		case XFER_UDMA_4:	return XFER_UDMA_3;
+		case XFER_UDMA_3:	return XFER_UDMA_2;
+		case XFER_UDMA_2:	return XFER_UDMA_1;
+		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
+		case XFER_UDMA_0:
+		default:		return XFER_PIO_4;
+	}
+}
+
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
+
+/*
+ * Update the 
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id;
+#if 0
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id)
+		return 0;
+
+	taskfile_lib_get_identify(drive, (char *)&id);
+
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+	return 1;
+#else
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	unsigned long timeout, flags;
+
+	SELECT_MASK(drive, 1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			SELECT_MASK(drive, 0);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+		SELECT_MASK(drive, 0);
+		printk("%s: CHECK for good STATUS\n", drive->name);
+		return 0;
+	}
+	local_irq_save(flags);
+	SELECT_MASK(drive, 0);
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id) {
+		local_irq_restore(flags);
+		return 0;
+	}
+	ata_input_data(drive, id, SECTOR_WORDS);
+	(void) hwif->INB(IDE_STATUS_REG);	/* clear drive IRQ */
+	local_irq_enable();
+	local_irq_restore(flags);
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+
+	return 1;
+#endif
+}
+
+EXPORT_SYMBOL(ide_driveid_update);
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	int	i, error	= 1;
+	u8 stat;
+
+//	while (HWGROUP(drive)->busy)
+//		ide_delay_50ms();
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	hwif->ide_dma_host_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(speed, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		local_irq_set(flags);
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (speed >= XFER_SW_DMA_0)
+		hwif->ide_dma_host_on(drive);
+	else
+		hwif->ide_dma_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+	return error;
+}
+
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+
+/*
+ * 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 ide_timer_expiry() handler later on).
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	spin_lock_irqsave(&ide_lock, flags);
+	if (hwgroup->handler != NULL) {
+		printk("%s: ide_set_handler: handler not null; "
+			"old=%p, new=%p\n",
+			drive->name, hwgroup->handler, handler);
+	}
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_set_handler);
+
+
+/* needed below */
+ide_startstop_t do_reset1 (ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
+
+	SELECT_DRIVE(drive);
+	udelay (10);
+
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		printk("%s: ATAPI reset complete\n", drive->name);
+	} else {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		/* end of polling */
+		hwgroup->poll_timeout = 0;
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n",
+				drive->name, stat);
+		/* do it the old fashioned way */
+		return do_reset1(drive, 1);
+	}
+	/* done polling */
+	hwgroup->poll_timeout = 0;
+	return ide_stopped;
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 tmp;
+
+	if (hwif->reset_poll != NULL) {
+		if (hwif->reset_poll(drive)) {
+			printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+				hwif->name, drive->name);
+			return ide_stopped;
+		}
+	}
+
+	if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+		drive->failures++;
+	} else  {
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+			printk("success\n");
+			drive->failures = 0;
+		} else {
+			drive->failures++;
+#if FANCY_STATUS_DUMPS
+			printk("master: ");
+			switch (tmp & 0x7f) {
+				case 1: printk("passed");
+					break;
+				case 2: printk("formatter device error");
+					break;
+				case 3: printk("sector buffer error");
+					break;
+				case 4: printk("ECC circuitry error");
+					break;
+				case 5: printk("controlling MPU error");
+					break;
+				default:printk("error (0x%02x?)", tmp);
+			}
+			if (tmp & 0x80)
+				printk("; slave: failed");
+			printk("\n");
+#else
+			printk("failed\n");
+#endif /* FANCY_STATUS_DUMPS */
+		}
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
+}
+
+void check_dma_crc (ide_drive_t *drive)
+{
+	if (drive->crc_count) {
+		(void) HWIF(drive)->ide_dma_off_quietly(drive);
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+		if (drive->current_speed >= XFER_SW_DMA_0)
+			(void) HWIF(drive)->ide_dma_on(drive);
+	} else {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+}
+
+void pre_reset (ide_drive_t *drive)
+{
+	if (drive->driver != NULL)
+		DRIVER(drive)->pre_reset(drive);
+
+	if (!drive->keep_settings) {
+		if (drive->using_dma) {
+			check_dma_crc(drive);
+		} else {
+			drive->unmask = 0;
+			drive->io_32bit = 0;
+		}
+		return;
+	}
+	if (drive->using_dma)
+		check_dma_crc(drive);
+
+	if (HWIF(drive)->pre_reset != NULL)
+		HWIF(drive)->pre_reset(drive);
+
+}
+
+/*
+ * do_reset1() 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 which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * 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.
+ */
+ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+{
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	local_irq_save(flags);
+
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media != ide_disk && !do_not_try_atapi) {
+		pre_reset(drive);
+		SELECT_DRIVE(drive);
+		udelay (20);
+		hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+		local_irq_restore(flags);
+		return ide_started;
+	}
+
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		pre_reset(&hwif->drives[unit]);
+
+#if OK_TO_RESET_CONTROLLER
+	if (!IDE_CONTROL_REG) {
+		local_irq_restore(flags);
+		return ide_stopped;
+	}
+
+# if 0
+        {
+		u8 control = hwif->INB(IDE_CONTROL_REG);
+		control |= 0x04;
+		hwif->OUTB(control,IDE_CONTROL_REG);
+		udelay(30);
+		control &= 0xFB;
+		hwif->OUTB(control, IDE_CONTROL_REG);
+	}
+# else
+	/*
+	 * 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.
+	 */
+	/* set SRST and nIEN */
+	hwif->OUTB(drive->ctl|6,IDE_CONTROL_REG);
+	/* more than enough time */
+	udelay(10);
+	if (drive->quirk_list == 2) {
+		/* clear SRST and nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	} else {
+		/* clear SRST, leave nIEN */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+	}
+	/* more than enough time */
+	udelay(10);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+# endif
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL) {
+		hwif->resetproc(drive);
+
+# if 0
+		if (drive->failures) {
+			local_irq_restore(flags);
+			return ide_stopped;
+		}
+# endif
+	}
+
+#endif	/* OK_TO_RESET_CONTROLLER */
+
+	local_irq_restore(flags);
+	return ide_started;
+}
+
+#if 0
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	return do_reset1(drive, 0);
+}
+#else
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	ide_startstop_t start_stop = ide_started;
+# if 0
+        u8 tmp_dma	= drive->using_dma;
+        u8 cspeed	= drive->current_speed;
+	u8 unmask	= drive->unmask;
+# endif
+
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long flags;
+		spin_lock_irqsave(&ide_lock, flags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&ide_lock, flags);
+	}
+
+	start_stop = do_reset1(drive, 0);
+# if 0
+	/*
+	 * check for suspend-spindown flag,
+	 * to attempt a restart or spinup of device.
+	 */
+	if (drive->suspend_reset) {
+		/*
+		 * APM WAKE UP todo !!
+		 * int nogoodpower = 1;
+		 * while(nogoodpower) {
+		 * 	check_power1() or check_power2()
+		 * 	nogoodpower = 0;
+		 * }
+		 * HWIF(drive)->multiproc(drive);
+		 */
+# endif
+
+	return start_stop;
+}
+#endif
+
+EXPORT_SYMBOL(ide_do_reset);
+
diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ide-lib.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,188 @@
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+/*
+ *	IDE library routines. These are plug in code that most 
+ *	drivers can use but occasionally may be weird enough
+ *	to want to do their own thing with
+ *
+ *	Add common non I/O op stuff here. Make sure it has proper
+ *	kernel-doc function headers or your patch will be rejected
+ */
+ 
+
+/**
+ *	ide_xfer_verbose	-	return IDE mode names
+ *	@xfer_rate: rate to name
+ *
+ *	Returns a constant string giving the name of the mode
+ *	requested.
+ */
+
+char *ide_xfer_verbose (u8 xfer_rate)
+{
+        switch(xfer_rate) {
+                case XFER_UDMA_7:	return("UDMA 7");
+                case XFER_UDMA_6:	return("UDMA 6");
+                case XFER_UDMA_5:	return("UDMA 5");
+                case XFER_UDMA_4:	return("UDMA 4");
+                case XFER_UDMA_3:	return("UDMA 3");
+                case XFER_UDMA_2:	return("UDMA 2");
+                case XFER_UDMA_1:	return("UDMA 1");
+                case XFER_UDMA_0:	return("UDMA 0");
+                case XFER_MW_DMA_2:	return("MW DMA 2");
+                case XFER_MW_DMA_1:	return("MW DMA 1");
+                case XFER_MW_DMA_0:	return("MW DMA 0");
+                case XFER_SW_DMA_2:	return("SW DMA 2");
+                case XFER_SW_DMA_1:	return("SW DMA 1");
+                case XFER_SW_DMA_0:	return("SW DMA 0");
+                case XFER_PIO_4:	return("PIO 4");
+                case XFER_PIO_3:	return("PIO 3");
+                case XFER_PIO_2:	return("PIO 2");
+                case XFER_PIO_1:	return("PIO 1");
+                case XFER_PIO_0:	return("PIO 0");
+                case XFER_PIO_SLOW:	return("PIO SLOW");
+                default:		return("XFER ERROR");
+        }
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ *	ide_dma_speed	-	compute DMA speed
+ *	@drive: drive
+ *	@mode; intended mode
+ *
+ *	Checks the drive capabilities and returns the speed to use
+ *	for the transfer. Returns -1 if the requested mode is unknown
+ *	(eg PIO)
+ */
+ 
+u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+{
+	struct hd_driveid *id   = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 speed = 0;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return 0;
+
+	switch(mode) {
+		case 0x04:
+			if ((id->dma_ultra & 0x0040) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if ((id->dma_ultra & 0x0020) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if ((id->dma_ultra & 0x0010) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_4; break; }
+			if ((id->dma_ultra & 0x0008) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if ((id->dma_ultra & 0x0004) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_2; break; }
+			if ((id->dma_ultra & 0x0002) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_1; break; }
+			if ((id->dma_ultra & 0x0001) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if ((id->dma_mword & 0x0004) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_2; break; }
+			if ((id->dma_mword & 0x0002) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_1; break; }
+			if ((id->dma_mword & 0x0001) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_0; break; }
+			if ((id->dma_1word & 0x0004) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_2; break; }
+			if ((id->dma_1word & 0x0002) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_1; break; }
+			if ((id->dma_1word & 0x0001) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_0; break; }
+	}
+
+//	printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+//		__FUNCTION__, drive->name, mode, speed);
+
+	return speed;
+}
+
+EXPORT_SYMBOL(ide_dma_speed);
+
+
+/**
+ *	ide_rate_filter		-	return best speed for mode
+ *	@mode: modes available
+ *	@speed: desired speed
+ *
+ *	Given the available DMA/UDMA mode this function returns
+ *	the best available speed at or below the speed requested.
+ */
+
+u8 ide_rate_filter (u8 mode, u8 speed) 
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	static u8 speed_max[] = {
+		XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
+		XFER_UDMA_5, XFER_UDMA_6
+	};
+
+//	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+
+	/* So that we remember to update this if new modes appear */
+	if (mode > 4)
+		BUG();
+	return min(speed, speed_max[mode]);
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	return min(speed, XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+EXPORT_SYMBOL(ide_rate_filter);
+
+int ide_dma_enable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	return ((int)	((((id->dma_ultra >> 8) & hwif->ultra_mask) ||
+			  ((id->dma_mword >> 8) & hwif->mwdma_mask) ||
+			  ((id->dma_1word >> 8) & hwif->swdma_mask)) ? 1 : 0));
+}
+
+EXPORT_SYMBOL(ide_dma_enable);
diff -Nru a/drivers/ide/ide-m8xx.c b/drivers/ide/ide-m8xx.c
--- a/drivers/ide/ide-m8xx.c	Sun Sep 15 19:20:24 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,857 +0,0 @@
-/*
- *  linux/drivers/ide/ide-m8xx.c
- *
- *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
- *  Modified for direct IDE interface
- *	by Thomas Lange, thomas@corelatus.com
- *  Modified for direct IDE interface on 8xx without using the PCMCIA
- *  controller
- *	by Steven.Scholz@imc-berlin.de
- *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
- *	by Mathew Locke <mattl@mvista.com>
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/bootmem.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-#include <asm/8xx_immap.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-static int identify  (volatile unsigned char *p);
-static void print_fixed (volatile unsigned char *p);
-static void print_funcid (int func);
-static int check_ide_device (unsigned long base);
-
-static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio);
-
-typedef	struct ide_ioport_desc {
-	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
-	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
-	int		irq;			/* IRQ				*/
-} ide_ioport_desc_t;
-
-ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
-#ifdef IDE0_BASE_OFFSET
-	{ IDE0_BASE_OFFSET,
-	    {
-		IDE0_DATA_REG_OFFSET,
-		IDE0_ERROR_REG_OFFSET,
-		IDE0_NSECTOR_REG_OFFSET,
-		IDE0_SECTOR_REG_OFFSET,
-		IDE0_LCYL_REG_OFFSET,
-		IDE0_HCYL_REG_OFFSET,
-		IDE0_SELECT_REG_OFFSET,
-		IDE0_STATUS_REG_OFFSET,
-		IDE0_CONTROL_REG_OFFSET,
-		IDE0_IRQ_REG_OFFSET,
-	    },
-	    IDE0_INTERRUPT,
-	},
-#ifdef IDE1_BASE_OFFSET
-	{ IDE1_BASE_OFFSET,
-	    {
-		IDE1_DATA_REG_OFFSET,
-		IDE1_ERROR_REG_OFFSET,
-		IDE1_NSECTOR_REG_OFFSET,
-		IDE1_SECTOR_REG_OFFSET,
-		IDE1_LCYL_REG_OFFSET,
-		IDE1_HCYL_REG_OFFSET,
-		IDE1_SELECT_REG_OFFSET,
-		IDE1_STATUS_REG_OFFSET,
-		IDE1_CONTROL_REG_OFFSET,
-		IDE1_IRQ_REG_OFFSET,
-	    },
-	    IDE1_INTERRUPT,
-	},
-#endif /* IDE1_BASE_OFFSET */
-#endif	/* IDE0_BASE_OFFSET */
-};
-
-ide_pio_timings_t ide_pio_clocks[6];
-int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
-
-/*
- * Warning: only 1 (ONE) PCMCIA slot supported here,
- * which must be correctly initialized by the firmware (PPCBoot).
- */
-static int _slot_ = -1;			/* will be read from PCMCIA registers   */
-
-/* Make clock cycles and always round up */
-#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
-
-
-
-/*
- * IDE stuff.
- */
-static int
-m8xx_ide_default_irq(ide_ioreg_t base)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	if (base >= MAX_HWIFS)
-		return 0;
-
-	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
-	
-	return (ioport_dsc[base].irq);
-#else
-        return 9;
-#endif
-}
-
-static ide_ioreg_t
-m8xx_ide_default_io_base(int index)
-{
-        return index;
-}
-
-#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
-
-/*
- * The TQM850L hardware has two pins swapped! Grrrrgh!
- */
-#ifdef	CONFIG_TQM850L
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
-#else
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
-#endif
-
-#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
-#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
-#endif
-
-/*
- * See include/linux/ide.h for definition of hw_regs_t (p, base)
- */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
- */
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-static void
-m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	typedef struct {
-		ulong br;
-		ulong or;
-	} pcmcia_win_t;
-	volatile pcmcia_win_t *win;
-	volatile pcmconf8xx_t *pcmp;
-
-	uint *pgcrx;
-	u32 pcmcia_phy_base;
-	u32 pcmcia_phy_end;
-	static unsigned long pcmcia_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	if (!pcmcia_base) {
-                /*
-                 * Read out PCMCIA registers. Since the reset values
-                 * are undefined, we sure hope that they have been
-                 * set up by firmware
-		 */
-
-		/* Scan all registers for valid settings */
-		pcmcia_phy_base = 0xFFFFFFFF;
-		pcmcia_phy_end = 0;
-		/* br0 is start of brX and orX regs */
-		win = (pcmcia_win_t *) \
-			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
-		for (i = 0; i < 8; i++) {
-			if (win->or & 1) {	/* This bank is marked as valid */
-				if (win->br < pcmcia_phy_base) {
-					pcmcia_phy_base = win->br;
-				}
-				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
-					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
-				}
-				/* Check which slot that has been defined */
-				_slot_ = (win->or >> 2) & 1;
-
-			}					/* Valid bank */
-			win++;
-		}						/* for */
-
-		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
-			'A' + _slot_,
-			pcmcia_phy_base, pcmcia_phy_end,
-			pcmcia_phy_end - pcmcia_phy_base);
-
-		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
-						   pcmcia_phy_end-pcmcia_phy_base);
-
-#ifdef DEBUG
-		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
-#endif
-		/* Compute clock cycles for PIO timings */
-		for (i=0; i<6; ++i) {
-			bd_t	*binfo = (bd_t *)__res;
-
-			hold_time[i]   =
-				PCMCIA_MK_CLKS (hold_time[i],
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].setup_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].active_time =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].cycle_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
-						binfo->bi_busfreq);
-#if 0
-			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
-				i,
-				ide_pio_clocks[i].setup_time,
-				ide_pio_clocks[i].active_time,
-				ide_pio_clocks[i].hold_time,
-				ide_pio_clocks[i].cycle_time,
-				ide_pio_timings[i].setup_time,
-				ide_pio_timings[i].active_time,
-				ide_pio_timings[i].hold_time,
-				ide_pio_timings[i].cycle_time);
-#endif
-		}
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	if (_slot_ == -1) {
-		printk ("PCMCIA slot has not been defined! Using A as default\n");
-		_slot_ = 0;
-	}
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-
-#ifdef DEBUG
-	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
-		pcmp->pcmc_pipr,
-		'A' + _slot_,
-		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
-#endif /* DEBUG */
-
-	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
-		printk ("No card in slot %c: PIPR=%08x\n",
-			'A' + _slot_, (u32) pcmp->pcmc_pipr);
-		return;		/* No card in slot */
-	}
-
-	check_ide_device (pcmcia_base);
-
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-
-	base = pcmcia_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-			pcmcia_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-#ifdef CONFIG_IDE_8xx_PCCARD
-		unsigned int reg;
-
-		*irq = ioport_dsc[data_port].irq;
-		if (_slot_)
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
-		else
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
-
-		reg = *pgcrx;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
-		*pgcrx = reg;
-#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
-		*irq = ioport_dsc[data_port].irq;
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
-					(0x80000000 >> ioport_dsc[data_port].irq);
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-	/* Make sure we dont get garbage irq */
-	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
-
-	/* Enable falling edge irq */
-	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
-#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
- * MPC8xx's internal PCMCIA interface
- */
-#if defined(CONFIG_IDE_EXT_DIRECT)
-void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	u32 ide_phy_base;
-	u32 ide_phy_end;
-	static unsigned long ide_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	if (!ide_base) {
-
-		/* TODO:
-		 * - add code to read ORx, BRx
-		 */
-		ide_phy_base = CFG_ATA_BASE_ADDR;
-		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
-
-		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
-			ide_phy_base, ide_phy_end,
-			ide_phy_end - ide_phy_base);
-		
-		ide_base=(unsigned long)ioremap(ide_phy_base,
-						ide_phy_end-ide_phy_base);
-
-#ifdef DEBUG
-		printk ("IDE virt base: %08lx\n", ide_base);
-#endif
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	base = ide_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-		ide_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-		/* direct connected IDE drive, i.e. external IRQ */
-		*irq = ioport_dsc[data_port].irq;
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
-			(0x80000000 >> ioport_dsc[data_port].irq);
-}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
-
-#endif	/* CONFIG_IDE_8xx_DIRECT */
-
-
-/* -------------------------------------------------------------------- */
-
-
-/* PCMCIA Timing */
-#ifndef	PCMCIA_SHT
-#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
-#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
-#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
-#endif
-
-
-/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	volatile pcmconf8xx_t	*pcmp;
-	ulong timing, mask, reg;
-#endif
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-
-#if 1
-	printk("%s[%d] %s: best PIO mode: %d\n",
-		__FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
-
-	timing  = PCMCIA_SHT(hold_time[pio]  )
-		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
-		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
-		;
-
-#if 1
-	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
-#endif
-	if ((reg = pcmp->pcmc_por0 & mask) != 0)
-		pcmp->pcmc_por0 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por1 & mask) != 0)
-		pcmp->pcmc_por1 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por2 & mask) != 0)
-		pcmp->pcmc_por2 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por3 & mask) != 0)
-		pcmp->pcmc_por3 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por4 & mask) != 0)
-		pcmp->pcmc_por4 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por5 & mask) != 0)
-		pcmp->pcmc_por5 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por6 & mask) != 0)
-		pcmp->pcmc_por6 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por7 & mask) != 0)
-		pcmp->pcmc_por7 = reg | timing;
-
-#elif defined(CONFIG_IDE_EXT_DIRECT)
-
-	printk("%s[%d] %s: not implemented yet!\n",
-		__FILE__,__LINE__,__FUNCTION__);
-#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
-}
-
-static void
-ide_interrupt_ack (void *dev)
-{
-#ifdef CONFIG_IDE_8xx_PCCARD
-	u_int pscr, pipr;
-
-#if (PCMCIA_SOCKETS_NO == 2)
-	u_int _slot_;
-#endif
-
-	/* get interrupt sources */
-
-	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
-	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
-
-	/*
-	 * report only if both card detect signals are the same
-	 * not too nice done,
-	 * we depend on that CD2 is the bit to the left of CD1...
-	 */
-
-	if(_slot_==-1){
-	  printk("PCMCIA slot has not been defined! Using A as default\n");
-	  _slot_=0;
-	}
-
-	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
-	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
-	  printk ("card detect interrupt\n");
-	}
-	/* clear the interrupt sources */
-	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
-
-#else /* ! CONFIG_IDE_8xx_PCCARD */
-	/*
-	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
-	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
-	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
-	 * The interrupt is handled somewhere else.	-- Steven
-	 */
-#endif /* CONFIG_IDE_8xx_PCCARD */
-}
-
-
-
-/*
- * CIS Tupel codes
- */
-#define CISTPL_NULL		0x00
-#define CISTPL_DEVICE		0x01
-#define CISTPL_LONGLINK_CB	0x02
-#define CISTPL_INDIRECT		0x03
-#define CISTPL_CONFIG_CB	0x04
-#define CISTPL_CFTABLE_ENTRY_CB 0x05
-#define CISTPL_LONGLINK_MFC	0x06
-#define CISTPL_BAR		0x07
-#define CISTPL_PWR_MGMNT	0x08
-#define CISTPL_EXTDEVICE	0x09
-#define CISTPL_CHECKSUM		0x10
-#define CISTPL_LONGLINK_A	0x11
-#define CISTPL_LONGLINK_C	0x12
-#define CISTPL_LINKTARGET	0x13
-#define CISTPL_NO_LINK		0x14
-#define CISTPL_VERS_1		0x15
-#define CISTPL_ALTSTR		0x16
-#define CISTPL_DEVICE_A		0x17
-#define CISTPL_JEDEC_C		0x18
-#define CISTPL_JEDEC_A		0x19
-#define CISTPL_CONFIG		0x1a
-#define CISTPL_CFTABLE_ENTRY	0x1b
-#define CISTPL_DEVICE_OC	0x1c
-#define CISTPL_DEVICE_OA	0x1d
-#define CISTPL_DEVICE_GEO	0x1e
-#define CISTPL_DEVICE_GEO_A	0x1f
-#define CISTPL_MANFID		0x20
-#define CISTPL_FUNCID		0x21
-#define CISTPL_FUNCE		0x22
-#define CISTPL_SWIL		0x23
-#define CISTPL_END		0xff
-
-/*
- * CIS Function ID codes
- */
-#define CISTPL_FUNCID_MULTI	0x00
-#define CISTPL_FUNCID_MEMORY	0x01
-#define CISTPL_FUNCID_SERIAL	0x02
-#define CISTPL_FUNCID_PARALLEL	0x03
-#define CISTPL_FUNCID_FIXED	0x04
-#define CISTPL_FUNCID_VIDEO	0x05
-#define CISTPL_FUNCID_NETWORK	0x06
-#define CISTPL_FUNCID_AIMS	0x07
-#define CISTPL_FUNCID_SCSI	0x08
-
-/*
- * Fixed Disk FUNCE codes
- */
-#define CISTPL_IDE_INTERFACE	0x01
-
-#define CISTPL_FUNCE_IDE_IFACE	0x01
-#define CISTPL_FUNCE_IDE_MASTER	0x02
-#define CISTPL_FUNCE_IDE_SLAVE	0x03
-
-/* First feature byte */
-#define CISTPL_IDE_SILICON	0x04
-#define CISTPL_IDE_UNIQUE	0x08
-#define CISTPL_IDE_DUAL		0x10
-
-/* Second feature byte */
-#define CISTPL_IDE_HAS_SLEEP	0x01
-#define CISTPL_IDE_HAS_STANDBY	0x02
-#define CISTPL_IDE_HAS_IDLE	0x04
-#define CISTPL_IDE_LOW_POWER	0x08
-#define CISTPL_IDE_REG_INHIBIT	0x10
-#define CISTPL_IDE_HAS_INDEX	0x20
-#define CISTPL_IDE_IOIS16	0x40
-
-
-/* -------------------------------------------------------------------- */
-
-
-#define	MAX_TUPEL_SZ	512
-#define MAX_FEATURES	4
-
-static int check_ide_device (unsigned long base)
-{
-	volatile unsigned char *ident = NULL;
-	volatile unsigned char *feature_p[MAX_FEATURES];
-	volatile unsigned char *p, *start;
-	int n_features = 0;
-	unsigned char func_id = ~0;
-	unsigned char code, len;
-	unsigned short config_base = 0;
-	int found = 0;
-	int i;
-
-#ifdef DEBUG
-	printk ("PCMCIA MEM: %08lX\n", base);
-#endif
-	start = p = (volatile unsigned char *) base;
-
-	while ((p - start) < MAX_TUPEL_SZ) {
-
-		code = *p; p += 2;
-
-		if (code == 0xFF) { /* End of chain */
-			break;
-		}
-
-		len = *p; p += 2;
-#ifdef	DEBUG_PCMCIA
-		{ volatile unsigned char *q = p;
-			printk ("\nTuple code %02x  length %d\n\tData:",
-				code, len);
-
-			for (i = 0; i < len; ++i) {
-				printk (" %02x", *q);
-				q+= 2;
-			}
-		}
-#endif	/* DEBUG_PCMCIA */
-		switch (code) {
-		case CISTPL_VERS_1:
-			ident = p + 4;
-			break;
-		case CISTPL_FUNCID:
-			func_id = *p;
-			break;
-		case CISTPL_FUNCE:
-			if (n_features < MAX_FEATURES)
-				feature_p[n_features++] = p;
-			break;
-		case CISTPL_CONFIG:
-			config_base = (*(p+6) << 8) + (*(p+4));
-		default:
-			break;
-		}
-		p += 2 * len;
-	}
-
-	found = identify (ident);
-
-	if (func_id != ((unsigned char)~0)) {
-		print_funcid (func_id);
-
-		if (func_id == CISTPL_FUNCID_FIXED)
-			found = 1;
-		else
-			return (1);	/* no disk drive */
-	}
-
-	for (i=0; i<n_features; ++i) {
-		print_fixed (feature_p[i]);
-	}
-
-	if (!found) {
-		printk ("unknown card type\n");
-		return (1);
-	}
-
-	/* set level mode irq and I/O mapped device in config reg*/
-	*((unsigned char *)(base + config_base)) = 0x41;
-
-	return (0);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_funcid (int func)
-{
-	switch (func) {
-	case CISTPL_FUNCID_MULTI:
-		printk (" Multi-Function");
-		break;
-	case CISTPL_FUNCID_MEMORY:
-		printk (" Memory");
-		break;
-	case CISTPL_FUNCID_SERIAL:
-		printk (" Serial Port");
-		break;
-	case CISTPL_FUNCID_PARALLEL:
-		printk (" Parallel Port");
-		break;
-	case CISTPL_FUNCID_FIXED:
-		printk (" Fixed Disk");
-		break;
-	case CISTPL_FUNCID_VIDEO:
-		printk (" Video Adapter");
-		break;
-	case CISTPL_FUNCID_NETWORK:
-		printk (" Network Adapter");
-		break;
-	case CISTPL_FUNCID_AIMS:
-		printk (" AIMS Card");
-		break;
-	case CISTPL_FUNCID_SCSI:
-		printk (" SCSI Adapter");
-		break;
-	default:
-		printk (" Unknown");
-		break;
-	}
-	printk (" Card\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_fixed (volatile unsigned char *p)
-{
-	if (p == NULL)
-		return;
-
-	switch (*p) {
-	case CISTPL_FUNCE_IDE_IFACE:
-	    {   unsigned char iface = *(p+2);
-
-		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
-		printk (" interface ");
-		break;
-	    }
-	case CISTPL_FUNCE_IDE_MASTER:
-	case CISTPL_FUNCE_IDE_SLAVE:
-	    {   unsigned char f1 = *(p+2);
-		unsigned char f2 = *(p+4);
-
-		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
-
-		if (f1 & CISTPL_IDE_UNIQUE)
-			printk (" [unique]");
-
-		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
-
-		if (f2 & CISTPL_IDE_HAS_SLEEP)
-			printk (" [sleep]");
-
-		if (f2 & CISTPL_IDE_HAS_STANDBY)
-			printk (" [standby]");
-
-		if (f2 & CISTPL_IDE_HAS_IDLE)
-			printk (" [idle]");
-
-		if (f2 & CISTPL_IDE_LOW_POWER)
-			printk (" [low power]");
-
-		if (f2 & CISTPL_IDE_REG_INHIBIT)
-			printk (" [reg inhibit]");
-
-		if (f2 & CISTPL_IDE_HAS_INDEX)
-			printk (" [index]");
-
-		if (f2 & CISTPL_IDE_IOIS16)
-			printk (" [IOis16]");
-
-		break;
-	    }
-	}
-	printk ("\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-#define MAX_IDENT_CHARS		64
-#define	MAX_IDENT_FIELDS	4
-
-static unsigned char *known_cards[] = {
-	"ARGOSY PnPIDE D5",
-	NULL
-};
-
-static int identify  (volatile unsigned char *p)
-{
-	unsigned char id_str[MAX_IDENT_CHARS];
-	unsigned char data;
-	unsigned char *t;
-	unsigned char **card;
-	int i, done;
-
-	if (p == NULL)
-		return (0);	/* Don't know */
-
-	t = id_str;
-	done =0;
-
-	for (i=0; i<=4 && !done; ++i, p+=2) {
-		while ((data = *p) != '\0') {
-			if (data == 0xFF) {
-				done = 1;
-				break;
-			}
-			*t++ = data;
-			if (t == &id_str[MAX_IDENT_CHARS-1]) {
-				done = 1;
-				break;
-			}
-			p += 2;
-		}
-		if (!done)
-			*t++ = ' ';
-	}
-	*t = '\0';
-	while (--t > id_str) {
-		if (*t == ' ')
-			*t = '\0';
-		else
-			break;
-	}
-	printk ("Card ID: %s\n", id_str);
-
-	for (card=known_cards; *card; ++card) {
-		if (strcmp(*card, id_str) == 0) {	/* found! */
-			return (1);
-		}
-	}
-
-	return (0);	/* don't know */
-}
-
-void m8xx_ide_init(void)
-{
-	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
-	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
-	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
-}
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Sun Sep 15 19:20:12 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,992 +0,0 @@
-/*
- *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
- *
- *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- *  This module provides support for automatic detection and
- *  configuration of all PCI IDE interfaces present in a system.  
- */
-
-/*
- * Chipsets that are on the IDE_IGNORE list because of problems of not being
- * set at compile time.
- *
- * CONFIG_BLK_DEV_PDC202XX
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
-#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
-#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
-#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
-#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
-#define DEVID_PIIX4E	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
-#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
-#define DEVID_PIIX4U	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
-#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
-#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_PIIX4U3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_PIIX4U4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_PIIX4U5	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_PIIX4U6	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
-#define DEVID_PIIX4U7	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
-#define DEVID_PIIX4U8   ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
-#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
-#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
-#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
-#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
-#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
-#define DEVID_PDC20263	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263})
-#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
-#define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
-#define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
-#define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
-#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
-#define DEVID_PDC20271	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271})
-#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
-#define DEVID_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
-#define DEVID_PDC20277	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277})
-#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
-#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
-#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
-#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
-#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
-#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
-#define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
-#define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
-#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
-#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
-#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
-#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
-#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
-#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
-#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
-#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
-#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
-#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
-#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
-#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
-#define DEVID_AEC6280	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865})
-#define DEVID_AEC6880	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP865R})
-#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
-#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
-#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
-#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
-#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
-#define DEVID_HPT372	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT372})
-#define DEVID_HPT302	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT302})
-#define DEVID_HPT371	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT371}) 
-#define DEVID_HPT374	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT374})
-#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
-#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
-#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
-#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
-#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
-#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
-#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_OPUS_7441})
-#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
-#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
-#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
-#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
-#define DEVID_CSB6	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE})
-#define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
-
-#define	IDE_IGNORE	((void *)-1)
-#define IDE_NO_DRIVER	((void *)-2)
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern void fixup_device_aec6x80(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
-#define FIXUP_AEC62XX	&fixup_device_aec6x80
-#define PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#define FIXUP_AEC62XX	NULL
-#define PCI_AEC62XX	NULL
-#define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	IDE_NO_DRIVER
-#define DMA_AEC62XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern void fixup_device_ali15x3(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
-#define FIXUP_ALI15X3	&fixup_device_ali15x3
-#define PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#define FIXUP_ALI15X3	NULL
-#define PCI_ALI15X3	NULL
-#define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	IDE_NO_DRIVER
-#define DMA_ALI15X3	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern void fixup_device_amd74xx(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
-#define FIXUP_AMD74XX	&fixup_device_amd74xx
-#define PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#define FIXUP_AMD74XX	NULL
-#define PCI_AMD74XX	NULL
-#define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	IDE_NO_DRIVER
-#define DMA_AMD74XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
-#define PCI_CMD64X	&pci_init_cmd64x
-#define ATA66_CMD64X	&ata66_cmd64x
-#define INIT_CMD64X	&ide_init_cmd64x
-#else
-#define PCI_CMD64X	NULL
-#define ATA66_CMD64X	NULL
-#ifdef __sparc_v9__
-#define INIT_CMD64X	IDE_IGNORE
-#else
-#define INIT_CMD64X	IDE_NO_DRIVER
-#endif
-#endif
-
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern void fixup_device_cy82c693(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
-extern void ide_init_cy82c693(ide_hwif_t *);
-#define FIXUP_CY82C693	&fixup_device_cy82c693
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#define FIXUP_CY82C693	NULL
-#define PCI_CY82C693	NULL
-#define INIT_CY82C693	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
-extern void ide_init_cs5530(ide_hwif_t *);
-#define PCI_CS5530	&pci_init_cs5530
-#define INIT_CS5530	&ide_init_cs5530
-#else
-#define PCI_CS5530	NULL
-#define INIT_CS5530	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern void fixup_device_hpt343(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
-extern void ide_init_hpt34x(ide_hwif_t *);
-#define FIXUP_HPT34X	&fixup_device_hpt343
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define FIXUP_HPT34X	NULL
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern void fixup_device_hpt366(struct pci_dev *, ide_pci_device_t *);
-extern void fixup_device_hpt374(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
-#define FIXUP_HPT366	&fixup_device_hpt366
-#define FIXUP_HPT374	&fixup_device_hpt374
-#define PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
-#else
-#define FIXUP_HPT366	NULL
-#define FIXUP_HPT374	NULL
-#define PCI_HPT366	NULL
-#define ATA66_HPT366	NULL
-#define INIT_HPT366	IDE_NO_DRIVER
-#define DMA_HPT366	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void fixup_device_opti621(struct pci_dev *, ide_pci_device_t *);
-extern void ide_init_opti621(ide_hwif_t *);
-#define FIXUP_OPTI621	&fixup_device_opti621
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define FIXUP_OPTI621	NULL
-#define INIT_OPTI621	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
-#define PCI_PDCADMA	&pci_init_pdcadma
-#define ATA66_PDCADMA	&ata66_pdcadma
-#define INIT_PDCADMA	&ide_init_pdcadma
-#define DMA_PDCADMA	&ide_dmacapable_pdcadma
-#else
-#define PCI_PDCADMA	IDE_IGNORE
-#define ATA66_PDCADMA	IDE_IGNORE
-#define INIT_PDCADMA	IDE_IGNORE
-#define DMA_PDCADMA	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern void fixup_device_pdc20265(struct pci_dev *, ide_pci_device_t *);
-extern void fixup_device_pdc20270(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
-#define FIXUP_PDC20265	&fixup_device_pdc20265
-#define FIXUP_PDC20270	&fixup_device_pdc20270
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define FIXUP_PDC20265	IDE_IGNORE
-#define FIXUP_PDC20270	IDE_IGNORE
-#define PCI_PDC202XX	IDE_IGNORE
-#define ATA66_PDC202XX	IDE_IGNORE
-#define INIT_PDC202XX	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern void fixup_device_piix(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_piix(struct pci_dev *, const char *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-#define FIXUP_PIIX	&fixup_device_piix
-#define PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define FIXUP_PIIX	NULL
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern void fixup_device_it8172(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
-extern void ide_init_it8172(ide_hwif_t *);
-#define FIXUP_IT8172	&fixup_device_it8172
-#define PCI_IT8172	&pci_init_it8172
-#define ATA66_IT8172	&ata66_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define FIXUP_IT8172	NULL
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
-#endif
-
-#define INIT_SAMURAI	NULL
-
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern void fixup_device_csb6(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
-extern void ide_dmacapable_svwks(ide_hwif_t *, unsigned long);
-#define FIXUP_CSB6	&fixup_device_csb6
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#define DMA_SVWKS	&ide_dmacapable_svwks
-#else
-#define FIXUP_CSB6	NULL
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
-#define DMA_SVWKS	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern void fixup_device_sis5513(struct pci_dev *, ide_pci_device_t *);
-extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
-#define FIXUP_SIS5513	&fixup_device_sis5513
-#define PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#define FIXUP_SIS5513	NULL
-#define PCI_SIS5513	NULL
-#define ATA66_SIS5513	NULL
-#define INIT_SIS5513	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
-extern unsigned int ata66_slc90e66(ide_hwif_t *);
-extern void ide_init_slc90e66(ide_hwif_t *);
-#define PCI_SLC90E66	&pci_init_slc90e66
-#define ATA66_SLC90E66	&ata66_slc90e66
-#define INIT_SLC90E66	&ide_init_slc90e66
-#else
-#define PCI_SLC90E66	NULL
-#define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define PCI_W82C105	&pci_init_sl82c105
-#define DMA_W82C105	&dma_init_sl82c105
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define PCI_W82C105	NULL
-#define DMA_W82C105	NULL
-#define INIT_W82C105	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
-#else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	IDE_NO_DRIVER
-#define DMA_VIA82CXXX	NULL
-#endif
-
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	FIXUP_PIIX,	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4E,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U3,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U4, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U5, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U6,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U7,	"PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U8, "PIIX4",	FIXUP_PIIX,	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	NULL,		PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	NULL,		PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifdef CONFIG_PDC202XX_FORCE
-	{DEVID_PDC20246,"PDC20246",	NULL,		PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-	{DEVID_PDC20263,"PDC20263",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	FIXUP_PDC20265,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-#else /* !CONFIG_PDC202XX_FORCE */
-	{DEVID_PDC20246,"PDC20246",	NULL,		PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20263,"PDC20263",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	FIXUP_PDC20265,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-#endif
-	{DEVID_PDC20268,"PDC20268",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	/*
-	 * Promise used a different PCI ident for the raid card apparently
-	 * to try and prevent Linux detecting it and using our own raid code.
-	 * We want to detect it for the ataraid drivers, so we have to list
-	 * both here..
-	 */
-	{DEVID_PDC20268R,"PDC20270",	FIXUP_PDC20270,	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20269,"PDC20269",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20271,"PDC20271",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20275,"PDC20275",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20276,"PDC20276",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20277,"PDC20277",	NULL,		PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	FIXUP_SIS5513,	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	NULL,		PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	NULL,		PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_CMD648,	"CMD648",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD649,	"CMD649",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD680,	"CMD680",	NULL,		PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	FIXUP_OPTI621,	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	FIXUP_OPTI621,	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	NULL,		PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	NULL,		PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	NULL,		PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_AEC6280,	"AEC6X80",	FIXUP_AEC62XX,	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6880,	"AEC6X80R",	FIXUP_AEC62XX,	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	NULL,		PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	FIXUP_HPT34X,	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	FIXUP_HPT366,	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_HPT372,	"HPT372A",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_HPT302,	"HPT302",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_HPT371,	"HPT371",	NULL,		PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_HPT374,	"HPT374",	FIXUP_HPT374,	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_ALI15X3,	"ALI15X3",	FIXUP_ALI15X3,	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	FIXUP_CY82C693,	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	NULL,		PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	FIXUP_AMD74XX,	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7409,	"AMD7409",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7411,	"AMD7411",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441,	"AMD7441",	FIXUP_AMD74XX,	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_PDCADMA,	"PDCADMA",	NULL,		PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_SLC90E66,"SLC90E66",	NULL,		PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_OSB4,	"SvrWks OSB4",	NULL,		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB5,	"SvrWks CSB5",	NULL,		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	DMA_SVWKS,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB6,	"SvrWks CSB6",	FIXUP_CSB6,	PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	DMA_SVWKS,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	FIXUP_IT8172,	PCI_IT8172,	NULL,		INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
-
-/*
- * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
- * settings of split-mirror pci-config space, place chipset into init-mode,
- * and/or preserve an interrupt if the card is not native ide support.
- */
-static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT366:
-		case PCI_DEVICE_ID_TTI_HPT372:
-		case PCI_DEVICE_ID_TTI_HPT302:
-		case PCI_DEVICE_ID_TTI_HPT371:
-		case PCI_DEVICE_ID_TTI_HPT374:
-		case PCI_DEVICE_ID_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20277:
-	/*
-	 *	case PCI_DEVICE_ID_ARTOP_ATP850UF:
-	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT372
-	 *	case PCI_DEVICE_ID_ARTOP_ATP860:
-	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT302
-	 *	case PCI_DEVICE_ID_ARTOP_ATP860R:
-	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT371
-	 *	case PCI_DEVICE_ID_ARTOP_ATP865:
-	 *		same device ID value as PCI_DEVICE_ID_TTI_HPT374
-	 */
-		case PCI_DEVICE_ID_ARTOP_ATP865R:
-			return dev->irq;
-		default:
-			break;
-	}
-	return 0;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
-{
-	int h;
-	ide_hwif_t *hwif;
-
-	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			printk("%s: port 0x%04lx already claimed by %s\n",
-				name, io_base, hwif->name);
-			return NULL;	/* already claimed */
-		}
-	}
-	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
-	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
-	 *
-	 * Unless there is a bootable card that does not use the standard
-	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
-	 */
-	if (bootable) {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			hwif = &ide_hwifs[h];
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	} else {
-		for (h = 2; h < MAX_HWIFS; ++h) {
-			hwif = ide_hwifs + h;
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	}
-	for (h = 0; h < 2; ++h) {
-		hwif = ide_hwifs + h;
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
-	}
-	printk("%s: too many IDE interfaces, no room in table\n", name);
-	return NULL;
-}
-
-static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
-{
-	byte reg, progif = 0;
-
-	/*
-	 * Place both IDE interfaces into PCI "native" mode:
-	 */
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
-			 (progif & 5) != 5) {
-		if ((progif & 0xa) != 0xa) {
-			printk("%s: device not capable of full "
-				"native PCI mode\n", name);
-			return 1;
-		}
-		printk("%s: placing both ports into native PCI mode\n", name);
-		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
-			return 1;
-		}
-	}
-	/*
-	 * Setup base registers for IDE command/control spaces for each interface:
-	 */
-	for (reg = 0; reg < 4; reg++) {
-		struct resource *res = dev->resource + reg;
-		if ((res->flags & IORESOURCE_IO) == 0)
-			continue;
-		if (!res->start) {
-			printk("%s: Missing I/O address #%d\n", name, reg);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
-	unsigned short pcicmd = 0, tried_config = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
-	unsigned int class_rev;
-	static int secondpdc = 0;
-
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		autodma = 1;
-#endif
-
-	if (d->init_hwif == IDE_NO_DRIVER) {
-		printk(KERN_WARNING "%s: detected chipset, "
-			"but driver not compiled in!\n", d->name);
-		d->init_hwif = NULL;
-	}
-
-	if (pci_enable_device(dev)) {
-		printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
-			"Could not enable device.\n", d->name);
-		return;
-	}
-
-check_if_enabled:
-	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", d->name);
-		return;
-	}
-	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
-		/*
-		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
-		 *  (or possibly the device is using a "legacy header" for IRQs).
-		 * Maybe the user deliberately *disabled* the device,
-		 * but we'll eventually ignore it again if no drives respond.
-		 */
-		if (tried_config++
-		 || ide_setup_pci_baseregs(dev, d->name)
-		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", d->name);
-			return;
-		}
-		autodma = 0;	/* default DMA off if we had to configure it here */
-		goto check_if_enabled;
-	}
-	if (tried_config)
-		printk("%s: device enabled (Linux)\n", d->name);
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	printk("%s: chipset revision %d\n", d->name, class_rev);
-
-	/*
-	 * Can we trust the reported IRQ?
-	 */
-	pciirq = dev->irq;
-	
-	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk("%s: not 100%% native mode: "
-			"will probe irqs later\n", d->name);
-		/*
-		 * This allows offboard ide-pci cards the enable a BIOS,
-		 * verify interrupt settings of split-mirror pci-config
-		 * space, place chipset into init-mode, and/or preserve
-		 * an interrupt if the card is not native ide support.
-		 */
-		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
-	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", d->name);
-		pciirq = 0;
-	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
-		pciirq = 0;
-	} else {
-		if (d->init_chipset)
-			(void) d->init_chipset(dev, d->name);
-#ifdef __sparc__
-		printk("%s: 100%% native mode on irq %s\n",
-		       d->name, __irq_itoa(pciirq));
-#else
-		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
-#endif
-	}
-
-	/*
-	 * Set up the IDE ports
-	 */
-	for (port = 0; port <= 1; ++port) {
-		unsigned long base = 0, ctl = 0;
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller,
-		 * the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled
-		 * by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) &&
-		    (secondpdc++==1) && (port==1)) 
-			goto controller_ok;
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) &&
-		    (secondpdc++==1) && (port==1)) 
-			goto controller_ok;
-			
-		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
-		    (tmp & e->mask) != e->val))
-			continue;	/* port not enabled */
-controller_ok:			
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) &&
-		    (port) && (class_rev < 0x03))
-			return;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) && (port))
-			return;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
-		    (port) && (!(PCI_FUNC(dev->devfn) & 1)))
-			return;
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE ||
-		    (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->resource[(2*port)+1].start;
-			base = dev->resource[2*port].start;
-			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
-			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-				printk("%s: IO baseregs (BIOS) are reported "
-					"as MEM, report to "
-					"<andre@linux-ide.org>.\n", d->name);
-#if 0
-				/*
-				 * FIXME! This really should check that
-				 * it really gets the IO/MEM part right!
-				 */
-				continue;
-#endif
-			}
-		}
-		if ((ctl && !base) || (base && !ctl)) {
-			printk("%s: inconsistent baseregs (BIOS) "
-				"for port %d, skipping\n", d->name, port);
-			continue;
-		}
-		if (!ctl)
-			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		if (!base)
-			base = port ? 0x170 : 0x1f0;	/* use default value */
-		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
-			continue;	/* no room in ide_hwifs[] */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_dev = dev;
-		hwif->pci_devid = d->devid;
-		hwif->channel = port;
-		if (!hwif->irq)
-			hwif->irq = pciirq;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
-				hwif->serialized = 1;
-				mate->serialized = 1;
-			}
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
-			hwif->irq = hwif->channel ? 15 : 14;
-			goto bypass_umc_dma;
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
-			goto bypass_piix_dma;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
-			goto bypass_legacy_dma;
-		if (hwif->udma_four) {
-			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n",
-				d->name);
-		} else {
-			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
-			autodma = 0;
-		if (autodma)
-			hwif->autodma = 1;
-
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20263) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20271) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20277) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6880) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT372) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT302) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT374) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
-		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
-			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
-			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
-				/*
- 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
- 	 			 */
-		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
-					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
-				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
-				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
-					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
-					dma_base = 0;
-				}
-			}
-			if (dma_base) {
-				if (d->dma_init) {
-					d->dma_init(hwif, dma_base);
-				} else {
-					ide_setup_dma(hwif, dma_base, 8);
-				}
-			} else {
-				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
-			}
-		}
-#endif	/* CONFIG_BLK_DEV_IDEDMA */
-bypass_legacy_dma:
-bypass_piix_dma:
-bypass_umc_dma:
-		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-			d->init_hwif(hwif);
-		mate = hwif;
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c.
- * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
- */
-void __init ide_scan_pcidev (struct pci_dev *dev)
-{
-	ide_pci_devid_t		devid;
-	ide_pci_device_t	*d;
-
-	devid.vid = dev->vendor;
-	devid.did = dev->device;
-	for (d = ide_pci_chipsets;
-	     d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
-
-	if (d->init_hwif == IDE_IGNORE)
-		printk("%s: ignored by ide_scan_pci_device() "
-			"(uses own driver)\n", d->name);
-	else if (d->fixup_device)
-		d->fixup_device(dev, d);
-#if 0
-	else if (((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) &&
-		 (!(PCI_FUNC(dev->devfn) & 1)))
-		return;
-#endif
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) &&
-		 (!(PCI_FUNC(dev->devfn) & 1)))
-		return;	/* UM8886A/BF pair */
-	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) ||
-		 (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
-			printk("%s: unknown IDE controller on PCI bus "
-				"%02x device %02x, VID=%04x, DID=%04x\n",
-				d->name, dev->bus->number, dev->devfn,
-				devid.vid, devid.did);
-		else
-			printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-				d->name, dev->bus->number, dev->devfn);
-		ide_setup_pci_device(dev, d);
-	}
-}
-
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev;
-
-	if (!scan_direction) {
-		pci_for_each_dev(dev) {
-			ide_scan_pcidev(dev);
-		}
-	} else {
-		pci_for_each_dev_reverse(dev) {
-			ide_scan_pcidev(dev);
-		}
-	}
-}
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1724 +0,0 @@
-/*
- * linux/drivers/ide/ide-pmac.c
- *
- * Support for IDE interfaces on PowerMacs.
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
- *
- *  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.
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/mediabay.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-#include "ide_modes.h"
-
-extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
-
-#define IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT	500
-
-struct pmac_ide_hwif {
-	ide_ioreg_t			regbase;
-	int				irq;
-	int				kind;
-	int				aapl_bus_id;
-	struct device_node*		node;
-	u32				timings[2];
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* Those fields are duplicating what is in hwif. We currently
-	 * can't use the hwif ones because of some assumptions that are
-	 * beeing done by the generic code about the kind of dma controller
-	 * and format of the dma table. This will have to be fixed though.
-	 */
-	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table_cpu;
-	dma_addr_t			dma_table_dma;
-	struct scatterlist*		sg_table;
-	int				sg_nents;
-	int				sg_dma_direction;
-#endif
-	
-} pmac_ide[MAX_HWIFS] __pmacdata;
-
-static int pmac_ide_count;
-
-enum {
-	controller_ohare,	/* OHare based */
-	controller_heathrow,	/* Heathrow/Paddington */
-	controller_kl_ata3,	/* KeyLargo ATA-3 */
-	controller_kl_ata4,	/* KeyLargo ATA-4 */
-	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG	0x200
-#define IDE_INTERRUPT		0x300
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
-#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- * 
- * 3 Values can be programmed:
- *  - Write data setup, which appears to match the cycle time. They
- *    also call it DIOW setup.
- *  - Ready to pause time (from spec)
- *  - Address setup. That one is weird. I don't see where exactly
- *    it fits in UDMA cycles, I got it's name from an obscure piece
- *    of commented out code in Darwin. They leave it to 0, we do as
- *    well, despite a comment that would lead to think it has a
- *    min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads. I can't explain that, I tried it and it broke everything
- * here.
- */
-#define TR_66_UDMA_MASK			0xfff00000
-#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT	29
-#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT	25
-#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT	21
-#define TR_66_MDMA_MASK			0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT	15
-#define TR_66_MDMA_ACCESS_MASK		0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT		10
-#define TR_66_PIO_MASK			0x000003ff
-#define TR_66_PIO_RECOVERY_MASK		0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT	5
-#define TR_66_PIO_ACCESS_MASK		0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT		0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- * 
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK			0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT	16
-#define TR_33_MDMA_ACCESS_MASK		0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT		11
-#define TR_33_MDMA_HALFTICK		0x00200000
-#define TR_33_PIO_MASK			0x000007ff
-#define TR_33_PIO_E			0x00000400
-#define TR_33_PIO_RECOVERY_MASK		0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT	5
-#define TR_33_PIO_ACCESS_MASK		0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT		0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA			0x80000000
-#define IDE_INTR_DEVICE			0x40000000
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-/* Rounded Multiword DMA timings
- * 
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
-	int	accessTime;
-	int	recoveryTime;
-	int	cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  75,  75, 150 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 150, 150, 300 },
-    { 120, 120, 240 },
-    {  90, 120, 210 },
-    {  90,  90, 180 },
-    {  90,  60, 150 },
-    {  90,  30, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  90,  75, 165 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-/* Ultra DMA timings (rounded) */
-struct {
-	int	addrSetup; /* ??? */
-	int	rdy2pause;
-	int	wrDataSetup;
-} udma_timings[] __pmacdata =
-{
-    {   0, 180,  120 },	/* Mode 0 */
-    {   0, 150,  90 },	/*      1 */
-    {   0, 120,  60 },	/*      2 */
-    {   0, 90,   45 },	/*      3 */
-    {   0, 90,   30 }	/*      4 */
-};
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS		256
-
-/* Wait 2s for disk to answer on IDE bus after
- * enable operation.
- * NOTE: There is at least one case I know of a disk that needs about 10sec
- *       before anwering on the bus. I beleive we could add a kernel command
- *       line arg to override this delay for such cases.
- */
-#define IDE_WAKEUP_DELAY_MS	2000
-
-static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier idepmac_sleep_notifier = {
-	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *);
-static struct notifier_block pmac_ide_reboot_notifier = {
-	pmac_ide_notify_reboot,
-	NULL,
-	0
-};
-
-static int __pmac
-pmac_ide_find(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_ioreg_t base;
-	int i;
-	
-	for (i=0; i<pmac_ide_count; i++) {
-		base = pmac_ide[i].regbase;
-		if (base && base == hwif->io_ports[0])
-			return i;
-	}
-	return -1;
-}
-
-/*
- * N.B. this can't be an initfunc, because the media-bay task can
- * call ide_[un]register at any time.
- */
-void __pmac
-pmac_ide_init_hwif_ports(hw_regs_t *hw,
-			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
-			      int *irq)
-{
-	int i, ix;
-
-	if (data_port == 0)
-		return;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (data_port == pmac_ide[ix].regbase)
-			break;
-
-	if (ix >= MAX_HWIFS) {
-		/* Probably a PCI interface... */
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-		return;
-	}
-
-	for (i = 0; i < 8; ++i)
-		hw->io_ports[i] = data_port + i * 0x10;
-	hw->io_ports[8] = data_port + 0x160;
-
-	if (irq != NULL)
-		*irq = pmac_ide[ix].irq;
-
-	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
-	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
-	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-		if (!noautodma)
-			ide_hwifs[ix].autodma = 1;
-#endif
-	}
-}
-
-#if 0
-/* This one could be later extended to handle CMD IDE and be used by some kind
- * of /proc interface. I want to be able to get the devicetree path of a block
- * device for yaboot configuration
- */
-struct device_node*
-pmac_ide_get_devnode(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return NULL;
-	return pmac_ide[i].node;
-}
-#endif
-
-/* Setup timings for the selected drive (master/slave). I still need to verify if this
- * is enough, I beleive selectproc will be called whenever an IDE command is started,
- * but... */
-static void __pmac
-pmac_ide_selectproc(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-
-	if (drive->select.b.unit & 0x01)
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[1]);
-	else
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[0]);
-	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-}
-
-
-static int __pmac
-pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
-{
-	int result = 1;
-	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
-	
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	(void)GET_STAT(); /* Get rid of pending error state */
-	if(wait_for_ready(drive, 2000)) {	/* Timeout bumped for some powerbooks */
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
-		goto out;
-	}
-	udelay(10);
-	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(command, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	udelay(1);
-	local_irq_set(flags);
-	result = wait_for_ready(drive, 2000);	/* Timeout bumped for some powerbooks */
-	local_irq_restore(flags);
-	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	if (result)
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
-out:
-	SELECT_MASK(HWIF(drive), drive, 0);
-	if (result == 0) {
-		drive->id->dma_ultra &= ~0xFF00;
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		switch(command) {
-			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-			default: break;
-		}
-	}
-	enable_irq(hwif->irq);
-	return result;
-}
-
-/* Calculate PIO timings */
-static void __pmac
-pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int i;
-	u32 *timings;
-	unsigned accessTicks, recTicks;
-	unsigned accessTime, recTime;
-	
-	i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-		
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[i].timings[1];
-	else
-		timings = &pmac_ide[i].timings[0];
-
-	recTime = d.cycle_time - ide_pio_timings[pio].active_time
-			- ide_pio_timings[pio].setup_time;
-	recTime = max(recTime, 150U);
-	accessTime = ide_pio_timings[pio].active_time;
-	accessTime = max(accessTime, 150U);
-	if (pmac_ide[i].kind == controller_kl_ata4 ||
-		pmac_ide[i].kind == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_66_PIO_MASK) |
-				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell */
-		int ebit = 0;
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 4U);
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 5U) - 4;
-		if (recTicks > 9) {
-			recTicks--; /* guess, but it's only for PIO0, so... */
-			ebit = 1;
-		}
-		*timings = ((*timings) & ~TR_33_PIO_MASK) |
-				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
-		if (ebit)
-			*timings |= TR_33_PIO_E;
-	}
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
-		pio,  *timings);
-#endif	
-		
-	if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
-		pmac_ide_selectproc(drive);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int __pmac
-set_timings_udma(u32 *timings, byte speed)
-{
-	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
-	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
-	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
-	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
-
-	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
-			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
-			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
-			TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-
-	return 0;
-}
-
-static int __pmac
-set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
-{
-	int cycleTime, accessTime, recTime;
-	unsigned accessTicks, recTicks;
-	struct mdma_timings_t* tm;
-	int i;
-
-	/* Get default cycle time for mode */
-	switch(speed & 0xf) {
-		case 0: cycleTime = 480; break;
-		case 1: cycleTime = 150; break;
-		case 2: cycleTime = 120; break;
-		default:
-			return -1;
-	}
-	/* Adjust for drive */
-	if (drive_cycle_time && drive_cycle_time > cycleTime)
-		cycleTime = drive_cycle_time;
-	/* OHare limits according to some old Apple sources */	
-	if ((intf_type == controller_ohare) && (cycleTime < 150))
-		cycleTime = 150;
-	/* Get the proper timing array for this controller */
-	switch(intf_type) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			tm = mdma_timings_66;
-			break;
-		case controller_kl_ata3:
-			tm = mdma_timings_33k;
-			break;
-		default:
-			tm = mdma_timings_33;
-			break;
-	}
-	/* Lookup matching access & recovery times */
-	i = -1;
-	for (;;) {
-		if (tm[i+1].cycleTime < cycleTime)
-			break;
-		i++;
-	}
-	if (i < 0)
-		return -1;
-	cycleTime = tm[i].cycleTime;
-	accessTime = tm[i].accessTime;
-	recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
-		cycleTime, accessTime, recTime);
-#endif	
-	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 0x1U);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 0x3U);
-		/* Clear out mdma bits and disable udma */
-		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
-			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
-			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
-	} else if (intf_type == controller_kl_ata3) {
-		/* 33Mhz cell on KeyLargo */
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 1U);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell on others */
-		int halfTick = 0;
-		int origAccessTime = accessTime;
-		int origRecTime = recTime;
-		
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 2U) - 1;
-		recTicks = min(recTicks, 0x1fU);
-		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
-		if ((accessTicks > 1) &&
-		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-            		halfTick = 1;
-			accessTicks--;
-		}
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-		if (halfTick)
-			*timings |= TR_33_MDMA_HALFTICK;
-	}
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-	return 0;
-}
-#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-/* You may notice we don't use this function on normal operation,
- * our, normal mdma function is supposed to be more precise
- */
-static int __pmac
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int intf		= pmac_ide_find(drive);
-	int unit		= (drive->select.b.unit & 0x01);
-	int ret			= 0;
-	u32 *timings;
-
-	if (intf < 0)
-		return 1;
-		
-	timings = &pmac_ide[intf].timings[unit];
-	
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-			if (pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (pmac_ide[intf].kind != controller_kl_ata4 &&
-				pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-			ret = set_timings_udma(timings, speed);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
-			break;
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			return 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pmac_ide_tuneproc(drive, speed & 0x07);
-			break;
-		default:
-			ret = 1;
-	}
-	if (ret)
-		return ret;
-
-	ret = pmac_ide_do_setfeature(drive, speed);
-	if (ret)
-		return ret;
-		
-	pmac_ide_selectproc(drive);	
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-static void __pmac
-sanitize_timings(int i)
-{
-	unsigned value;
-	
-	switch(pmac_ide[i].kind) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			value = 0x0008438c;
-			break;
-		case controller_kl_ata3:
-			value = 0x00084526;
-			break;
-		case controller_heathrow:
-		case controller_ohare:
-		default:
-			value = 0x00074526;
-			break;
-	}
-	pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
-}
-
-ide_ioreg_t __pmac
-pmac_ide_get_base(int index)
-{
-	return pmac_ide[index].regbase;
-}
-
-int __pmac
-pmac_ide_check_base(ide_ioreg_t base)
-{
-	int ix;
-	
- 	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return ix;
-	return -1;
-}
-
-int __pmac
-pmac_ide_get_irq(ide_ioreg_t base)
-{
-	int ix;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return pmac_ide[ix].irq;
-	return 0;
-}
-
-static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
-
-kdev_t __init
-pmac_find_ide_boot(char *bootdevice, int n)
-{
-	int i;
-	
-	/*
-	 * Look through the list of IDE interfaces for this one.
-	 */
-	for (i = 0; i < pmac_ide_count; ++i) {
-		char *name;
-		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
-			continue;
-		name = pmac_ide[i].node->full_name;
-		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_ide_probe(void)
-{
-	struct device_node *np;
-	int i;
-	struct device_node *atas;
-	struct device_node *p, **pp, *removables, **rp;
-	unsigned long base;
-	int irq, big_delay;
-	ide_hwif_t *hwif;
-
-	if (_machine != _MACH_Pmac)
-		return;
-	pp = &atas;
-	rp = &removables;
-	p = find_devices("ATA");
-	if (p == NULL)
-		p = find_devices("IDE");
-	if (p == NULL)
-		p = find_type_devices("ide");
-	if (p == NULL)
-		p = find_type_devices("ata");
-	/* Move removable devices such as the media-bay CDROM
-	   on the PB3400 to the end of the list. */
-	for (; p != NULL; p = p->next) {
-		if (p->parent && p->parent->type
-		    && strcasecmp(p->parent->type, "media-bay") == 0) {
-			*rp = p;
-			rp = &p->next;
-		} else {
-			*pp = p;
-			pp = &p->next;
-		}
-	}
-	*rp = NULL;
-	*pp = removables;
-	big_delay = 0;
-
-	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
-		struct device_node *tp;
-		struct pmac_ide_hwif* pmhw;
-		int *bidp;
-		int in_bay = 0;
-		u8 pbus, pid;
-		struct pci_dev *pdev = NULL;
-
-		/*
-		 * If this node is not under a mac-io or dbdma node,
-		 * leave it to the generic PCI driver.
-		 */
-		for (tp = np->parent; tp != 0; tp = tp->parent)
-			if (tp->type && (strcmp(tp->type, "mac-io") == 0
-					 || strcmp(tp->type, "dbdma") == 0))
-				break;
-		if (tp == 0)
-			continue;
-
-		if (np->n_addrs == 0) {
-			printk(KERN_WARNING "ide: no address for device %s\n",
-			       np->full_name);
-			continue;
-		}
-
-		/* We need to find the pci_dev of the mac-io holding the
-		 * IDE interface
-		 */
-		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
-			pdev = pci_find_slot(pbus, pid);
-		if (pdev == NULL)
-			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
-			       np->full_name);
-
-		/*
-		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
-		 */
-		while (i < MAX_HWIFS
-		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
-			++i;
-		if (i >= MAX_HWIFS)
-			break;
-		pmhw = &pmac_ide[i];
-
-		/*
-		 * Some older OFs have bogus sizes, causing request_OF_resource
-		 * to fail. We fix them up here
-		 */
-		if (np->addrs[0].size > 0x1000)
-			np->addrs[0].size = 0x1000;
-		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
-			np->addrs[1].size = 0x100;
-
-		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
-			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
-			continue;
-		}
-
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
-
-		/* XXX This is bogus. Should be fixed in the registry by checking
-		   the kind of host interrupt controller, a bit like gatwick
-		   fixes in irq.c
-		 */
-		if (np->n_intrs == 0) {
-			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
-			       np->full_name);
-			irq = 13;
-		} else {
-			irq = np->intrs[0].line;
-		}
-		pmhw->regbase = base;
-		pmhw->irq = irq;
-		pmhw->node = np;
-		if (device_is_compatible(np, "keylargo-ata")) {
-			if (strcmp(np->name, "ata-4") == 0)
-				pmhw->kind = controller_kl_ata4;
-			else
-				pmhw->kind = controller_kl_ata3;
-		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmhw->kind = controller_heathrow;
-		else
-			pmhw->kind = controller_ohare;
-
-		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmhw->aapl_bus_id =  bidp ? *bidp : 0;
-
-		if (pmhw->kind == controller_kl_ata4) {
-			char* cable = get_property(np, "cable-type", NULL);
-			if (cable && !strncmp(cable, "80-", 3))
-				pmhw->kind = controller_kl_ata4_80;
-		}
-
-		/* Make sure we have sane timings */
-		sanitize_timings(i);
-
-		if (np->parent && np->parent->name
-		    && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
-			media_bay_set_ide_infos(np->parent,base,irq,i);
-#endif /* CONFIG_PMAC_PBOOK */
-			in_bay = 1;
-			if (!bidp)
-				pmhw->aapl_bus_id = 1;
-		} else if (pmhw->kind == controller_ohare) {
-			/* The code below is having trouble on some ohare machines
-			 * (timing related ?). Until I can put my hand on one of these
-			 * units, I keep the old way
-			 */
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-		} else {
- 			/* This is necessary to enable IDE when net-booting */
-			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmhw->aapl_bus_id);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1);
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1);
-			mdelay(10);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0);
-			big_delay = 1;
-		}
-
-		hwif = &ide_hwifs[i];
-		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
-		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->chipset = ide_pmac;
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
-		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
-		hwif->pci_dev = pdev;
-#ifdef CONFIG_PMAC_PBOOK
-		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
-			hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (np->n_addrs >= 2) {
-			/* has a DBDMA controller channel */
-			pmac_ide_setup_dma(np, i);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-		++i;
-	}
-	pmac_ide_count = i;
-	if (big_delay)
-		mdelay(IDE_WAKEUP_DELAY_MS);
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-	register_reboot_notifier(&pmac_ide_reboot_notifier);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-static void __init 
-pmac_ide_setup_dma(struct device_node *np, int ix)
-{
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-
-	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
-		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
-		return;
-	}
-
-	pmif->dma_regs =
-		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
-
-	/*
-	 * Allocate space for the DBDMA commands.
-	 * The +2 is +1 for the stop command and +1 to allow for
-	 * aligning the start address to a multiple of 16 bytes.
-	 */
-	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
-		ide_hwifs[ix].pci_dev,
-		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-		&pmif->dma_table_dma);
-	if (pmif->dma_table_cpu == NULL) {
-		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-		       ide_hwifs[ix].name);
-		return;
-	}
-
-	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
-				 GFP_KERNEL);
-	if (pmif->sg_table == NULL) {
-		pci_free_consistent(	ide_hwifs[ix].pci_dev,
-					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-				    	pmif->dma_table_cpu, pmif->dma_table_dma);
-		return;
-	}
-	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-	if (!noautodma)
-		ide_hwifs[ix].autodma = 1;
-#endif
-}
-
-static int
-pmac_ide_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct buffer_head *bh;
-	struct scatterlist *sg = pmif->sg_table;
-	int nents = 0;
-
-	if (hwif->sg_dma_active)
-		BUG();
-		
-	if (rq->cmd == READ)
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
-
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-static int
-pmac_ide_raw_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
-	int sector_count = rq->nr_sectors;
-
-	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
-	if (sector_count > 128) {
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = 128  * SECTOR_SIZE;
-		nents++;
-		virt_addr = virt_addr + (128 * SECTOR_SIZE);
-		sector_count -= 128;
-	}
-	memset(&sg[nents], 0, sizeof(*sg));
-	sg[nents].address = virt_addr;
-	sg[nents].length =  sector_count  * SECTOR_SIZE;
-	nents++;
-   
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
-{
-	struct dbdma_cmd *table;
-	int i, count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
-	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
-	struct scatterlist *sg;
-
-	/* DMA table is already aligned */
-	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
-
-	/* Make sure DMA controller is stopped (necessary ?) */
-	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
-	while (in_le32(&dma->status) & RUN)
-		udelay(1);
-
-	/* Build sglist */
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
-	else
-		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
-	if (!i)
-		return 0;
-
-	/* Build DBDMA commands list */
-	sg = pmac_ide[ix].sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		while (cur_len) {
-			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-			if (++count >= MAX_DCMDS) {
-				printk(KERN_WARNING "%s: DMA table too small\n",
-				       drive->name);
-				return 0; /* revert to PIO for this request */
-			}
-			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
-			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, cur_addr);
-			table->cmd_dep = 0;
-			table->xfer_status = 0;
-			table->res_count = 0;
-			cur_addr += tc;
-			cur_len -= tc;
-			++table;
-		}
-		sg++;
-		i--;
-	}
-
-	/* convert the last command to an input/output last command */
-	if (count)
-		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
-	else
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
-	/* add the stop command to the end of the list */
-	memset(table, 0, sizeof(struct dbdma_cmd));
-	out_le16(&table->command, DBDMA_STOP);
-
-	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
-	return 1;
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	struct scatterlist *sg = pmac_ide[ix].sg_table;
-	int nents = pmac_ide[ix].sg_nents;
-
-	if (nents) {
-		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
-		pmac_ide[ix].sg_nents = 0;
-	}
-}
-
-static __inline__ unsigned char
-dma_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return XFER_MW_DMA_2;
-	if(bits & 0x02)
-		return XFER_MW_DMA_1;
-	if(bits & 0x01)
-		return XFER_MW_DMA_0;
-	return 0;
-}
-
-static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits, int high_speed)
-{
-	if (high_speed) {
-		if(bits & 0x10)
-			return XFER_UDMA_4;
-		if(bits & 0x08)
-			return XFER_UDMA_3;
-	}
-	if(bits & 0x04)
-		return XFER_UDMA_2;
-	if(bits & 0x02)
-		return XFER_UDMA_1;
-	if(bits & 0x01)
-		return XFER_UDMA_0;
-	return 0;
-}
-
-/* Calculate MultiWord DMA timings */
-static int __pmac
-pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
-{
-	byte bits = drive->id->dma_mword & 0x07;
-	byte feature = dma_bits_to_command(bits);
-	u32 *timings;
-	int drive_cycle_time;
-	struct hd_driveid *id = drive->id;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
-	    	return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-	
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	/* Check if drive provide explicit cycle time */
-	if ((id->field_valid & 2) && (id->eide_dma_time))
-		drive_cycle_time = id->eide_dma_time;
-	else
-		drive_cycle_time = 0;
-
-	/* Calculate controller timings */
-	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-/* Calculate Ultra DMA timings */
-static int __pmac
-pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
-{
-	byte bits = drive->id->dma_ultra & 0x1f;
-	byte feature = udma_bits_to_command(bits, high_speed);
-	u32 *timings;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-		printk(KERN_WARNING "%s: Failed !\n", drive->name);
-		return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	set_timings_udma(timings, feature);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-static int __pmac
-pmac_ide_check_dma(ide_drive_t *drive)
-{
-	int ata4, udma, idx;
-	struct hd_driveid *id = drive->id;
-	int enable = 1;
-
-	drive->using_dma = 0;
-	
-	idx = pmac_ide_find(drive);
-	if (idx < 0)
-		return 0;
-		
-	if (drive->media == ide_floppy)
-		enable = 0;
-	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
-		enable = 0;
-	if (check_drive_lists(drive, BAD_DMA_DRIVE))
-		enable = 0;
-
-	udma = 0;
-	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
-		pmac_ide[idx].kind == controller_kl_ata4_80);
-			
-	if(enable) {
-		if (ata4 && (drive->media == ide_disk) &&
-		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
-			/* UltraDMA modes. */
-			drive->using_dma = pmac_ide_udma_enable(drive, idx,
-				pmac_ide[idx].kind == controller_kl_ata4_80);
-		}
-		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
-			/* Normal MultiWord DMA modes. */
-			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
-		}
-		OUT_BYTE(0, IDE_CONTROL_REG);
-		/* Apply settings to controller */
-		pmac_ide_selectproc(drive);
-	}
-	return 0;
-}
-
-static int __pmac
-pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-//	ide_task_t *args = HWGROUP(drive)->rq->special;
-	int ix, dstat;
-	volatile struct dbdma_regs *dma;
-	byte unit = (drive->select.b.unit & 0x01);
-	byte ata4;
-	int reading = 0;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return 0;		
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-	
-	switch (func) {
-	case ide_dma_off:
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	case ide_dma_off_quietly:
-		drive->using_dma = 0;
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		pmac_ide_check_dma(drive);
-		break;
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		SELECT_READ_WRITE(HWIF(drive),drive,func);
-		if (!pmac_ide_build_dmatable(drive, ix, !reading))
-			return 1;
-		/* Apple adds 60ns to wrDataSetup on reads */
-		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-				pmac_ide[ix].timings[unit] + 
-				(reading ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-		}
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-			BUG();
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-#if 0
-	{
-		ide_task_t *args = HWGROUP(drive)->rq->special;
-		OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-	}
-#else
-		if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) {
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		} else if (drive->addressing == 1)
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		else
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-#endif
-	case ide_dma_begin:
-		out_le32(&dma->control, (RUN << 16) | RUN);
-		/* Make sure it gets to the controller right now */
-		(void)in_le32(&dma->control);
-		break;
-	case ide_dma_end: /* returns 1 on error, 0 otherwise */
-		drive->waiting_for_dma = 0;
-		dstat = in_le32(&dma->status);
-		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-		pmac_ide_destroy_dmatable(drive, ix);
-		/* verify good dma status */
-		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-		/* We have to things to deal with here:
-		 * 
-		 * - The dbdma won't stop if the command was started
-		 * but completed with an error without transfering all
-		 * datas. This happens when bad blocks are met during
-		 * a multi-block transfer.
-		 * 
-		 * - The dbdma fifo hasn't yet finished flushing to
-		 * to system memory when the disk interrupt occurs.
-		 * 
-		 * The trick here is to increment drive->waiting_for_dma,
-		 * and return as if no interrupt occured. If the counter
-		 * reach a certain timeout value, we then return 1. If
-		 * we really got the interrupt, it will happen right away
-		 * again.
-		 * Apple's solution here may be more elegant. They issue
-		 * a DMA channel interrupt (a separate irq line) via a DBDMA
-		 * NOP command just before the STOP, and wait for both the
-		 * disk and DBDMA interrupts to have completed.
-		 */
-		 
-		/* If ACTIVE is cleared, the STOP command have passed and
-		 * transfer is complete.
-		 */
-		if (!(in_le32(&dma->status) & ACTIVE))
-			return 1;
-		if (!drive->waiting_for_dma)
-			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
-
-		/* If dbdma didn't execute the STOP command yet, the
-		 * active bit is still set */
-		drive->waiting_for_dma++;
-		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-			printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-			return 1;
-		}
-		udelay(1);
-		return 0;
-
-		/* Let's implement tose just in case someone wants them */
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-	case ide_dma_verbose:
-		return report_drive_dmaing(drive);
-	case ide_dma_retune:
-	case ide_dma_lostirq:
-	case ide_dma_timeout:
-		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-		return 1;
-	default:
-		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-		return 1;
-	}
-	return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-static void __pmac
-idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
-{
-	int j;
-	
-	/* FIXME: We only handle the master IDE disk, we shoud
-	 *        try to fix CD-ROMs here
-	 */
-	switch (drive->media) {
-	case ide_disk:
-		/* Spin down the drive */
-		OUT_BYTE(drive->select.all, base+0x60);
-		(void) IN_BYTE(base+0x60);
-		udelay(100);
-		OUT_BYTE(0x0, base+0x30);
-		OUT_BYTE(0x0, base+0x20);
-		OUT_BYTE(0x0, base+0x40);
-		OUT_BYTE(0x0, base+0x50);
-		OUT_BYTE(0xe0, base+0x70);
-		OUT_BYTE(0x2, base+0x160);   
-		for (j = 0; j < 10; j++) {
-			int status;
-			mdelay(100);
-			status = IN_BYTE(base+0x70);
-			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
-				break;
-		}
-		break;
-	case ide_cdrom:
-		// todo
-		break;
-	case ide_floppy:
-		// todo
-		break;
-	}
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-static void __pmac
-idepmac_wake_device(ide_drive_t *drive, int used_dma)
-{
-	/* We force the IDE subdriver to check for a media change
-	 * This must be done first or we may lost the condition
-	 *
-	 * Problem: This can schedule. I moved the block device
-	 * wakeup almost late by priority because of that.
-	 */
-	if (DRIVER(drive) && DRIVER(drive)->media_change)
-		DRIVER(drive)->media_change(drive);
-
-	/* We kick the VFS too (see fix in ide.c revalidate) */
-	__check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
-	
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* We re-enable DMA on the drive if it was active. */
-	/* This doesn't work with the CD-ROM in the media-bay, probably
-	 * because of a pending unit attention. The problem if that if I
-	 * clear the error, the filesystem dies.
-	 */
-	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		pmac_ide_check_dma(drive);
-		HWGROUP(drive)->busy = 0;
-		if (!list_empty(&drive->queue.queue_head))
-			ide_do_request(HWGROUP(drive), 0);
-		spin_unlock_irq(&ide_lock);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-}
-
-static void __pmac
-idepmac_sleep_interface(int i, unsigned base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	/* We clear the timings */
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
-	
-	/* The media bay will handle itself just fine */
-	if (mediabay)
-		return;
-	
-	/* Disable the bus */
-	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
-}
-
-static void __pmac
-idepmac_wake_interface(int i, unsigned long base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	if (!mediabay) {
-		/* Revive IDE disk and controller */
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
-		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
-		mdelay(10);
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
-	}
-}
-
-static void
-idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
-{
-	int unlock = 0;
-
-	/* Wait for HW group to complete operations */
-	if (ide_spin_wait_hwgroup(drive)) {
-		// What can we do here ? Wake drive we had already
-		// put to sleep and return an error ?
-	} else {
-		unlock = 1;
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		/* Stop the device */
-		idepmac_sleep_device(drive, idx, base);
-	}
-	if (unlock)
-		spin_unlock_irq(&ide_lock);
-}
-
-static void
-idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
-{
-	unsigned long flags;
-	int j;
-	
-	/* Reset timings */
-	pmac_ide_selectproc(drive);
-	mdelay(10);
-	
-	/* Wait up to 20 seconds for the drive to be ready */
-	for (j = 0; j < 200; j++) {
-		int status;
-		mdelay(100);
-		OUT_BYTE(drive->select.all, base + 0x60);
-		if (IN_BYTE(base + 0x60) != drive->select.all)
-			continue;
-		status = IN_BYTE(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
-
-	/* We resume processing on the HW group */
-	spin_lock_irqsave(&ide_lock, flags);
-	HWGROUP(drive)->busy = 0;
-	if (!list_empty(&drive->queue.queue_head))
-		ide_do_request(HWGROUP(drive), 0);
-	spin_unlock_irqrestore(&ide_lock, flags);			
-}
-
-/* Note: We support only master drives for now. This will have to be
- * improved if we want to handle sleep on the iMacDV where the CD-ROM
- * is a slave
- */
-static int __pmac
-idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	int i, ret;
-	unsigned long base;
-	int big_delay;
- 
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-	case PBOOK_SLEEP_NOW:
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int dn;
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				if (!hwif->drives[dn].present)
-					continue;
-				idepmac_sleep_drive(&hwif->drives[dn], i, base);
-			}
-			/* Disable irq during sleep */
-			disable_irq(pmac_ide[i].irq);
-			
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay.
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV))
-				idepmac_sleep_interface(i, base, (ret == 0));
-		}
-		break;
-	case PBOOK_WAKE:
-		big_delay = 0;
-		for (i = 0; i < pmac_ide_count; ++i) {
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			/* Make sure we have sane timings */		
-			sanitize_timings(i);
-
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV)) {
-				idepmac_wake_interface(i, base, (ret == 0));				
-				big_delay = 1;
-			}
-
-		}
-		/* Let hardware get up to speed */
-		if (big_delay)
-			mdelay(IDE_WAKEUP_DELAY_MS);
-	
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int used_dma, dn;
-			int irq_on = 0;
-			
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				ide_drive_t *drive = &hwif->drives[dn];
-				if (!drive->present)
-					continue;
-				/* We don't have re-configured DMA yet */
-				used_dma = drive->using_dma;
-				drive->using_dma = 0;
-				idepmac_wake_drive(drive, base);
-				if (!irq_on) {
-					enable_irq(pmac_ide[i].irq);
-					irq_on = 1;
-				}
-				idepmac_wake_device(drive, used_dma);
-			}
-			if (!irq_on)
-				enable_irq(pmac_ide[i].irq);
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int __pmac
-pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
-{
-	int i, gotone;
-	unsigned long base;
-
-	if (code != SYS_HALT && code != SYS_POWER_OFF)
-		return 0;
-
-	gotone = 0;
-	for (i = 0; i < pmac_ide_count; ++i) {
-		ide_hwif_t *hwif;
-		ide_drive_t *drive;
-		int unlock = 0;
-		int dn;
-
-		if ((base = pmac_ide[i].regbase) == 0)
-				continue;	
-
-		hwif = &ide_hwifs[i];
-		for (dn=0; dn<MAX_DRIVES; dn++) {
-			drive = &hwif->drives[dn];
-			if (drive->present) {
-				gotone = 1;
-				/* Wait for HW group to complete operations */
-				if (ide_spin_wait_hwgroup(drive)) {
-					// What can we do here ? Wake drive we had already
-					// put to sleep and return an error ?
-				} else {
-					unlock = 1;
-					/* Lock HW group */
-					HWGROUP(drive)->busy = 1;
-
-					/* Stop the device */
-					idepmac_sleep_device(drive, i, base);
-				}
-			}
-			if (unlock)
-				spin_unlock_irq(&ide_lock);
-		}
-	}
-	if (gotone)
-		mdelay(1000);
-		
-	return NOTIFY_DONE;
-}
diff -Nru a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
--- a/drivers/ide/ide-pnp.c	Sun Sep 15 19:19:56 2002
+++ b/drivers/ide/ide-pnp.c	Sun Sep 15 19:19:56 2002
@@ -21,12 +21,6 @@
 
 #include <linux/isapnp.h>
 
-#ifndef PREPARE_FUNC
-#define PREPARE_FUNC(dev)  (dev->prepare)
-#define ACTIVATE_FUNC(dev)  (dev->activate)
-#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
-#endif
-
 #define DEV_IO(dev, index) (dev->resource[index].start)
 #define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
 
@@ -54,6 +48,7 @@
 };
 
 /* Generic initialisation function for ISA PnP IDE interface */
+
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
@@ -66,13 +61,16 @@
 		return 1;
 
 	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
-			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
-			0, NULL, DEV_IRQ(dev, 0));
+			generic_ide_offsets,
+			(ide_ioreg_t) DEV_IO(dev, 1),
+			0, NULL,
+//			generic_pnp_ide_iops,
+			DEV_IRQ(dev, 0));
 
 	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1) {
-	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+	    	printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
@@ -88,7 +86,6 @@
 	{	0 }
 };
 
-#ifdef MODULE
 #define NR_PNP_DEVICES 8
 struct pnp_dev_inst {
 	struct pci_dev *dev;
@@ -96,11 +93,11 @@
 };
 static struct pnp_dev_inst devices[NR_PNP_DEVICES];
 static int pnp_ide_dev_idx = 0;
-#endif
 
 /*
  * Probe for ISA PnP IDE interfaces.
  */
+
 void __init pnpide_init(int enable)
 {
 	struct pci_dev *dev = NULL;
@@ -109,19 +106,18 @@
 	if (!isapnp_present())
 		return;
 
-#ifdef MODULE
 	/* Module unload, deactivate all registered devices. */
 	if (!enable) {
 		int i;
 		for (i = 0; i < pnp_ide_dev_idx; i++) {
+			dev = devices[i].dev;
 			devices[i].dev_type->init_fn(dev, 0);
-
-			if (DEACTIVATE_FUNC(devices[i].dev))
-				DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+			if (dev->deactivate)
+				dev->deactivate(dev);
 		}
 		return;
 	}
-#endif
+
 	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
@@ -129,20 +125,20 @@
 			if (dev->active)
 				continue;
 
-       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s prepare failed\n", DEV_NAME(dev));
+       			if (dev->prepare && dev->prepare(dev) < 0) {
+				printk(KERN_ERR"ide-pnp: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
 
-			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s activate failed\n", DEV_NAME(dev));
+			if (dev->activate && dev->activate(dev) < 0) {
+				printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
 				continue;
 			}
 
 			/* Call device initialization function */
 			if (dev_type->init_fn(dev, 1)) {
-				if (DEACTIVATE_FUNC(dev))
-					DEACTIVATE_FUNC(dev)(dev);
+				if (dev->deactivate(dev))
+					dev->deactivate(dev);
 			} else {
 #ifdef MODULE
 				/*
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Sun Sep 15 19:19:51 2002
+++ b/drivers/ide/ide-probe.c	Sun Sep 15 19:19:51 2002
@@ -52,46 +52,69 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static inline void do_identify (ide_drive_t *drive, byte cmd)
+/*
+ * CompactFlash cards and their brethern pretend to be removable
+ * hard disks, except:
+ *	(1) they never have a slave unit, and
+ *	(2) they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting
+ * appropriate config bits.
+ *
+ * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
+ * devices, so in linux 2.3.x we should change this to just treat all PCMCIA
+ * drives this way, and get rid of the model-name tests below
+ * (too big of an interface change for 2.2.x).
+ * At that time, we might also consider parameterizing the timeouts and retries,
+ * since these are MUCH faster than mechanical drives.	-M.Lord
+ */
+inline int drive_is_flashcard (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (drive->removable && id != NULL) {
+		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
+		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
+		{
+			return 1;	/* yes, it is a flash memory card */
+		}
+	}
+	return 0;	/* no, it is not a flash memory card */
+}
+
+static inline void do_identify (ide_drive_t *drive, u8 cmd)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	int bswap = 1;
 	struct hd_driveid *id;
 
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	/* called with interrupts disabled! */
+	id = drive->id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
 	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		printk(KERN_WARNING "(ide-probe::do_identify) "
+			"Out of memory.\n");
 		goto err_kmalloc;
 	}
 	/* read 512 bytes of id info */
-#if 1
-	ata_input_data(drive, id, SECTOR_WORDS);
-#else
-	{
-		unsigned long	*ptr = (unsigned long *)id ;
-		unsigned long	lcount = 256/2 ;
-                // printk("IDE_DATA_REG = %#lx",IDE_DATA_REG);
-		while( lcount-- )
-			*ptr++ = inl(IDE_DATA_REG);
-	}
-#endif
+	hwif->ata_input_data(drive, id, SECTOR_WORDS);
+
 	local_irq_enable();
 	ide_fix_driveid(id);
 
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n",
-			drive->name, drive->id->word156);
-	}
-
 	if (!drive->forced_lun)
 		drive->last_lun = id->last_lun & 0x7;
+
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:
 	 * Ignore them if there is a driver for them available.
 	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+	if ((id->model[0] == 'P' && id->model[1] == 'M') ||
+	    (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
 		goto err_misc;
 	}
@@ -105,16 +128,18 @@
 		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
 		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
 		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
+			/* Vertos drives may still be weird */
+			bswap ^= 1;	
 	}
-	ide_fixstring (id->model,     sizeof(id->model),     bswap);
-	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+	ide_fixstring(id->model,     sizeof(id->model),     bswap);
+	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
 		goto err_misc;
 
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	/* we depend on this a lot! */
+	id->model[sizeof(id->model)-1] = '\0';
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
 
@@ -122,7 +147,7 @@
 	 * Check for an ATAPI device
 	 */
 	if (cmd == WIN_PIDENTIFY) {
-		byte type = (id->config >> 8) & 0x1f;
+		u8 type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
 		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
@@ -142,7 +167,8 @@
 						break;
 					}
 				}
-				type = ide_cdrom;	/* Early cdrom models used zero */
+				/* Early cdrom models used zero */
+				type = ide_cdrom;
 			case ide_cdrom:
 				drive->removable = 1;
 #ifdef CONFIG_PPC
@@ -182,16 +208,18 @@
 	 * slave drive if the hwif is actually a flash memory card of
 	 * some variety:
 	 */
+	drive->is_flash = 0;
 	if (drive_is_flashcard(drive)) {
 		ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];
 		if (!mate->ata_flash) {
 			mate->present = 0;
 			mate->noprobe = 1;
 		}
+		drive->is_flash = 1;
 	}
 	drive->media = ide_disk;
-	printk("ATA DISK drive\n");
-	QUIRK_LIST(hwif, drive);
+	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+	QUIRK_LIST(drive);
 	return;
 
 err_misc:
@@ -211,68 +239,80 @@
  *		1  device timed-out (no response to identify request)
  *		2  device aborted the command (refused to identify itself)
  */
-static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 {
-//	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif = HWIF(drive);
 	int rc;
 	ide_ioreg_t hd_status;
 	unsigned long timeout;
-	byte s, a;
+	u8 s = 0, a = 0;
 
 	if (IDE_CONTROL_REG) {
 		/* take a deep breath */
 		ide_delay_50ms();
-		a = IN_BYTE(IDE_ALTSTATUS_REG);
-		s = IN_BYTE(IDE_STATUS_REG);
+		a = hwif->INB(IDE_ALTSTATUS_REG);
+		s = hwif->INB(IDE_STATUS_REG);
 		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+			printk("%s: probing with STATUS(0x%02x) instead of "
+				"ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			/* ancient Seagate drives, broken interfaces */
+			hd_status = IDE_STATUS_REG;
 		} else {
-			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+			/* use non-intrusive polling */
+			hd_status = IDE_ALTSTATUS_REG;
 		}
 	} else {
 		ide_delay_50ms();
 		hd_status = IDE_STATUS_REG;
 	}
 
-	/* set features register for atapi identify command to be sure of reply */
+	/* set features register for atapi
+	 * identify command to be sure of reply
+	 */
 	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+		/* disable dma & overlap */
+		hwif->OUTB(0, IDE_FEATURE_REG);
 
-#if CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(ide_drive_t *);
-		if (pdc4030_identify(drive)) {
+	if (hwif->identify != NULL) {
+		if (hwif->identify(drive))
 			return 1;
-		}
-	} else
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	} else {
+		/* ask drive for ID */
+		hwif->OUTB(cmd, IDE_COMMAND_REG);
+	}
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
 		if (time_after(jiffies, timeout)) {
-			return 1;	/* drive timed-out */
+			/* drive timed-out */
+			return 1;
 		}
-		ide_delay_50ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
+		/* give drive a breather */
+		ide_delay_50ms();
+	} while ((hwif->INB(hd_status)) & BUSY_STAT);
 
-	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+	/* wait for IRQ and DRQ_STAT */
+	ide_delay_50ms();
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
 		unsigned long flags;
+
+		/* local CPU only; some systems need this */
 		local_irq_save(flags);
-			/* local CPU only; some systems need this */
-		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* drive responded with ID */
-		(void) GET_STAT();	/* clear drive IRQ */
+		/* drive returned ID */
+		do_identify(drive, cmd);
+		/* drive responded with ID */
+		rc = 0;
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
 		local_irq_restore(flags);
-	} else
-		rc = 2;			/* drive refused ID */
+	} else {
+		/* drive refused ID */
+		rc = 2;
+	}
 	return rc;
 }
 
-static int try_to_identify (ide_drive_t *drive, byte cmd)
+static int try_to_identify (ide_drive_t *drive, u8 cmd)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	int retval;
@@ -282,26 +322,34 @@
 	if (IDE_CONTROL_REG && !hwif->irq) {
 		autoprobe = 1;
 		cookie = probe_irq_on();
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		/* enable device irq */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
-		(void) GET_STAT();			/* clear drive IRQ */
+		/* mask device irq */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
 		irq = probe_irq_off(cookie);
 		if (!hwif->irq) {
 			if (irq > 0) {
 				hwif->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+			} else {
+				/* Mmmm.. multiple IRQs..
+				 * don't know which was ours
+				 */
+				printk("%s: IRQ probe failed (0x%lx)\n",
+					drive->name, cookie);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
 				if (hwif->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+					printk("%s: Hmmm.. probably a driver "
+						"problem.\n", drive->name);
 					CMD640_DUMP_REGS;
 				}
 #endif /* CMD640_DUMP_REGS */
@@ -329,11 +377,13 @@
  *		3  bad status from device (possible for ATAPI drives)
  *		4  probe was not attempted because failure was obvious
  */
-static int do_probe (ide_drive_t *drive, byte cmd)
+static int do_probe (ide_drive_t *drive, u8 cmd)
 {
 	int rc;
 	ide_hwif_t *hwif = HWIF(drive);
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
+
+	if (drive->present) {
+		/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
 			return 4;
 	}
@@ -342,43 +392,64 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	SELECT_DRIVE(hwif,drive);
+
+	/* needed for some systems
+	 * (e.g. crw9624 as drive0 with disk as slave)
+	 */
+	ide_delay_50ms();
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+	if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		if (drive->select.b.unit != 0) {
-			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
+			/* exit with drive0 selected */
+			SELECT_DRIVE(&hwif->drives[0]);
+			/* allow BUSY_STAT to assert & clear */
+			ide_delay_50ms();
 		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+		/* no i/f present: mmm.. this should be a 4 -ml */
+		return 3;
 	}
 
-	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT) ||
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
 	    drive->present || cmd == WIN_PIDENTIFY) {
-		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
-			rc = try_to_identify(drive,cmd); /* failed: try again */
+		/* send cmd and wait */
+		if ((rc = try_to_identify(drive, cmd))) {
+			/* failed: try again */
+			rc = try_to_identify(drive,cmd);
+		}
+		if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+			return 4;
+
 		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
 			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			printk("%s: no response (status = 0x%02x), "
+				"resetting drive\n", drive->name,
+				hwif->INB(IDE_STATUS_REG));
 			ide_delay_50ms();
-			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			ide_delay_50ms();
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+			       time_before(jiffies, timeout + WAIT_WORSTCASE))
 				ide_delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
-		(void) GET_STAT();		/* ensure drive irq is clear */
+			printk("%s: no response (status = 0x%02x)\n",
+				drive->name, hwif->INB(IDE_STATUS_REG));
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	} else {
-		rc = 3;				/* not present or maybe ATAPI */
+		/* not present or maybe ATAPI */
+		rc = 3;
 	}
 	if (drive->select.b.unit != 0) {
-		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		/* exit with drive0 selected */
+		SELECT_DRIVE(&hwif->drives[0]);
 		ide_delay_50ms();
-		(void) GET_STAT();		/* ensure drive irq is clear */
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	}
 	return rc;
 }
@@ -392,9 +463,9 @@
 	unsigned long timeout;
 
 	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
-	SELECT_DRIVE(hwif, drive);
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
 		if (time_after(jiffies, timeout)) {
@@ -402,15 +473,21 @@
 			return;
 		}
 		ide_delay_50ms();
-	} while (GET_STAT() & BUSY_STAT);
+	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
 	ide_delay_50ms();
-	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
-		printk("failed (status = 0x%02x)\n", GET_STAT());
-	else
+
+	if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
+		printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
+	} else {
 		printk("success\n");
+	}
 
-	if (do_probe(drive, WIN_IDENTIFY) >= 2)	/* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
+	}
 }
 
 /*
@@ -419,102 +496,99 @@
  * Returns:	0  no device was found
  *		1  device was found (note: drive->present might still be 0)
  */
-static inline byte probe_for_drive (ide_drive_t *drive)
+static inline u8 probe_for_drive (ide_drive_t *drive)
 {
-	if (drive->noprobe)			/* skip probing? */
+	/* skip probing? */
+	if (drive->noprobe)
 		return drive->present;
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
 		enable_nest(drive);
 	if (!drive->present)
-		return 0;			/* drive not found */
-	if (drive->id == NULL) {		/* identification failed? */
+		/* drive not found */
+		return 0;
+
+	/* identification failed? */
+	if (drive->id == NULL) {
 		if (drive->media == ide_disk) {
-			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
-			 drive->name, drive->cyl, drive->head, drive->sect);
+			printk("%s: non-IDE drive, CHS=%d/%d/%d\n",
+				drive->name, drive->cyl,
+				drive->head, drive->sect);
 		} else if (drive->media == ide_cdrom) {
 			printk("%s: ATAPI cdrom (?)\n", drive->name);
 		} else {
-			drive->present = 0;	/* nuke it */
+			/* nuke it */
+			drive->present = 0;
 		}
 	}
-	return 1;	/* drive was found */
+	/* drive was found */
+	return 1;
 }
 
-/*
- * Calculate the region that this interface occupies,
- * handling interfaces where the registers may not be
- * ordered sanely.  We deal with the CONTROL register
- * separately.
- */
+#define hwif_check_region(addr, num) \
+	((hwif->mmio) ? check_mem_region((addr),(num)) : check_region((addr),(num)))
+
 static int hwif_check_regions (ide_hwif_t *hwif)
 {
-	int region_errors = 0;
-
-	hwif->straight8 = 0;
-	region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+	u32 i		= 0;
+	int addr_errs	= 0;
 
+	if (hwif->mmio == 2)
+		return 0;
+	addr_errs  = hwif_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		addr_errs += hwif_check_region(hwif->io_ports[i], 1);
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-	/*
-	 * If any errors are return, we drop the hwif interface.
-	 */
-	return(region_errors);
+	/* If any errors are return, we drop the hwif interface. */
+	hwif->straight8 = 0;
+	return(addr_errs);
 }
 
+//EXPORT_SYMBOL(hwif_check_regions);
+
+#define hwif_request_region(addr, num, name)	\
+	((hwif->mmio) ? request_mem_region((addr),(num),(name)) : request_region((addr),(num),(name)))
+
 static void hwif_register (ide_hwif_t *hwif)
 {
-	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
-	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
-		hwif->straight8 = 1;
-		goto jump_straight8;
-	}
-
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+	u32 i = 0;
 
-jump_straight8:
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
+		hwif_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+		hwif->straight8 = 1;
+		return;
+	}
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hwif_request_region(hwif->io_ports[i], 1, hwif->name);
 }
 
+//EXPORT_SYMBOL(hwif_register);
+
 /*
  * 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_hwif (ide_hwif_t *hwif)
+void probe_hwif (ide_hwif_t *hwif)
 {
 	unsigned int unit;
 	unsigned long flags;
@@ -524,8 +598,7 @@
 #ifdef CONFIG_BLK_DEV_IDE
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
 		extern void probe_cmos_for_drives(ide_hwif_t *);
-
-		probe_cmos_for_drives (hwif);
+		probe_cmos_for_drives(hwif);
 	}
 #endif
 
@@ -534,20 +607,25 @@
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	    (hwif_check_regions(hwif))) {
-		int msgout = 0;
+		u16 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);
+				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);
+			printk("%s: ports already in use, skipping probe\n",
+				hwif->name);
 		return;	
 	}
 
+	if (hwif->hw.ack_intr && hwif->irq)
+		disable_irq(hwif->irq);
+
 	local_irq_set(flags);
 	/*
 	 * Second drive should only exist if first drive was found,
@@ -556,7 +634,8 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 		drive->dn = ((hwif->channel ? 2 : 0) + unit);
-		(void) probe_for_drive (drive);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		(void) probe_for_drive(drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
 			if (hwif->chipset != ide_4drives ||
@@ -567,40 +646,76 @@
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		byte stat;
+		u8 stat;
 
 		printk("%s: reset\n", hwif->name);
-		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
-		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		do {
 			ide_delay_50ms();
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
 		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
 
 	}
 	local_irq_restore(flags);
+	if (hwif->hw.ack_intr && hwif->irq)
+		enable_irq(hwif->irq);
+
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 		if (drive->present) {
 			if (hwif->tuneproc != NULL && drive->autotune == 1)
 				/* auto-tune PIO mode */
 				hwif->tuneproc(drive, 255);
-
-			if ((drive->autotune != 2) && hwif->dmaproc != NULL) {
+			/*
+			 * MAJOR HACK BARF :-/
+			 *
+			 * FIXME: chipsets own this cruft!
+			 */
+			/*
+			 * Move here to prevent module loading clashing.
+			 */
+	//		drive->autodma = hwif->autodma;
+			if ((drive->autotune != 2) && (hwif->ide_dma_check)) {
 				/*
 				 * Force DMAing for the beginning of the check.
 				 * Some chipsets appear to do interesting
 				 * things, if not checked and cleared.
 				 *   PARANOIA!!!
 				 */
-				hwif->dmaproc(ide_dma_off_quietly, drive);
-				hwif->dmaproc(ide_dma_check, drive);
+				hwif->ide_dma_off_quietly(drive);
+				hwif->ide_dma_check(drive);
 			}
 		}
 	}
 }
 
+EXPORT_SYMBOL(probe_hwif);
+
+int hwif_init (ide_hwif_t *hwif);
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#if 1
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present)
+				ata_attach(drive);
+		}
+	}
+#endif
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -613,7 +728,7 @@
  *
  * This routine detects and reports such situations, but does not fix them.
  */
-static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
 {
 	ide_hwif_t *m = *match;
 
@@ -626,6 +741,7 @@
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
+EXPORT_SYMBOL(save_match);
 #endif /* MAX_HWIFS > 1 */
 
 /*
@@ -667,17 +783,20 @@
  * 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 int init_irq (ide_hwif_t *hwif)
+int init_irq (ide_hwif_t *hwif)
 {
 	unsigned long flags;
 	unsigned int index;
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
-	
+#if 0
+	/* Allocate the buffer and no sleep allowed */
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_ATOMIC);
+#else
 	/* Allocate the buffer and potentially sleep first */
-	
 	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+#endif
 	
 	spin_lock_irqsave(&ide_lock, flags);
 
@@ -691,7 +810,8 @@
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
-				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+				if (hwif->chipset != ide_pci ||
+				    h->chipset != ide_pci) {
 					save_match(hwif, h, &match);
 				}
 			}
@@ -734,16 +854,23 @@
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else /* !CONFIG_IDEPCI_SHARE_IRQ */
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+		int sa = SA_INTERRUPT;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+		sa = SA_SHIRQ;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+			sa = SA_SHIRQ;
+#ifndef CONFIG_IDEPCI_SHARE_IRQ
+			sa |= SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		}
 
 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
-			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+			/* clear nIEN */
+			hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
 
-		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
+		if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
 			spin_unlock_irqrestore(&ide_lock, flags);
@@ -774,11 +901,12 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
+
+	/* all CPUs; safe now that hwif->hwgroup is set up */
 	spin_unlock_irqrestore(&ide_lock, flags);
-		/* all CPUs; safe now that hwif->hwgroup is set up */
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET],
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
@@ -788,7 +916,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
-	printk("%s at %p on irq 0x%08x", hwif->name,
+	printk("%s at %x on irq 0x%08x", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
 #endif /* __mc68000__ && CONFIG_APUS */
 	if (match)
@@ -798,6 +926,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(init_irq);
+
 /*
  * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  * after probing for drives, to allocate partition tables and other data
@@ -811,15 +941,7 @@
 	extern devfs_handle_t ide_devfs_handle;
 	char *names;
 
-#if 1
 	units = MAX_DRIVES;
-#else
-	/* figure out maximum drive number on the interface */
-	for (units = MAX_DRIVES; units > 0; --units) {
-		if (hwif->drives[units-1].present)
-			break;
-	}
-#endif
 
 	minors    = units * (1<<PARTN_BITS);
 	gd        = kmalloc(MAX_DRIVES * sizeof(struct gendisk), GFP_KERNEL);
@@ -827,7 +949,7 @@
 		goto err_kmalloc_gd;
 	memset(gd, 0, MAX_DRIVES * sizeof(struct gendisk));
 
-	names = kmalloc (4 * MAX_DRIVES, GFP_KERNEL);
+	names = kmalloc(4 * MAX_DRIVES, GFP_KERNEL);
 	if (!names)
 		goto err_kmalloc_gd_names;
 	memset(names, 0, 4 * MAX_DRIVES);
@@ -843,7 +965,6 @@
 	}
 
 	for (unit = 0; unit < units; ++unit) {
-#if 1
 		char name[64];
 		ide_add_generic_settings(hwif->drives + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
@@ -852,18 +973,6 @@
 			hwif->channel, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-#else
-		if (hwif->drives[unit].present) {
-			char name[64];
-
-			ide_add_generic_settings(hwif->drives + unit);
-			sprintf (name, "host%d/bus%d/target%d/lun%d",
-				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
-				 hwif->channel, unit, hwif->drives[unit].lun);
-			hwif->drives[unit].de =
-				devfs_mk_dir (ide_devfs_handle, name, NULL);
-		}
-#endif
 	}
 	return;
 
@@ -873,7 +982,9 @@
 	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+EXPORT_SYMBOL(init_gendisk);
+
+int hwif_init (ide_hwif_t *hwif)
 {
 	if (!hwif->present)
 		return 0;
@@ -891,8 +1002,9 @@
 		return (hwif->present = 0);
 	}
 #endif /* CONFIG_BLK_DEV_HD */
-	
-	hwif->present = 0; /* we set it back to 1 if all is ok below */
+
+	/* we set it back to 1 if all is ok below */	
+	hwif->present = 0;
 
 	if (register_blkdev (hwif->major, hwif->name, ide_fops)) {
 		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
@@ -909,13 +1021,13 @@
 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
 			printk("%s: Disabled unable to get IRQ %d.\n",
 				hwif->name, i);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		if (init_irq(hwif)) {
 			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 				hwif->name, i, hwif->irq);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		printk("%s: probed IRQ %d failed, using default.\n",
@@ -926,28 +1038,23 @@
 	blk_dev[hwif->major].data = hwif;
 	blk_dev[hwif->major].queue = ide_get_queue;
 	hwif->present = 1;	/* success */
-
-#if (DEBUG_SPINLOCK > 0)
-{
-	static int done = 0;
-	if (!done++)
-		printk("ide_lock is %p\n", &ide_lock);    /* FIXME */
-}
-#endif
-	return hwif->present;
+	return 1;
 }
 
+EXPORT_SYMBOL(hwif_init);
+
 void export_ide_init_queue (ide_drive_t *drive)
 {
 	ide_init_queue(drive);
 }
 
-byte export_probe_for_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(export_ide_init_queue);
+
+u8 export_probe_for_drive (ide_drive_t *drive)
 {
 	return probe_for_drive(drive);
 }
 
-EXPORT_SYMBOL(export_ide_init_queue);
 EXPORT_SYMBOL(export_probe_for_drive);
 
 int ideprobe_init (void);
@@ -961,7 +1068,7 @@
 {
 	unsigned int index;
 	int probe[MAX_HWIFS];
-	
+
 	MOD_INC_USE_COUNT;
 	memset(probe, 0, MAX_HWIFS * sizeof(int));
 	for (index = 0; index < MAX_HWIFS; ++index)
@@ -976,7 +1083,7 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
-	for (index = 0; index < MAX_HWIFS; ++index)
+	for (index = 0; index < MAX_HWIFS; ++index) {
 		if (probe[index]) {
 			ide_hwif_t *hwif = &ide_hwifs[index];
 			int unit;
@@ -985,6 +1092,7 @@
 			for (unit = 0; unit < MAX_DRIVES; ++unit)
 				ata_attach(&hwif->drives[unit]);
 		}
+	}
 	if (!ide_probe)
 		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/ide/ide-proc.c	Sun Sep 15 19:19:28 2002
@@ -57,6 +57,9 @@
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -75,59 +78,6 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern byte aec62xx_proc;
-int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern byte ali_proc;
-int (*ali_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern byte amd74xx_proc;
-int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern byte cmd64x_proc;
-int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-extern byte cs5530_proc;
-int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern byte hpt34x_proc;
-int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt366_proc;
-int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern byte pdc202xx_proc;
-int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-extern byte piix_proc;
-int (*piix_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern byte svwks_proc;
-int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern byte sis_proc;
-int (*sis_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern byte slc90e66_proc;
-int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern byte via_proc;
-int (*via_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -161,6 +111,15 @@
 
 static struct proc_dir_entry * proc_ide_root = NULL;
 
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#include <linux/delay.h>
+/*
+ * This is the list of registered PCI chipset driver data structures.
+ */
+static ide_pci_host_proc_t * ide_pci_host_proc_list;
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -215,7 +174,7 @@
 						break;
 				case 'P':	is_pci = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+						if (hwif->pci_dev && !hwif->pci_dev->vendor)
 							break;
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 						msg = "not a PCI device";
@@ -313,11 +272,11 @@
  * 
  */
 					switch (digits) {
-						case 2:	OUT_BYTE(val, reg);
+						case 2:	hwif->OUTB(val, reg);
 							break;
-						case 4:	OUT_WORD(val, reg);
+						case 4:	hwif->OUTW(val, reg);
 							break;
-						case 8:	outl(val, reg);
+						case 8:	hwif->OUTL(val, reg);
 							break;
 					}
 #endif /* !__mc68000__ && !CONFIG_APUS */
@@ -333,7 +292,7 @@
 	return xx_xx_parse_error(start, startn, msg);
 }
 
-static int proc_ide_read_config
+int proc_ide_read_config
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -342,20 +301,26 @@
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
 	struct pci_dev	*dev = hwif->pci_dev;
-	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
+	if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) {
 		int reg = 0;
 
-		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
-			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+		out += sprintf(out, "pci bus %02x device %02x vendor %04x "
+				"device %04x channel %d\n",
+			dev->bus->number, dev->devfn,
+			hwif->pci_dev->vendor, hwif->pci_dev->device,
+			hwif->channel);
 		do {
-			byte val;
+			u8 val;
 			int rc = pci_read_config_byte(dev, reg, &val);
 			if (rc) {
-				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
+				printk("proc_ide_read_config: error %d reading"
+					" bus %02x dev %02x reg 0x%02x\n",
 					rc, dev->bus->number, dev->devfn, reg);
-				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "??%c",
+					(++reg & 0xf) ? ' ' : '\n');
 			} else
-				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "%02x%c",
+					val, (++reg & 0xf) ? ' ' : '\n');
 		} while (reg < 0x100);
 	} else
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
@@ -364,6 +329,7 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_config);
 
 static int ide_getdigit(char c)
 {
@@ -405,7 +371,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_mate
+EXPORT_SYMBOL(proc_ide_read_imodel);
+
+int proc_ide_read_mate
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -418,7 +386,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_channel
+EXPORT_SYMBOL(proc_ide_read_mate);
+
+int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -430,7 +400,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_identify
+EXPORT_SYMBOL(proc_ide_read_channel);
+
+int proc_ide_read_identify
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *)data;
@@ -441,7 +413,8 @@
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			out += sprintf(out, "%04x%c",
+				le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
 			val += 1;
 		} while (i < (SECTOR_WORDS * 2));
 		len = out - page;
@@ -451,7 +424,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_settings
+EXPORT_SYMBOL(proc_ide_read_identify);
+
+int proc_ide_read_settings
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -481,9 +456,11 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_settings);
+
 #define MAX_LEN	30
 
-static int proc_ide_write_settings
+int proc_ide_write_settings
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -558,6 +535,8 @@
 	return -EINVAL;
 }
 
+EXPORT_SYMBOL(proc_ide_write_settings);
+
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -569,10 +548,12 @@
 		len = sprintf(page, "(none)\n");
         else
 		len = sprintf(page,"%llu\n",
-			      (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
+			      (u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -580,24 +561,32 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+			drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+			drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_dmodel
+EXPORT_SYMBOL(proc_ide_read_geometry);
+
+int proc_ide_read_dmodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	struct hd_driveid *id = drive->id;
 	int		len;
 
-	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	len = sprintf(page, "%.40s\n",
+		(id && id->model[0]) ? (char *)id->model : "(none)");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_driver
+EXPORT_SYMBOL(proc_ide_read_dmodel);
+
+int proc_ide_read_driver
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -607,11 +596,14 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
 	else
-		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+		len = sprintf(page, "%s version %s\n",
+			driver->name, driver->version);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_write_driver
+EXPORT_SYMBOL(proc_ide_read_driver);
+
+int proc_ide_write_driver
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -623,7 +615,9 @@
 	return count;
 }
 
-static int proc_ide_read_media
+EXPORT_SYMBOL(proc_ide_write_driver);
+
+int proc_ide_read_media
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -647,6 +641,8 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_media);
+
 static ide_proc_entry_t generic_drive_entries[] = {
 	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
@@ -673,6 +669,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_add_proc_entries);
+
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
 	if (!dir || !p)
@@ -683,7 +681,9 @@
 	}
 }
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+EXPORT_SYMBOL(ide_remove_proc_entries);
+
+void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
@@ -713,6 +713,8 @@
 	}
 }
 
+EXPORT_SYMBOL(create_proc_ide_drives);
+
 void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	struct proc_dir_entry *ent;
@@ -740,6 +742,8 @@
 	}
 }
 
+EXPORT_SYMBOL(recreate_proc_ide_device);
+
 void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	ide_driver_t *driver = drive->driver;
@@ -754,19 +758,21 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_device);
+
 void destroy_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
-//		ide_driver_t *driver = drive->driver;
-
 		if (drive->proc)
 			destroy_proc_ide_device(hwif, drive);
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_drives);
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
@@ -794,7 +800,29 @@
 	}
 }
 
-static void destroy_proc_ide_interfaces(void)
+#ifdef CONFIG_BLK_DEV_IDEPCI
+void ide_pci_register_host_proc (ide_pci_host_proc_t *p)
+{
+	ide_pci_host_proc_t *tmp;
+
+	if (!p) return;
+	p->next = NULL;
+	p->set = 1;
+	if (ide_pci_host_proc_list) {
+		tmp = ide_pci_host_proc_list;
+		while (tmp->next) tmp = tmp->next;
+		tmp->next = p;
+	} else
+		ide_pci_host_proc_list = p;
+}
+
+EXPORT_SYMBOL(ide_pci_register_host_proc);
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+void destroy_proc_ide_interfaces(void)
 {
 	int	h;
 
@@ -815,6 +843,8 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_interfaces);
+
 extern struct seq_operations ide_drivers_op;
 static int ide_drivers_open(struct inode *inode, struct file *file)
 {
@@ -829,6 +859,9 @@
 
 void proc_ide_create(void)
 {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 	struct proc_dir_entry *entry;
 	proc_ide_root = proc_mkdir("ide", 0);
 	if (!proc_ide_root) return;
@@ -839,120 +872,40 @@
 	if (entry)
 		entry->proc_fops = &ide_drivers_operations;
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	while (p != NULL)
+	{
+		if (p->name != NULL && p->set == 1 && p->get_info != NULL) 
+		{
+			p->parent = proc_ide_root;
+			create_proc_info_entry(p->name, 0, p->parent, p->get_info);
+			p->set = 2;
+		}
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+EXPORT_SYMBOL(proc_ide_create);
+
 void proc_ide_destroy(void)
 {
-	/*
-	 * Mmmm.. does this free up all resources,
-	 * or do we need to do a more proper cleanup here ??
-	 */
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		remove_proc_entry("ide/aec62xx",0);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		remove_proc_entry("ide/ali",0);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		remove_proc_entry("ide/amd74xx",0);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		remove_proc_entry("ide/cmd64x",0);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		remove_proc_entry("ide/cs5530",0);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		remove_proc_entry("ide/hpt34x",0);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		remove_proc_entry("ide/hpt366",0);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		remove_proc_entry("ide/pdc202xx",0);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		remove_proc_entry("ide/piix",0);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		remove_proc_entry("ide/svwks",0);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		remove_proc_entry("ide/sis", 0);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		remove_proc_entry("ide/slc90e66",0);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+	char name[32];
 
-	remove_proc_entry("ide/drivers", 0);
+	while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) {
+		name[0] = '\0';
+		sprintf(name, "ide/%s", p->name);
+		if (p->set == 2)
+			remove_proc_entry(p->name, p->parent);
+		if (p->next == NULL) break;
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	remove_proc_entry("ide/drivers", proc_ide_root);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
+
+EXPORT_SYMBOL(proc_ide_destroy);
diff -Nru a/drivers/ide/ide-swarm.c b/drivers/ide/ide-swarm.c
--- a/drivers/ide/ide-swarm.c	Sun Sep 15 19:20:24 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/swarm_ide.h>
-
-void __init swarm_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif;
-	/* 
-	 * Find the first untaken slot in hwifs 
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
-			break;
-		}
-	}
-	if (i == MAX_HWIFS) {
-		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Set up our stuff */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
-	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
-//	hwif->hw->ack_intr                     = swarm_ide_ack_intr;
-	hwif->hw.irq                          = SWARM_IDE_INT;
-	hwif->ideproc                         = swarm_ideproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	hwif->irq = hwif->hw.irq;
-	printk("SWARM onboard IDE configured as device %i\n", i);
-}
-
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/ide/ide-tape.c	Sun Sep 15 19:19:30 2002
@@ -724,10 +724,10 @@
 	struct bio *bio;
 	char *b_data;
 	int b_count;
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idetape_pc_t;
 
@@ -888,7 +888,7 @@
 	/*
 	 *	Read position information
 	 */
-	byte partition;
+	u8 partition;
 	unsigned int first_frame_position;		/* Current block */
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
@@ -896,7 +896,7 @@
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
+	u8 sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
@@ -1164,101 +1164,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idetape_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-	} b;
-} idetape_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-	} b;
-} idetape_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idetape_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idetape_ireason_reg_t;
-
-/*
- *	ATAPI Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-	} b;
-} idetape_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-	} b;
-} idetape_control_reg_t;
-
-/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ide_drive_t structure.
@@ -1431,7 +1336,7 @@
  * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
  */
 
-char *idetape_sense_key_verbose (byte idetape_sense_key)
+char *idetape_sense_key_verbose(u8 idetape_sense_key)
 {
 	switch (idetape_sense_key) {
 		default: {
@@ -1443,7 +1348,7 @@
 	}
 }
 
-char *idetape_command_key_verbose (byte idetape_command_key)
+char *idetape_command_key_verbose(u8 idetape_command_key)
 {
 	switch (idetape_command_key) {
 		case IDETAPE_TEST_UNIT_READY_CMD:	return("TEST_UNIT_READY_CMD");
@@ -1505,7 +1410,7 @@
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = min(bio->bi_size - pc->b_count, bcount);
-		atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
+		HWIF(drive)->atapi_input_bytes(drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
 		pc->b_count += bio->bi_size;
 		if (pc->b_count == bio->bi_size) {
@@ -1531,7 +1436,7 @@
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = min((unsigned long) pc->b_count, (unsigned long) bcount);
-		atapi_output_bytes(drive, /*(void *)*/ bio_data(bio), count);
+		HWIF(drive)->atapi_output_bytes(drive, bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -2018,7 +1923,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *rq;
-	idetape_error_reg_t error;
+	atapi_error_t error;
 
 	error.all = IN_BYTE(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage(drive);
@@ -2057,9 +1962,9 @@
 static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
 	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
@@ -2074,11 +1979,12 @@
 				"interrupt handler\n");
 #endif /* IDETAPE_DEBUG_LOG */	
 
-	status.all = GET_STAT();	/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2102,7 +2008,8 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {		/* No more interrupts */
+	/* No more interrupts */
+	if (!status.b.drq) {
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = max(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
@@ -2159,7 +2066,7 @@
 		printk(KERN_ERR "ide-tape: The tape wants to issue more "
 				"interrupts in DMA mode\n");
 		printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->ide_dma_off(drive);
 		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -2199,12 +2106,12 @@
 		if (pc->bio != NULL)
 			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes(drive, pc->current_position, bcount.all);	/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);	/* Write the current buffer */
 	} else {
 		if (pc->bio != NULL)
 			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes(drive, pc->current_position, bcount.all);	/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);	/* Read the current buffer */
 	}
 	pc->actually_transferred += bcount.all;	/* Update the current position */
 	pc->current_position += bcount.all;
@@ -2264,7 +2171,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 	int retries = 100;
 	ide_startstop_t startstop;
 
@@ -2293,15 +2200,17 @@
 	tape->cmd_start_time = jiffies;
 	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
 		BUG();
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes(drive, pc->c, 12);	/* Send the actual packet */
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
 }
 
 static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_bcount_reg_t bcount;
+	atapi_bcount_t bcount;
 	int dma_ok = 0;
 
 #if IDETAPE_DEBUG_BUGS
@@ -2359,10 +2268,14 @@
 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
 		printk(KERN_WARNING "ide-tape: DMA disabled, "
 				"reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags))
+			dma_ok = !HWIF(drive)->ide_dma_write(drive);
+		else
+			dma_ok = !HWIF(drive)->ide_dma_read(drive);
 	}
-	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = !HWIF(drive)->dmaproc(test_bit(PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
@@ -2374,7 +2287,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {			/* Begin DMA, if necessary */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
@@ -2408,7 +2321,7 @@
 /*
  *	A mode sense command is used to "sense" tape parameters.
  */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
 {
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
@@ -2520,11 +2433,11 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 	if (tape->onstream)
 		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
-	status.all = GET_STAT();
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 	if (status.b.dsc) {
 		if (status.b.check) {		/* Error detected */
 			printk(KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
@@ -2654,7 +2567,7 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
@@ -2665,40 +2578,6 @@
 }
 
 /*
- * This is our end_request replacement function.
- */
-static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
-{
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
-
-	BUG_ON(!(rq->flags & REQ_STARTED));
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
-		add_blkdev_randomness(major(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-		HWGROUP(drive)->rq = NULL;
-		end_that_request_last(rq);
-		ret = 0;
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return ret;
-}
-
-/*
  * idetape_do_request is our request handling function.	
  */
 static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -2706,7 +2585,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 #if IDETAPE_DEBUG_LOG
 #if 0
@@ -2727,7 +2606,7 @@
 		 */
 		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
 			"request queue (%ld)\n", drive->name, rq->flags);
-		idetape_do_end_request(drive, 0);
+		ide_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -2754,7 +2633,7 @@
 	 * If the tape is still busy, postpone our request and service
 	 * the other device meanwhile.
 	 */
-	status.all = GET_STAT();
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	/*
 	 * The OnStream tape drive doesn't support DSC. Assume
@@ -3192,7 +3071,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-	if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
+	if (rq == NULL || !IDETAPE_RQ_CMD(rq->flags)) {
 		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
 		return;
 	}
@@ -3420,7 +3299,7 @@
 	return position;
 }
 
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
@@ -3498,7 +3377,7 @@
  *	of the request queue and wait for their completion.
  *	
  */
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int retval;
@@ -3719,7 +3598,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1;
@@ -3747,11 +3626,11 @@
 	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
 {
 	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_SPACE_CMD;
-	put_unaligned(htonl (count), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl(count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
 	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
@@ -6299,7 +6178,7 @@
 
 #endif
 
-static int idetape_reinit(ide_drive_t *drive);
+static int idetape_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6334,7 +6213,7 @@
 	capacity:		NULL,
 	special:		NULL,
 	proc:			idetape_proc,
-	reinit:			idetape_reinit,
+	attach:			idetape_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 	drives:			LIST_HEAD_INIT(idetape_driver.drives),
@@ -6352,7 +6231,7 @@
 	release:	idetape_chrdev_release,
 };
 
-static int idetape_reinit (ide_drive_t *drive)
+static int idetape_attach (ide_drive_t *drive)
 {
 	idetape_tape_t *tape;
 	int minor;
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/ide/ide-taskfile.c	Sun Sep 15 19:19:28 2002
@@ -60,15 +60,17 @@
 #endif
 
 #define task_map_rq(rq, flags)		ide_map_buffer((rq), (flags))
-#define task_unmap_rq(rq, buf, flags)	ide_unmap_buffer((buf), (flags))
+#define task_unmap_rq(rq, buf, flags)	ide_unmap_buffer((rq), (buf), (flags))
 
 inline u32 task_read_24 (ide_drive_t *drive)
 {
-	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
+EXPORT_SYMBOL(task_read_24);
+
 static void ata_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -79,282 +81,47 @@
 	}
 }
 
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void task_vlb_sync (ide_ioreg_t port)
-{
-	(void) IN_BYTE (port);
-	(void) IN_BYTE (port);
-	(void) IN_BYTE (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	/*
-	 * first check if this controller has defined a special function
-	 * for handling polled ide transfers
-	 */
-
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			local_irq_save(flags);
-			task_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			local_irq_restore(flags);
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			local_irq_save(flags);
-			task_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			local_irq_restore(flags);
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ata_input_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ata_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
 
-void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+void taskfile_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
-	ata_input_data(drive, buffer, wcount);
+	HWIF(drive)->ata_input_data(drive, buffer, wcount);
 	if (drive->bswap)
 		ata_bswap_data(buffer, wcount);
 }
 
-void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+EXPORT_SYMBOL(taskfile_input_data);
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
 	if (drive->bswap) {
 		ata_bswap_data(buffer, wcount);
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 		ata_bswap_data(buffer, wcount);
 	} else {
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 	}
 }
 
-/*
- * Needed for PCI irq sharing
- */
-int drive_is_ready (ide_drive_t *drive)
-{
-	byte stat = 0;
-	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
-	/* need to guarantee 400ns since last command was issued */
-	udelay(1);
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-	/*
-	 * We do a passive status test under shared PCI interrupts on
-	 * cards that truly share the ATA side interrupt, but may also share
-	 * an interrupt with another pci card/device.  We make no assumptions
-	 * about possible isa-pnp and pci-pnp issues yet.
-	 */
-	if (IDE_CONTROL_REG)
-		stat = GET_ALTSTAT();
-	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
-
-	if (stat & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	return 1;		/* drive ready: *might* be interrupting */
-}
+EXPORT_SYMBOL(taskfile_output_data);
 
-/*
- * Global for All, and taken from ide-pmac.c
- */
-int wait_for_ready (ide_drive_t *drive, int timeout)
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-	byte stat = 0;
-
-	while(--timeout) {
-		stat = GET_STAT();
-		if(!(stat & BUSY_STAT)) {
-			if (drive->ready_stat == 0)
-				break;
-			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
-				break;
-		}
-		mdelay(1);
-	}
-	if((stat & ERR_STAT) || timeout <= 0) {
-		if (stat & ERR_STAT) {
-			printk(KERN_ERR "%s: wait_for_ready, error status: %x\n", drive->name, stat);
-		}
-		return 1;
-	}
-	return 0;
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	if (drive->media == ide_disk)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
-/*
- * 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() -- caller should just return.
- *
- * 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 timeout is achieved, before timing out.
- */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
-{
-	byte stat;
-	int i;
-	unsigned long flags;
- 
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		*startstop = ide_stopped;
-		return 1;
-	}
-
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		local_irq_set(flags);
-		timeout += jiffies;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (time_after(jiffies, timeout)) {
-				local_irq_restore(flags);
-				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
-				return 1;
-			}
-		}
-		local_irq_restore(flags);
-	}
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), good, bad))
-			return 0;
-	}
-	*startstop = DRIVER(drive)->error(drive, "status error", stat);
-	return 1;
-}
+EXPORT_SYMBOL(taskfile_lib_get_identify);
 
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
 {
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 	printk(KERN_INFO "%s: ", drive->name);
 //	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
 	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
@@ -373,96 +140,102 @@
 	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
 	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
 	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 }
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
 ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 {
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF;
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
 
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 	void debug_taskfile(drive, task);
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
 	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
+	if (IDE_CONTROL_REG) {
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	}
+	SELECT_MASK(drive, 0);
+
+	if (drive->addressing == 1) {
+		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
-
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (task->handler != NULL) {
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
+		ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+		hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
 		if (task->prehandler != NULL)
 			return task->prehandler(drive, task->rq);
 		return ide_started;
 	}
-#if 0
-	switch(task->data_phase) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case TASKFILE_OUT_DMAQ:
-		case TASKFILE_OUT_DMA:
-			HWIF(drive)->dmaproc(ide_dma_write, drive);
-			break;
-		case TASKFILE_IN_DMAQ:
-		case TASKFILE_IN_DMA:
-			HWIF(drive)->dmaproc(ide_dma_read, drive);
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		default:
-			if (task->handler == NULL)
+	/* for dma commands we down set the handler */
+	if (blk_fs_request(task->rq) && drive->using_dma) {
+		if (rq_data_dir(task->rq) == READ) {
+			if (hwif->ide_dma_read(drive))
 				return ide_stopped;
-			ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
-			/* Issue the command */
-			OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-			if (task->prehandler != NULL)
-				return task->prehandler(drive, HWGROUP(drive)->rq);
+		} else {
+			if (hwif->ide_dma_write(drive))
+				return ide_stopped;
+		}
+	} else {
+		if (!drive->using_dma && (task->handler == NULL))
+			return ide_stopped;
+
+		switch(taskfile->command) {
+			case WIN_WRITEDMA_ONCE:
+			case WIN_WRITEDMA:
+			case WIN_WRITEDMA_EXT:
+				if (hwif->ide_dma_write(drive))
+					return ide_stopped;
+				break;
+			case WIN_READDMA_ONCE:
+			case WIN_READDMA:
+			case WIN_READDMA_EXT:
+			case WIN_IDENTIFY_DMA:
+				if (hwif->ide_dma_read(drive))
+					return ide_stopped;
+				break;
+			default:
+				if (task->handler == NULL)
+					return ide_stopped;
+		}
 	}
-#else
-	//	if ((rq->cmd == WRITE) && (drive->using_dma))
-	/* for dma commands we down set the handler */
-	if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-#endif
 	return ide_started;
 }
 
-#if 0
+EXPORT_SYMBOL(do_rw_taskfile);
+
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+u8 taskfile_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
 	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (stat & BUSY_STAT) {
 		printk("Busy ");
-	else {
+	} else {
 		if (stat & READY_STAT)	printk("DriveReady ");
 		if (stat & WRERR_STAT)	printk("DeviceFault ");
 		if (stat & SEEK_STAT)	printk("SeekComplete ");
@@ -475,62 +248,66 @@
 #endif  /* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = task_read_24(drive);
-					OUT_BYTE(0x80, IDE_CONTROL_REG);
-					high = task_read_24(drive);
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld", sectors);
+		if (drive->media == ide_disk)
+			goto media_out;
+
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)	printk("Bad%s", (err & ABRT_ERR) ? "CRC " : "Sector ");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
+				u64 sectors = 0;
+				u32 high = 0;
+				u32 low = task_read_24(drive);
+				hwif->OUTB(0x80, IDE_CONTROL_REG);
+				high = task_read_24(drive);
+				sectors = ((u64)high << 24) | low;
+				printk(", LBAsect=%lld", sectors);
+			} else {
+				u8 cur  = hwif->INB(IDE_SELECT_REG);
+				u8 low  = hwif->INB(IDE_LCYL_REG);
+				u8 high = hwif->INB(IDE_HCYL_REG);
+				u8 sect = hwif->INB(IDE_SECTOR_REG);
+				/* using LBA? */
+				if (cur & 0x40) {
+					printk(", LBAsect=%d", (u32)
+						((cur&0xf)<<24)|(high<<16)|
+						(low<<8)|sect);
 				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(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(IDE_HCYL_REG)<<8) +
-						   IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
+					printk(", CHS=%d/%d/%d",
+						((high<<8) + low),
+						(cur & 0xf), sect);
 				}
-				if (HWGROUP(drive)->rq)
-					printk(", sector=%lu", (__u64) HWGROUP(drive)->rq->sector);
 			}
+			if (HWGROUP(drive)->rq)
+				printk(", sector=%lu",
+					HWGROUP(drive)->rq->sector);
 		}
+media_out:
 #endif  /* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
 	local_irq_restore(flags);
 	return err;
 }
-#endif
+
+EXPORT_SYMBOL(taskfile_dump_status);
 
 /*
  * Clean up after success/failure of an explicit taskfile operation.
  */
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+void ide_end_taskfile (ide_drive_t *drive, u8 stat, u8 err)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 	ide_task_t *args;
@@ -547,26 +324,26 @@
 		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
 	if (args->tf_in_flags.b.data) {
-		unsigned short data = IN_WORD(IDE_DATA_REG);
+		u16 data = hwif->INW(IDE_DATA_REG);
 		args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
 		args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
 	}
 	args->tfRegister[IDE_ERROR_OFFSET]   = err;
-	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
 	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 	if ((drive->id->command_set_2 & 0x0400) &&
 	    (drive->id->cfs_enable_2 & 0x0400) &&
 	    (drive->addressing == 1)) {
-		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+		hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
 	}
 
 #if 0
@@ -583,7 +360,8 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-#if 0
+EXPORT_SYMBOL(ide_end_taskfile);
+
 /*
  * try_to_flush_leftover_data() is invoked in response to a drive
  * unexpectedly having its DRQ_STAT bit set.  As an alternative to
@@ -601,50 +379,68 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		taskfile_input_data (drive, buffer, wcount);
+		taskfile_input_data(drive, buffer, wcount);
 	}
 }
 
+EXPORT_SYMBOL(task_try_to_flush_leftover_data);
+
 /*
  * taskfile_error() takes action based on the error returned by the drive.
  */
-ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 
         err = taskfile_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		rq->errors = 1;
 		ide_end_taskfile(drive, stat, err);
 		return ide_stopped;
 	}
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+		if (drive->media != ide_disk)
+			goto media_out;
+		if (stat & ERR_STAT) {
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				/* UDMA crc error -- just retry the operation */
+				drive->crc_count++;
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
 				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-                                rq->errors |= ERROR_RECAL;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
                 }
-                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+media_out:
+                if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
                         task_try_to_flush_leftover_data(drive);
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX) {
-			DRIVER(drive)->end_request(drive, 0);
+		DRIVER(drive)->end_request(drive, 0, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -656,20 +452,18 @@
 	}
 	return ide_stopped;
 }
-#endif
 
-/*
- * Handler for special commands without a data phase from ide-disk
- */
+EXPORT_SYMBOL(taskfile_error);
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
 ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 		drive->mult_count = drive->mult_req;
 	} else {
 		drive->mult_req = drive->mult_count = 0;
@@ -679,62 +473,73 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(set_multmode_intr);
+
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
 ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int retries = 5;
-	byte stat;
+	u8 stat;
 
-	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
 		udelay(10);
 
-	if (OK_STAT(stat, READY_STAT,BAD_STAT))
+	if (OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_stopped;
 
 	if (stat & (ERR_STAT|DRQ_STAT))
 		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
 
-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
 		BUG();
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(set_geometry_intr);
+
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
 ide_startstop_t recal_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT();
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
 		return DRIVER(drive)->error(drive, "recal_intr", stat);
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(recal_intr);
+
 /*
  * Handler for commands without a data phase
  */
 ide_startstop_t task_no_data_intr (ide_drive_t *drive)
 {
 	ide_task_t *args	= HWGROUP(drive)->rq->special;
-	byte stat		= GET_STAT();
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
 
 	local_irq_enable();
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 		DTF("%s: command opcode 0x%02x\n", drive->name,
 			args->tfRegister[IDE_COMMAND_OFFSET]);
 		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
 		/* calls ide_end_drive_cmd */
 	}
 	if (args)
-		ide_end_drive_cmd (drive, stat, GET_ERR());
+		ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(task_no_data_intr);
+
 /*
  * Handler for command with PIO data-in phase, READ
  */
@@ -744,12 +549,13 @@
  */
 ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
 	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
 	char *pBuf		= NULL;
+	u8 stat;
 	unsigned long flags;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 #if 0
 			DTF("%s: attempting to recover last " \
@@ -768,7 +574,7 @@
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
 			if (HWGROUP(drive)->handler == NULL)
-				ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 			return ide_started;  
 		}
 	}
@@ -786,11 +592,11 @@
 		return DRIVER(drive)->error(drive, "task_in_intr", stat);
         }
 	if (!rq->current_nr_sectors)
-		if (!DRIVER(drive)->end_request(drive, 1))
+		if (!DRIVER(drive)->end_request(drive, 1, 0))
 			return ide_stopped;
 
 	if (--rq->current_nr_sectors <= 0)
-		if (!DRIVER(drive)->end_request(drive, 1))
+		if (!DRIVER(drive)->end_request(drive, 1, 0))
 			return ide_stopped;
 #endif
 
@@ -803,78 +609,36 @@
 	 * FIXME :: We really can not legally get a new page/bh
 	 * regardless, if this is the end of our segment.
 	 * BH walking or segment can only be updated after we have a good
-	 * GET_STAT(); return.
+	 * hwif->INB(IDE_STATUS_REG); return.
 	 */
 	if (--rq->current_nr_sectors <= 0)
-		if (!DRIVER(drive)->end_request(drive, 1))
+		if (!DRIVER(drive)->end_request(drive, 1, 0))
 			return ide_stopped;
 	/*
 	 * ERM, it is techincally legal to leave/exit here but it makes
 	 * a mess of the code ...
 	 */
 	if (HWGROUP(drive)->handler == NULL)
-		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
-#undef ALTSTAT_SCREW_UP
-
-#ifdef ALTSTAT_SCREW_UP
-/*
- * (ks/hs): Poll Alternate Status Register to ensure
- * that drive is not busy.
- */
-byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
-{
-	int i;
-
-	DTF("multi%s: ASR = %x\n", msg, stat);
-	if (stat & BUSY_STAT) {
-		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
-		for (i=0; i<100; i++) {
-			stat = GET_ALTSTAT();
-			if ((stat & BUSY_STAT) == 0)
-				break;
-		}
-	}
-	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
-	 */
-	return(GET_STAT());
-}
-
-/*
- * (ks/hs): Poll Alternate status register to wait for drive
- * to become ready for next transfer
- */
-byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
-{
-
-	/* (ks/hs): FIXME: Error handling, time-out? */
-	while (stat & BUSY_STAT)
-		stat = GET_ALTSTAT();
-	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
-	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
-}
-#endif /* ALTSTAT_SCREW_UP */
+EXPORT_SYMBOL(task_in_intr);
 
 /*
  * Handler for command with Read Multiple
  */
 ide_startstop_t task_mulin_intr (ide_drive_t *drive)
 {
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
 	unsigned int msect	= drive->mult_count;
 	unsigned int nsect;
 	unsigned long flags;
+	u8 stat;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			if (!rq->bio) {
 				rq->current_nr_sectors += drive->mult_count;
@@ -890,38 +654,10 @@
 		}
 		/* no data yet, so wait for another interrupt */
 		if (HWGROUP(drive)->handler == NULL)
-			ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
-		 */
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = task_map_rq(rq, &flags);
-			DTF("Multiread: %p, nsect: %d, " \
-				"rq->current_nr_sectors: %ld\n",
-				pBuf, nsect, rq->current_nr_sectors);
-//			rq->current_nr_sectors -= nsect;
-			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-			task_unmap_rq(rq, pBuf, &flags);
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
-		}
-		DRIVER(drive)->end_request(drive, 1);
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
 	do {
 		nsect = rq->current_nr_sectors;
 		if (nsect > msect)
@@ -930,8 +666,6 @@
 		DTF("Multiread: %p, nsect: %d, msect: %d, " \
 			" rq->current_nr_sectors: %d\n",
 			pBuf, nsect, msect, rq->current_nr_sectors);
-//		rq->current_nr_sectors -= nsect;
-//		msect -= nsect;
 		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
 		task_unmap_rq(rq, pBuf, &flags);
 		rq->errors = 0;
@@ -941,18 +675,20 @@
 		 * FIXME :: We really can not legally get a new page/bh
 		 * regardless, if this is the end of our segment.
 		 * BH walking or segment can only be updated after we have a
-		 * good GET_STAT(); return.
+		 * good hwif->INB(IDE_STATUS_REG); return.
 		 */
 		if (!rq->current_nr_sectors) {
-			if (!DRIVER(drive)->end_request(drive, 1))
+			if (!DRIVER(drive)->end_request(drive, 1, 0))
 				return ide_stopped;
 		}
 	} while (msect);
 	if (HWGROUP(drive)->handler == NULL)
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_mulin_intr);
+
 /*
  * VERIFY ME before 2.4 ... unexpected race is possible based on details
  * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
@@ -965,23 +701,21 @@
 
 	if (ide_wait_stat(&startstop, drive, DATA_READY,
 			drive->bad_wstat, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+		printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
 			drive->name,
-			drive->addressing ? "WRITE_EXT" : "WRITE");
+			drive->addressing ? "_EXT" : "");
 		return startstop;
 	}
 	/* For Write_sectors we need to stuff the first sector */
 	pBuf = task_map_rq(rq, &flags);
-//	rq->current_nr_sectors--;
 	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
 	rq->current_nr_sectors--;
-	/*
-	 * WARNING :: Interrupt could happen instantly :-/
-	 */
 	task_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(pre_task_out_intr);
+
 /*
  * Handler for command with PIO data-out phase WRITE
  *
@@ -989,12 +723,13 @@
  */
 ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
 	unsigned long flags;
+	u8 stat;
 
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) {
 		DTF("%s: WRITE attempting to recover last " \
 			"sector counter status=0x%02x\n",
 			drive->name, stat);
@@ -1006,26 +741,37 @@
 	 * We have a good STATUS CHECK!!!
 	 */
 	if (!rq->current_nr_sectors)
-		if (!DRIVER(drive)->end_request(drive, 1))
+		if (!DRIVER(drive)->end_request(drive, 1, 0))
 			return ide_stopped;
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
 		pBuf = task_map_rq(rq, &flags);
 		DTF("write: %p, rq->current_nr_sectors: %d\n",
 			pBuf, (int) rq->current_nr_sectors);
-//		rq->current_nr_sectors--;
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
 		task_unmap_rq(rq, pBuf, &flags);
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
 	if (HWGROUP(drive)->handler == NULL)
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_out_intr);
+
+#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
 ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
 {
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	ide_hwif_t *hwif		= HWIF(drive);
+	char *pBuf			= NULL;
+	unsigned int nsect = 0, msect	= drive->mult_count;
+        u8 stat;
+	unsigned long flags;
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
 	ide_task_t *args = rq->special;
 	ide_startstop_t startstop;
 
@@ -1043,6 +789,32 @@
 			drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
 		return startstop;
 	}
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1, 0))
+				if (!rq->bio) {
+					stat = hwif->INB(IDE_STATUS_REG);
+					return ide_stopped;
+				}
+		}
+	} while (msect);
+	rq->errors = 0;
+	return ide_started;
+#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
 #if 0
 	if (wait_for_ready(drive, 100))
 		IDE_DEBUG(__LINE__);		//BUG();
@@ -1060,8 +832,11 @@
 	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
 	 */
 	return args->handler(drive);
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
 }
 
+EXPORT_SYMBOL(pre_task_mulout_intr);
+
 /*
  * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
  */
@@ -1072,12 +847,8 @@
  */
 ide_startstop_t task_mulout_intr (ide_drive_t *drive)
 {
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
+	ide_hwif_t *hwif		= HWIF(drive);
+	u8 stat				= hwif->INB(IDE_STATUS_REG);
 	struct request *rq		= HWGROUP(drive)->rq;
 	char *pBuf			= NULL;
 	ide_startstop_t startstop	= ide_stopped;
@@ -1104,7 +875,7 @@
 			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
 		}
 		if (!rq->bio)
-			DRIVER(drive)->end_request(drive, 1);
+			DRIVER(drive)->end_request(drive, 1, 0);
 		return startstop;
 	}
 	/*
@@ -1126,10 +897,11 @@
 		}
 		/* no data yet, so wait for another interrupt */
 		if (HWGROUP(drive)->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
+#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
 	if (HWGROUP(drive)->handler != NULL) {
 		unsigned long lflags;
 		spin_lock_irqsave(&ide_lock, lflags);
@@ -1137,30 +909,7 @@
 		del_timer(&HWGROUP(drive)->timer);
 		spin_unlock_irqrestore(&ide_lock, lflags);
 	}
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = task_map_rq(rq, &flags);
-			DTF("Multiwrite: %p, nsect: %d, " \
-				"rq->current_nr_sectors: %d\n",
-				pBuf, nsect, rq->current_nr_sectors);
-//			rq->current_nr_sectors -= nsect;
-			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-			task_unmap_rq(pBuf, &flags);
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
-		}
-		DRIVER(drive)->end_request(drive, 1);
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
 
 	do {
 		nsect = rq->current_nr_sectors;
@@ -1171,7 +920,6 @@
 			"rq->current_nr_sectors: %ld\n",
 			pBuf, nsect, msect, rq->current_nr_sectors);
 		msect -= nsect;
-//		rq->current_nr_sectors -= nsect;
 		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
 		task_unmap_rq(rq, pBuf, &flags);
 		rq->current_nr_sectors -= nsect;
@@ -1179,32 +927,38 @@
 		 * FIXME :: We really can not legally get a new page/bh
 		 * regardless, if this is the end of our segment.
 		 * BH walking or segment can only be updated after we
-		 * have a good  GET_STAT(); return.
+		 * have a good  hwif->INB(IDE_STATUS_REG); return.
 		 */
 		if (!rq->current_nr_sectors) {
-			if (!DRIVER(drive)->end_request(drive, 1))
+			if (!DRIVER(drive)->end_request(drive, 1, 0))
 				if (!rq->bio)
 					return ide_stopped;
 		}
 	} while (msect);
 	rq->errors = 0;
 	if (HWGROUP(drive)->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_mulout_intr);
+
 /* Called by internal to feature out type of command being called */
+//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
 				/* IDE_DRIVE_TASK_RAW_WRITE */
 		case CFA_WRITE_MULTI_WO_ERASE:
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
 			return &pre_task_mulout_intr;
 			
 				/* IDE_DRIVE_TASK_OUT */
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
 		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
@@ -1216,6 +970,7 @@
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				return &pre_task_out_intr;
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1226,7 +981,10 @@
 	return(NULL);
 }
 
+EXPORT_SYMBOL(ide_pre_handler_parser);
+
 /* Called by internal to feature out type of command being called */
+//ide_handler_t * ide_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
@@ -1235,6 +993,7 @@
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ_BUFFER:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
 		case WIN_READ_EXT:
 			return &task_in_intr;
 		case WIN_SECURITY_DISABLE:
@@ -1246,11 +1005,16 @@
 		case WIN_WRITE_BUFFER:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:	
 		case WIN_WRITE_EXT:
 			return &task_out_intr;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
 		case WIN_MULTREAD_EXT:
 			return &task_mulin_intr;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
@@ -1269,6 +1033,7 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 			return &task_no_data_intr;
@@ -1308,11 +1073,13 @@
 			return &task_no_data_intr;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1327,6 +1094,8 @@
 	}	
 }
 
+EXPORT_SYMBOL(ide_handler_parser);
+
 ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
@@ -1338,11 +1107,14 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_post_handler_parser);
+
 /* Called by ioctl to feature out type of command being called */
 int ide_cmd_type_parser (ide_task_t *args)
 {
-	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
-	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
+
+	task_struct_t *taskfile = (task_struct_t *) args->tfRegister;
+	hob_struct_t *hobfile   = (hob_struct_t *) args->hobRegister;
 
 	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
 	args->handler		= ide_handler_parser(taskfile, hobfile);
@@ -1354,19 +1126,25 @@
 			return IDE_DRIVE_TASK_IN;
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
 		case WIN_READ_EXT:
 		case WIN_READ_BUFFER:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
 		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_DOWNLOAD_MICROCODE:
 			return IDE_DRIVE_TASK_RAW_WRITE;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
 		case WIN_MULTREAD_EXT:
 			return IDE_DRIVE_TASK_IN;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
@@ -1391,12 +1169,14 @@
 			}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1440,6 +1220,7 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 		case WIN_SPECIFY:
@@ -1478,400 +1259,7 @@
 	}
 }
 
-/*
- * NOTICE: This is additions from IBM to provide a discrete interface,
- * for selective taskregister access operations.  Nice JOB Klaus!!!
- * Glad to be able to work and co-develop this with you and IBM.
- */
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-#if DEBUG_TASKFILE
-	byte status;
-#endif
-
-
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-	void debug_taskfile(drive, task);
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
-
-	/*
-	 * (ks) Check taskfile in/out flags.
-	 * If set, then execute as it is defined.
-	 * If not set, then define default settings.
-	 * The default values are:
-	 *	write and read all taskfile registers (except data) 
-	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
-	 */
-	if (task->tf_out_flags.all == 0) {
-		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
-		}
-        }
-
-	if (task->tf_in_flags.all == 0) {
-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
-		}
-        }
-
-	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-#if DEBUG_TASKFILE
-	status = GET_STAT();
-	if (status & 0x80) {
-		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
-		udelay(100);
-		status = GET_STAT();
-		printk("flagged_taskfile -> Status = %02x\n", status);
-	}
-#endif
-
-	if (task->tf_out_flags.b.data) {
-		unsigned short data =  taskfile->data + (hobfile->data << 8);
-		OUT_WORD(data, IDE_DATA_REG);
-	}
-
-	/* (ks) send hob registers first */
-	if (task->tf_out_flags.b.nsector_hob)
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-	if (task->tf_out_flags.b.sector_hob)
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl_hob)
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl_hob)
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-
-	/* (ks) Send now the standard registers */
-	if (task->tf_out_flags.b.error_feature)
-		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	/* refers to number of sectors to transfer */
-	if (task->tf_out_flags.b.nsector)
-		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to sector offset or start sector */
-	if (task->tf_out_flags.b.sector)
-		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl)
-		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl)
-		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-        /*
-	 * (ks) In the flagged taskfile approch, we will used all specified
-	 * registers and the register value will not be changed. Except the
-	 * select bit (master/slave) in the drive_head register. We must make
-	 * sure that the desired drive is selected.
-	 */
-	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
-	switch(task->data_phase) {
-
-   	        case TASKFILE_OUT_DMAQ:
-		case TASKFILE_OUT_DMA:
-			HWIF(drive)->dmaproc(ide_dma_write, drive);
-			break;
-
-		case TASKFILE_IN_DMAQ:
-		case TASKFILE_IN_DMA:
-			HWIF(drive)->dmaproc(ide_dma_read, drive);
-			break;
-
-	        default:
- 			if (task->handler == NULL)
-				return ide_stopped;
-
-			ide_set_handler (drive, task->handler, WAIT_WORSTCASE, NULL);
-			/* Issue the command */
-			OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-			if (task->prehandler != NULL)
-				return task->prehandler(drive, HWGROUP(drive)->rq);
-	}
-
-	return ide_started;
-}
-
-ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
-{
-	byte stat = GET_STAT();
-
-	local_irq_enable();
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
-		if (stat & ERR_STAT) {
-			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
-		}
-		/*
-		 * (ks) Unexpected ATA data phase detected.
-		 * This should not happen. But, it can !
-		 * I am not sure, which function is best to clean up
-		 * this situation.  I choose: ide_error(...)
-		 */
- 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
-	}
-
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-
-	return ide_stopped;
-}
-
-/*
- * Handler for command with PIO data-in phase
- */
-ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
-	int retries             = 5;
-
-	if (rq->current_nr_sectors == 0) 
-		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
-
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
-		if (stat & ERR_STAT) {
-			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
-		}
-		/*
-		 * (ks) Unexpected ATA data phase detected.
-		 * This should not happen. But, it can !
-		 * I am not sure, which function is best to clean up
-		 * this situation.  I choose: ide_error(...)
-		 */
-		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
-	}
-
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
-
-	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
-
-	if (--rq->current_nr_sectors != 0) {
-		/*
-                 * (ks) We don't know which command was executed. 
-		 * So, we wait the 'WORSTCASE' value.
-                 */
-		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
-		return ide_started;
-	}
-	/*
-	 * (ks) Last sector was transfered, wait until drive is ready. 
-	 * This can take up to 10 usec. We willl wait max 50 us.
-	 */
-	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
-		udelay(10);
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-
-	return ide_stopped;
-}
-
-ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
-	int retries             = 5;
-	unsigned int msect, nsect;
-
-	if (rq->current_nr_sectors == 0) 
-		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
-
-	msect = drive->mult_count;
-	if (msect == 0) 
-		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
-
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
-		if (stat & ERR_STAT) {
-			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
-		}
-		/*
-		 * (ks) Unexpected ATA data phase detected.
-		 * This should not happen. But, it can !
-		 * I am not sure, which function is best to clean up
-		 * this situation.  I choose: ide_error(...)
-		 */
-		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
-	}
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-
-	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-	    pBuf, nsect, rq->current_nr_sectors);
-
-	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		/*
-                 * (ks) We don't know which command was executed. 
-		 * So, we wait the 'WORSTCASE' value.
-                 */
-		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
-		return ide_started;
-	}
-
-	/*
-	 * (ks) Last sector was transfered, wait until drive is ready. 
-	 * This can take up to 10 usec. We willl wait max 50 us.
-	 */
-	while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
-		udelay(10);
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-
-	return ide_stopped;
-}
-
-/*
- * Pre handler for command with PIO data-out phase
- */
-ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
-{
-	byte stat		= GET_STAT();
-	ide_startstop_t startstop;
-
-	if (!rq->current_nr_sectors) {
-		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
-	}
-
-	if (ide_wait_stat(&startstop, drive, DATA_READY,
-			BAD_W_STAT, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
-		return startstop;
-	}
-
-	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-	--rq->current_nr_sectors;
-
-	return ide_started;
-}
-
-ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
-
-	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
-		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
-	
-	if (!rq->current_nr_sectors) { 
-		ide_end_drive_cmd (drive, stat, GET_ERR());
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
-		/*
-		 * (ks) Unexpected ATA data phase detected.
-		 * This should not happen. But, it can !
-		 * I am not sure, which function is best to clean up
-		 * this situation.  I choose: ide_error(...)
-		 */
-		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
-	}
-
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
-		(int) rq->current_nr_sectors, stat);
-
-	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
-	--rq->current_nr_sectors;
-
-	/*
-	 * (ks) We don't know which command was executed. 
-	 * So, we wait the 'WORSTCASE' value.
-	 */
-	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
-
-	return ide_started;
-}
-
-ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
-{
-	byte stat		= GET_STAT();
-	char *pBuf		= NULL;
-	ide_startstop_t startstop;
-	unsigned int msect, nsect;
-
-	if (!rq->current_nr_sectors) 
-		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
-
-	msect = drive->mult_count;
-	if (msect == 0)
-		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
-
-	if (ide_wait_stat(&startstop, drive, DATA_READY,
-			BAD_W_STAT, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
-		return startstop;
-	}
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-	    pBuf, nsect, rq->current_nr_sectors);
-
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-
-	rq->current_nr_sectors -= nsect;
-
-	return ide_started;
-}
-
-ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	struct request *rq	= HWGROUP(drive)->rq;
-	char *pBuf		= NULL;
-	unsigned int msect, nsect;
-
-	msect = drive->mult_count;
-	if (msect == 0)
-		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
-
-	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
-		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
-	
-	if (!rq->current_nr_sectors) { 
-		ide_end_drive_cmd (drive, stat, GET_ERR());
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
-		/*
-		 * (ks) Unexpected ATA data phase detected.
-		 * This should not happen. But, it can !
-		 * I am not sure, which function is best to clean up
-		 * this situation.  I choose: ide_error(...)
-		 */
-		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
-	}
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-	    pBuf, nsect, rq->current_nr_sectors);
-
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	rq->current_nr_sectors -= nsect;
-
-	/*
-	 * (ks) We don't know which command was executed. 
-	 * So, we wait the 'WORSTCASE' value.
-	 */
-	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
-
-	return ide_started;
-}
+EXPORT_SYMBOL(ide_cmd_type_parser);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
@@ -1882,7 +1270,11 @@
 	rq->flags = REQ_DRIVE_TASKFILE;
 }
 
-int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, byte *buf)
+EXPORT_SYMBOL(ide_init_drive_taskfile);
+
+#if 1
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 {
 	struct request rq;
 
@@ -1919,10 +1311,78 @@
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+#else
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+	struct request *rq;
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	struct list_head *queue_head = &drive->queue.queue_head;
+	DECLARE_COMPLETION(wait);
+
+	if (HWIF(drive)->chipset == ide_pdc4030 && buf != NULL)
+		return -ENOSYS; /* special drive cmds not supported */
+
+	memset(rq, 0, sizeof(*rq));
+	rq->flags = REQ_DRIVE_TASKFILE;
+	rq->buffer = buf;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0) {
+			ata_nsector_t nsector;
+			nsector.b.low = args->hobRegister[IDE_NSECTOR_OFFSET_HOB];
+			nsector.b.high = args->tfRegister[IDE_NSECTOR_OFFSET];
+			rq.nr_sectors = nsector.all;
+		} else {
+			rq.nr_sectors = data_size / SECTOR_SIZE;
+		}
+		rq.current_nr_sectors = rq.nr_sectors;
+	//	rq.hard_cur_sectors = rq.nr_sectors;
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+	}
+	rq->special = args;
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->waiting = &wait;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	queue_head = queue_head->prev;
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	wait_for_completion(&wait);	/* wait for it to be serviced */
+	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+}
+
+#endif
+
+EXPORT_SYMBOL(ide_diag_taskfile);
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
 {
 	return ide_diag_taskfile(drive, args, 0, buf);
 }
+
+EXPORT_SYMBOL(ide_raw_taskfile);
 	
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 char * ide_ioctl_verbose (unsigned int cmd)
@@ -1930,7 +1390,7 @@
 	return("unknown");
 }
 
-char * ide_task_cmd_verbose (byte task)
+char * ide_task_cmd_verbose (u8 task)
 {
 	return("unknown");
 }
@@ -1938,19 +1398,28 @@
 
 #define MAX_DMA		(256*SECTOR_WORDS)
 
+ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+ide_startstop_t flagged_task_no_data_intr(ide_drive_t *);
+ide_startstop_t flagged_task_in_intr(ide_drive_t *);
+ide_startstop_t flagged_task_mulin_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_out_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_out_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_mulout_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_mulout_intr(ide_drive_t *);
+
 int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	ide_task_request_t	*req_task;
 	ide_task_t		args;
-	byte *outbuf		= NULL;
-	byte *inbuf		= NULL;
+	u8 *outbuf		= NULL;
+	u8 *inbuf		= NULL;
 	task_ioreg_t *argsptr	= args.tfRegister;
 	task_ioreg_t *hobsptr	= args.hobRegister;
 	int err			= 0;
 	int tasksize		= sizeof(struct ide_task_request_s);
 	int taskin		= 0;
 	int taskout		= 0;
-	byte io_32bit		= drive->io_32bit;
+	u8 io_32bit		= drive->io_32bit;
 
 //	printk("IDE Taskfile ...\n");
 
@@ -1993,7 +1462,7 @@
 		}
 	}
 
-	memset (&args, 0, sizeof (ide_task_t) );
+	memset(&args, 0, sizeof(ide_task_t));
 	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
 	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
@@ -2136,8 +1605,26 @@
 	return err;
 }
 
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
-int set_transfer(ide_drive_t *drive, ide_task_t *args);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
+
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+	struct request rq;
+	u8 buffer[4];
+
+	if (!buf)
+		buf = buffer;
+	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = cmd;
+	*buf++ = nsect;
+	*buf++ = feature;
+	*buf++ = sectors;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+EXPORT_SYMBOL(ide_wait_cmd);
 
 /*
  * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
@@ -2146,8 +1633,8 @@
 {
 #if 1
 	int err = 0;
-	byte args[4], *argbuf = args;
-	byte xfer_rate = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
 	int argsize = 4;
 	ide_task_t tfargs;
 
@@ -2200,8 +1687,8 @@
 #else
 
 	int err = 0;
-	byte args[4], *argbuf = args;
-	byte xfer_rate = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
 	int argsize = 0;
 	ide_task_t tfargs;
 
@@ -2246,7 +1733,6 @@
 		ide_driveid_update(drive);
 	}
 abort:
-
 	args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
 	args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
 	args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
@@ -2262,16 +1748,29 @@
 	return err;
 
 #endif
+}
+
+EXPORT_SYMBOL(ide_cmd_ioctl);
 
+int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf)
+{
+	struct request rq;
+
+	ide_init_drive_cmd(&rq);
+	rq.flags = REQ_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
+EXPORT_SYMBOL(ide_wait_cmd_task);
+
 /*
  * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
  */
 int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
-	byte args[7], *argbuf = args;
+	u8 args[7], *argbuf = args;
 	int argsize = 7;
 
 	if (copy_from_user(args, (void *)arg, 7))
@@ -2282,487 +1781,412 @@
 	return err;
 }
 
-EXPORT_SYMBOL(drive_is_ready);
-EXPORT_SYMBOL(wait_for_ready);
+EXPORT_SYMBOL(ide_task_ioctl);
 
-EXPORT_SYMBOL(task_read_24);
-EXPORT_SYMBOL(ata_input_data);
-EXPORT_SYMBOL(ata_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
-EXPORT_SYMBOL(taskfile_input_data);
-EXPORT_SYMBOL(taskfile_output_data);
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations.  Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+#if DEBUG_TASKFILE
+	u8 status;
+#endif
 
-EXPORT_SYMBOL(ide_wait_stat);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(flagged_taskfile);
-EXPORT_SYMBOL(ide_end_taskfile);
 
-EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-EXPORT_SYMBOL(task_no_data_intr);
-EXPORT_SYMBOL(task_in_intr);
-EXPORT_SYMBOL(task_mulin_intr);
-EXPORT_SYMBOL(pre_task_out_intr);
-EXPORT_SYMBOL(task_out_intr);
-EXPORT_SYMBOL(pre_task_mulout_intr);
-EXPORT_SYMBOL(task_mulout_intr);
+	/*
+	 * (ks) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
+        }
 
-EXPORT_SYMBOL(ide_init_drive_taskfile);
-EXPORT_SYMBOL(ide_raw_taskfile);
-EXPORT_SYMBOL(ide_pre_handler_parser);
-EXPORT_SYMBOL(ide_handler_parser);
-EXPORT_SYMBOL(ide_post_handler_parser);
-EXPORT_SYMBOL(ide_cmd_type_parser);
-EXPORT_SYMBOL(ide_taskfile_ioctl);
-EXPORT_SYMBOL(ide_cmd_ioctl);
-EXPORT_SYMBOL(ide_task_ioctl);
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+        }
 
-/*
- * Beginning of Taskfile OPCODE Library and feature sets.
- */
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	SELECT_MASK(drive, 0);
 
-/*
- *  All hosts that use the 80c ribbon must use!
- *  The name is derived from upper byte of word 93 and the 80c ribbon.
- */
-byte eighty_ninty_three (ide_drive_t *drive)
-{
-#if 0
-	if (!HWIF(drive)->udma_four)
-		return 0;
+#if DEBUG_TASKFILE
+	status = hwif->INB(IDE_STATUS_REG);
+	if (status & 0x80) {
+		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+		udelay(100);
+		status = hwif->INB(IDE_STATUS_REG);
+		printk("flagged_taskfile -> Status = %02x\n", status);
+	}
+#endif
 
-	if (drive->id->major_rev_num) {
-		int hssbd = 0;
-		int i;
-		/*
-		 * Determime highest Supported SPEC
-		 */
-		for (i=1; i<=15; i++)
-			if (drive->id->major_rev_num & (1<<i))
-				hssbd++;
-
-		switch (hssbd) {
-			case 7:
-
-			case 6:
-			case 5:
-		/* ATA-4 and older do not support above Ultra 33 */
-			default:
-				return 0;
-		}
+	if (task->tf_out_flags.b.data) {
+		u16 data =  taskfile->data + (hobfile->data << 8);
+		hwif->OUTW(data, IDE_DATA_REG);
 	}
 
-	return ((byte) (
-#ifndef CONFIG_IDEDMA_IVB
-		(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+	/* (ks) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
 
-#else
+	/* (ks) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 
-	return ((byte) ((HWIF(drive)->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-			(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-			(drive->id->hw_config & 0x6000)) ? 1 : 0);
-#endif
+        /*
+	 * (ks) In the flagged taskfile approch, we will used all specified
+	 * registers and the register value will not be changed. Except the
+	 * select bit (master/slave) in the drive_head register. We must make
+	 * sure that the desired drive is selected.
+	 */
+	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	switch(task->data_phase) {
+
+   	        case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			hwif->ide_dma_write(drive);
+			break;
+
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			hwif->ide_dma_read(drive);
+			break;
+
+	        default:
+ 			if (task->handler == NULL)
+				return ide_stopped;
+
+			ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+			/* Issue the command */
+			hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+
+	return ide_started;
 }
 
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+EXPORT_SYMBOL(flagged_taskfile);
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
 {
-	if (!HWIF(drive)->udma_four) {
-		printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n",
-			HWIF(drive)->name);
-		return 1;
-	}
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-#ifndef CONFIG_IDEDMA_IVB
-		if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-		if (((drive->id->hw_config & 0x2000) == 0) ||
-		    ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
-			return 1;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+
+	local_irq_enable();
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
 		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+ 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
 	}
-	return 0;
+
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+
+	return ide_stopped;
 }
 
 /*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
+ * Handler for command with PIO data-in phase
  */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
+ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
 {
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
-	    (drive->id->dma_ultra ||
-	     drive->id->dma_mword ||
-	     drive->id->dma_1word))
-		return 1;
-
-	return 0;
-}
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
 
-byte ide_auto_reduce_xfer (ide_drive_t *drive)
-{
-	if (!drive->crc_count)
-		return drive->current_speed;
-	drive->crc_count = 0;
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
 
-	switch(drive->current_speed) {
-		case XFER_UDMA_7:	return XFER_UDMA_6;
-		case XFER_UDMA_6:	return XFER_UDMA_5;
-		case XFER_UDMA_5:	return XFER_UDMA_4;
-		case XFER_UDMA_4:	return XFER_UDMA_3;
-		case XFER_UDMA_3:	return XFER_UDMA_2;
-		case XFER_UDMA_2:	return XFER_UDMA_1;
-		case XFER_UDMA_1:	return XFER_UDMA_0;
-			/*
-			 * OOPS we do not goto non Ultra DMA modes
-			 * without iCRC's available we force
-			 * the system to PIO and make the user
-			 * invoke the ATA-1 ATA-2 DMA modes.
-			 */
-		case XFER_UDMA_0:
-		default:		return XFER_PIO_4;
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
 	}
-}
 
-int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf)
-{
-	ide_task_t args;
-	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
-	if (drive->media == ide_disk)
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
-	else
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
-	args.command_type			= ide_cmd_type_parser(&args);
-	return ide_raw_taskfile(drive, &args, buf);
-}
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
 
-/*
- * Update the 
- */
-int ide_driveid_update (ide_drive_t *drive)
-{
-#if 0
-	struct hd_driveid *id;
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
 
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id)
-		return 0;
-
-	taskfile_lib_get_identify(drive, (char *)&id);
-
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
+	if (--rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
 	}
-	return 1;
-#else
 	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
 	 */
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
-
-	SELECT_MASK(HWIF(drive), drive, 1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	ide_delay_50ms();
-	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (time_after(jiffies, timeout)) {
-			SELECT_MASK(HWIF(drive), drive, 0);
-			return 0;	/* drive timed-out */
-		}
-		ide_delay_50ms();	/* give drive a breather */
-	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
-	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
-	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(HWIF(drive), drive, 0);
-		printk("%s: CHECK for good STATUS\n", drive->name);
-		return 0;
-	}
-	local_irq_save(flags);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		local_irq_restore(flags);
-		return 0;
-	}
-	ata_input_data(drive, id, SECTOR_WORDS);
-	(void) GET_STAT();	/* clear drive IRQ */
-	local_irq_enable();
-	local_irq_restore(flags);
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
-	}
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-	return 1;
-#endif
+	return ide_stopped;
 }
 
-
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
+ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	int	i, error	= 1;
-	byte stat;
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+	unsigned int msect, nsect;
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	hwif->dmaproc(ide_dma_host_off, drive);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
 
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	udelay(1);
-	/*
-	 * Wait for drive to become non-BUSY
-	 */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		unsigned long flags, timeout;
-		local_irq_set(flags);
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (time_after(jiffies, timeout))
-				break;
-		}
-		local_irq_restore(flags);
-	}
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
 
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-			error = 0;
-			break;
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
 		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
 	}
 
-	SELECT_MASK(HWIF(drive), drive, 0);
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
 
-	enable_irq(hwif->irq);
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
 
-	if (error) {
-		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
-		return error;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	if (speed >= XFER_SW_DMA_0)
-		hwif->dmaproc(ide_dma_host_on, drive);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	drive->current_speed = speed;
-	return error;
-}
-
-EXPORT_SYMBOL(eighty_ninty_three);
-EXPORT_SYMBOL(ide_auto_reduce_xfer);
-EXPORT_SYMBOL(set_transfer);
-EXPORT_SYMBOL(taskfile_lib_get_identify);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_config_drive_speed);
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
 
-#ifdef CONFIG_PKT_TASK_IOCTL
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
+	}
 
-#if 0
-{
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+
+	return ide_stopped;
+}
 
-{ /* start cdrom */
+/*
+ * Pre handler for command with PIO data-out phase
+ */
+ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	ide_startstop_t startstop;
 
-	struct cdrom_info *info = drive->driver_data;
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
+	}
 
-	if (info->dma) {
-		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
-		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
-		} else {
-			printk("ide-cd: DMA set, but not allowed\n");
-		}
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
 	}
 
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+	return ide_started;
+}
 
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return ide_started;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
 	}
 
-} /* end cdrom */
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
+	}
 
-{ /* start floppy */
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
+		(int) rq->current_nr_sectors, stat);
 
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	floppy->pc=pc;		/* Set the current packet command */
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
 
-	pc->retries++;
-	pc->actually_transferred=0; /* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+	return ide_started;
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	char *pBuf		= NULL;
+	ide_startstop_t startstop;
+	unsigned int msect, nsect;
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+	if (!rq->current_nr_sectors) 
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-} /* end floppy */
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
 
-{ /* start tape */
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
 
-	idetape_tape_t *tape = drive->driver_data;
+	rq->current_nr_sectors -= nsect;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+	return ide_started;
+}
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return ide_started;
-	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idetape_transfer_pc(drive);
+ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect, nsect;
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
 	}
 
-} /* end tape */
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
 
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	rq->current_nr_sectors -= nsect;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
 }
-#endif
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+
+#ifdef CONFIG_PKT_TASK_IOCTL
 
 int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/ide/ide.c	Sun Sep 15 19:19:29 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
+ *  linux/drivers/ide/ide.c		Version 7.00alpha1	August 19 2002
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -12,7 +12,8 @@
  *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to MAX_HWIFS 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:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
@@ -113,6 +114,7 @@
  * Version 6.31		Debug Share INTR's and request queue streaming
  *			Native ATA-100 support
  *			Prep for Cascades Project
+ * Version 7.00alpha	First named revision of ide rearrange
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
@@ -121,8 +123,8 @@
  *
  */
 
-#define	REVISION	"Revision: 6.31"
-#define	VERSION		"Id: ide.c 6.31 2000/06/09"
+#define	REVISION	"Revision: 7.00alpha2"
+#define	VERSION		"Id: ide.c 7.00a2 20020906"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -141,9 +143,7 @@
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
 #include <linux/slab.h>
-#ifndef MODULE
 #include <linux/init.h>
-#endif /* MODULE */
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -161,28 +161,24 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
 
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
-
-static int	idebus_parameter; /* holds the "idebus=" parameter */
-static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
-static int	initializing;     /* set while initializing built-in drivers */
+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+					IDE2_MAJOR, IDE3_MAJOR,
+					IDE4_MAJOR, IDE5_MAJOR,
+					IDE6_MAJOR, IDE7_MAJOR,
+					IDE8_MAJOR, IDE9_MAJOR };
+
+static int idebus_parameter;	/* holds the "idebus=" parameter */
+static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
+static int initializing;	/* set while initializing built-in drivers */
 
 spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-#ifdef CONFIG_BLK_DEV_IDESCSI_24
-#define CONFIG_BLK_DEV_IDESCSI
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 /*
@@ -192,33 +188,57 @@
 static int	ide_intr_lock;
 #endif /* __mc68000__ || CONFIG_APUS */
 
+#ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
+ide_module_t *ide_chipsets;
 ide_module_t *ide_probe;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
+
+EXPORT_SYMBOL(ide_hwifs);
+
+ide_devices_t *idedisk;
+ide_devices_t *idecd;
+ide_devices_t *idefloppy;
+ide_devices_t *idetape;
+ide_devices_t *idescsi;
+
+EXPORT_SYMBOL(idedisk);
+EXPORT_SYMBOL(idecd);
+EXPORT_SYMBOL(idefloppy);
+EXPORT_SYMBOL(idetape);
+EXPORT_SYMBOL(idescsi);
 
 #if (DISK_RECOVERY_TIME > 0)
+
+Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43
+Does anyone ever use this anyway ??
+
 /*
  * For really screwy hardware (hey, at least it *can* be used with Linux)
  * we can enforce a minimum delay time between successive operations.
  */
-static unsigned long read_timer (void)
+static unsigned long read_timer (ide_hwif_t *hwif)
 {
 	unsigned long t, flags;
 	int i;
-
+	
+	/* FIXME this is completely unsafe! */
 	local_irq_save(flags);
 	t = jiffies * 11932;
-    	outb_p(0, 0x43);
+	outb_p(0, 0x43);
 	i = inb_p(0x40);
-	i |= IN_BYTE(0x40) << 8;
+	i |= inb_p(0x40) << 8;
 	local_irq_restore(flags);
 	return (t - i);
 }
@@ -227,7 +247,7 @@
 static inline void set_recovery_timer (ide_hwif_t *hwif)
 {
 #if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer();
+	hwif->last_time = read_timer(hwif);
 #endif /* DISK_RECOVERY_TIME */
 }
 
@@ -260,6 +280,16 @@
 	hwif->name[2]	= 'e';
 	hwif->name[3]	= '0' + index;
 	hwif->bus_state = BUSSTATE_ON;
+	hwif->reset_poll= NULL;
+	hwif->pre_reset = NULL;
+
+	hwif->atapi_dma = 0;		/* disable all atapi dma */ 
+	hwif->ultra_mask = 0x80;	/* disable all ultra */
+	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
+	hwif->swdma_mask = 0x80;	/* disable all swdma */
+
+	default_hwif_iops(hwif);
+	default_hwif_transport(hwif);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
@@ -275,6 +305,8 @@
 		drive->name[1]			= 'd';
 		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		drive->using_dma		= 0;
+		drive->is_flash			= 0;
 		INIT_LIST_HEAD(&drive->list);
 	}
 }
@@ -292,6 +324,9 @@
  * 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.
+ *
+ * FIXME: We should stuff the setup data into __init and copy the
+ * relevant hwifs/allocate them properly during boot.
  */
 #define MAGIC_COOKIE 0x12345678
 static void __init init_ide_data (void)
@@ -315,37 +350,6 @@
 }
 
 /*
- * CompactFlash cards and their brethern pretend to be removable hard disks, except:
- *	(1) they never have a slave unit, and
- *	(2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
- * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
- * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
- * At that time, we might also consider parameterizing the timeouts and retries,
- * since these are MUCH faster than mechanical drives.	-M.Lord
- */
-int drive_is_flashcard (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a) return 1;	/* CompactFlash */
-		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
-		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
-		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
-		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
-		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
-		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
-		{
-			return 1;	/* yes, it is a flash memory card */
-		}
-	}
-	return 0;	/* no, it is not a flash memory card */
-}
-
-/*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
  * bus speed (in MHz).  This is used for calculating interface PIO timings.
  * The default is 40 for known PCI systems, 50 otherwise.
@@ -355,15 +359,18 @@
 int ide_system_bus_speed (void)
 {
 	if (!system_bus_speed) {
-		if (idebus_parameter)
-			system_bus_speed = idebus_parameter;	/* user supplied value */
-#ifdef CONFIG_PCI
-		else if (pci_present())
-			system_bus_speed = 33;	/* safe default value for PCI */
-#endif /* CONFIG_PCI */
-		else
-			system_bus_speed = 50;	/* safe default value for VESA and PCI */
-		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
+		if (idebus_parameter) {
+			/* user supplied value */
+			system_bus_speed = idebus_parameter;
+		} else if (pci_present()) {
+			/* safe default value for PCI */
+			system_bus_speed = 33;
+		} else {
+			/* safe default value for VESA and PCI */
+			system_bus_speed = 50;
+		}
+		printk("ide: Assuming %dMHz system bus speed "
+			"for PIO modes%s\n", system_bus_speed,
 			idebus_parameter ? "" : "; override with idebus=xx");
 	}
 	return system_bus_speed;
@@ -372,7 +379,7 @@
 /*
  * This is our end_request replacement function.
  */
-int ide_end_request (ide_drive_t *drive, int uptodate)
+int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
 {
 	struct request *rq;
 	unsigned long flags;
@@ -383,16 +390,19 @@
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
 
+	if (!nr_sectors)
+		nr_sectors = rq->hard_cur_sectors;
+
 	/*
 	 * decide whether to reenable DMA -- 3 is a random magic for now,
 	 * if we DMA timeout more than 3 times, just stay in PIO
 	 */
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive);
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
 	}
 
-	if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) {
+	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
 		add_blkdev_randomness(major(rq->rq_dev));
 		blkdev_dequeue_request(rq);
 		HWGROUP(drive)->rq = NULL;
@@ -403,30 +413,7 @@
 	return ret;
 }
 
-/*
- * 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 ide_timer_expiry() handler later on).
- */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-		      unsigned int timeout, ide_expiry_t *expiry)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	spin_lock_irqsave(&ide_lock, flags);
-	if (hwgroup->handler != NULL) {
-		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
-			drive->name, hwgroup->handler, handler);
-	}
-	hwgroup->handler	= handler;
-	hwgroup->expiry		= expiry;
-	hwgroup->timer.expires	= jiffies + timeout;
-	add_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
+EXPORT_SYMBOL(ide_end_request);
 
 /*
  * current_capacity() returns the capacity (in sectors) of a drive
@@ -441,232 +428,21 @@
 	return 0;
 }
 
-extern struct block_device_operations ide_fops[];
-
-static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	byte stat;
-
-	SELECT_DRIVE(HWIF(drive),drive);
-	udelay (10);
-
-	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
-		printk("%s: ATAPI reset complete\n", drive->name);
-	} else {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		hwgroup->poll_timeout = 0;	/* end of polling */
-		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		return do_reset1 (drive, 1);	/* do it the old fashioned way */
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tmp;
-
-	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
-		drive->failures++;
-	} else  {
-		printk("%s: reset: ", hwif->name);
-		if ((tmp = GET_ERR()) == 1) {
-			printk("success\n");
-			drive->failures = 0;
-		} else {
-			drive->failures++;
-#if FANCY_STATUS_DUMPS
-			printk("master: ");
-			switch (tmp & 0x7f) {
-				case 1: printk("passed");
-					break;
-				case 2: printk("formatter device error");
-					break;
-				case 3: printk("sector buffer error");
-					break;
-				case 4: printk("ECC circuitry error");
-					break;
-				case 5: printk("controlling MPU error");
-					break;
-				default:printk("error (0x%02x?)", tmp);
-			}
-			if (tmp & 0x80)
-				printk("; slave: failed");
-			printk("\n");
-#else
-			printk("failed\n");
-#endif /* FANCY_STATUS_DUMPS */
-		}
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-static void check_dma_crc (ide_drive_t *drive)
-{
-	if (drive->crc_count) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
-		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
-	} else {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-}
-
-static void pre_reset (ide_drive_t *drive)
-{
-	if (drive->driver != NULL)
-		DRIVER(drive)->pre_reset(drive);
-
-	if (!drive->keep_settings) {
-		if (drive->using_dma) {
-			check_dma_crc(drive);
-		} else {
-			drive->unmask = 0;
-			drive->io_32bit = 0;
-		}
-		return;
-	}
-	if (drive->using_dma)
-		check_dma_crc(drive);
-}
-
-/*
- * do_reset1() 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 which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * 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 ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
-{
-	unsigned int unit;
-	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	local_irq_save(flags);
-
-	/* For an ATAPI device, first try an ATAPI SRST. */
-	if (drive->media != ide_disk && !do_not_try_atapi) {
-		pre_reset(drive);
-		SELECT_DRIVE(hwif,drive);
-		udelay (20);
-		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-			BUG();
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		local_irq_restore(flags);
-		return ide_started;
-	}
-
-	/*
-	 * First, reset any device state data we were maintaining
-	 * for any of the drives on this interface.
-	 */
-	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		pre_reset(&hwif->drives[unit]);
-
-#if OK_TO_RESET_CONTROLLER
-	if (!IDE_CONTROL_REG) {
-		local_irq_restore(flags);
-		return ide_stopped;
-	}
-	/*
-	 * 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 SRST and nIEN */
-	udelay(10);			/* more than enough time */
-	if (drive->quirk_list == 2) {
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
-	} else {
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	}
-	udelay(10);			/* more than enough time */
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-		BUG();
-	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-
-	/*
-	 * Some weird controller like resetting themselves to a strange
-	 * state when the disks are reset this way. At least, the Winbond
-	 * 553 documentation says that
-	 */
-	if (hwif->resetproc != NULL)
-		hwif->resetproc(drive);
-
-#endif	/* OK_TO_RESET_CONTROLLER */
-
-	local_irq_restore(flags);
-	return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
-	return do_reset1 (drive, 0);
-}
+EXPORT_SYMBOL(current_capacity);
 
 static inline u32 read_24 (ide_drive_t *drive)
 {
-	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
+	return  (HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
 /*
  * Clean up after success/failure of an explicit drive cmd
  */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
+void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 
@@ -675,28 +451,28 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 
 	if (rq->flags & REQ_DRIVE_CMD) {
-		byte *args = (byte *) rq->buffer;
+		u8 *args = (u8 *) rq->buffer;
 		if (rq->errors == 0)
 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
 		if (args) {
 			args[0] = stat;
 			args[1] = err;
-			args[2] = IN_BYTE(IDE_NSECTOR_REG);
+			args[2] = hwif->INB(IDE_NSECTOR_REG);
 		}
 	} else if (rq->flags & REQ_DRIVE_TASK) {
-		byte *args = (byte *) rq->buffer;
+		u8 *args = (u8 *) rq->buffer;
 		if (rq->errors == 0)
 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
 		if (args) {
 			args[0] = stat;
 			args[1] = err;
-			args[2] = IN_BYTE(IDE_NSECTOR_REG);
-			args[3] = IN_BYTE(IDE_SECTOR_REG);
-			args[4] = IN_BYTE(IDE_LCYL_REG);
-			args[5] = IN_BYTE(IDE_HCYL_REG);
-			args[6] = IN_BYTE(IDE_SELECT_REG);
+			args[2] = hwif->INB(IDE_NSECTOR_REG);
+			args[3] = hwif->INB(IDE_SECTOR_REG);
+			args[4] = hwif->INB(IDE_LCYL_REG);
+			args[5] = hwif->INB(IDE_HCYL_REG);
+			args[6] = hwif->INB(IDE_SELECT_REG);
 		}
 	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = (ide_task_t *) rq->special;
@@ -705,27 +481,25 @@
 			
 		if (args) {
 			if (args->tf_in_flags.b.data) {
-				unsigned short data			= IN_WORD(IDE_DATA_REG);
+				u16 data				= hwif->INW(IDE_DATA_REG);
 				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
 				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
 			}
 			args->tfRegister[IDE_ERROR_OFFSET]   = err;
-			args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-			args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-			args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-			args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-			args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+			args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+			args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+			args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+			args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+			args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
 			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 
-			if ((drive->id->command_set_2 & 0x0400) &&
-			    (drive->id->cfs_enable_2 & 0x0400) &&
-			    (drive->addressing == 1)) {
-				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+			if (drive->addressing == 1) {
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
 			}
 		}
 	}
@@ -737,21 +511,24 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
 	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (stat & BUSY_STAT) {
 		printk("Busy ");
-	else {
+	} else {
 		if (stat & READY_STAT)	printk("DriveReady ");
 		if (stat & WRERR_STAT)	printk("DeviceFault ");
 		if (stat & SEEK_STAT)	printk("SeekComplete ");
@@ -764,13 +541,13 @@
 #endif	/* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
 		if (drive->media == ide_disk) {
 			printk(" { ");
 			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+			if (err & ICRC_ERR)	printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
 			if (err & ECC_ERR)	printk("UncorrectableError ");
 			if (err & ID_ERR)	printk("SectorIdNotFound ");
 			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
@@ -780,30 +557,30 @@
 				if ((drive->id->command_set_2 & 0x0400) &&
 				    (drive->id->cfs_enable_2 & 0x0400) &&
 				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = read_24(drive);
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+					u64 sectors = 0;
+					u32 high = 0;
+					u32 low = read_24(drive);
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
 					high = read_24(drive);
 
-					sectors = ((__u64)high << 24) | low;
+					sectors = ((u64)high << 24) | low;
 					printk(", LBAsect=%llu, high=%d, low=%d",
-					       (unsigned long long) sectors,
+					       (u64) sectors,
 					       high, low);
 				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
+					u8 cur = hwif->INB(IDE_SELECT_REG);
 					if (cur & 0x40) {	/* using LBA? */
 						printk(", LBAsect=%ld", (unsigned long)
 						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
+						 |(hwif->INB(IDE_HCYL_REG)<<16)
+						 |(hwif->INB(IDE_LCYL_REG)<<8)
+						 | hwif->INB(IDE_SECTOR_REG));
 					} else {
 						printk(", CHS=%d/%d/%d",
-						 (IN_BYTE(IDE_HCYL_REG)<<8) +
-						  IN_BYTE(IDE_LCYL_REG),
+						 (hwif->INB(IDE_HCYL_REG)<<8) +
+						  hwif->INB(IDE_LCYL_REG),
 						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
+						  hwif->INB(IDE_SECTOR_REG));
 					}
 				}
 				if (HWGROUP(drive) && HWGROUP(drive)->rq)
@@ -817,6 +594,8 @@
 	return err;
 }
 
+EXPORT_SYMBOL(ide_dump_status);
+
 /*
  * try_to_flush_leftover_data() is invoked in response to a drive
  * unexpectedly having its DRQ_STAT bit set.  As an alternative to
@@ -824,7 +603,7 @@
  * 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)
+void try_to_flush_leftover_data (ide_drive_t *drive)
 {
 	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
@@ -832,12 +611,15 @@
 		return;
 	while (i > 0) {
 		u32 buffer[16];
-		unsigned int wcount = (i > 16) ? 16 : i;
+		u32 wcount = (i > 16) ? 16 : i;
+
 		i -= wcount;
-		ata_input_data (drive, buffer, wcount);
+		HWIF(drive)->ata_input_data(drive, buffer, wcount);
 	}
 }
 
+EXPORT_SYMBOL(try_to_flush_leftover_data);
+
 /*
  * FIXME Add an ATAPI error
  */
@@ -845,56 +627,70 @@
 /*
  * ide_error() takes action based on the error returned by the drive.
  */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 
 	err = ide_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
 	if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
 		rq->errors = 1;
 		ide_end_drive_cmd(drive, stat, err);
 		return ide_stopped;
-	} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+	}
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		rq->errors = 1;
 		ide_end_drive_cmd(drive, stat, err);
 //		ide_end_taskfile(drive, stat, err);
 		return ide_stopped;
 	}
 
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		 /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
+		if (drive->media != ide_disk)
+			goto media_out;
 
-/* ide_disk */
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+		if (stat & ERR_STAT) {
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++; /* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				drive->crc_count++;
+				/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
 				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
+			}
 		}
-/* !ide_disk */
-		if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+media_out:
+		if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
 			try_to_flush_leftover_data(drive);
-/* !ide_disk */
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX) {
 		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(drive, 0);
+			DRIVER(drive)->end_request(drive, 0, 0);
 		else
-	 		ide_end_request(drive, 0);
+	 		ide_end_request(drive, 0, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -907,53 +703,62 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(ide_error);
+
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
  */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler)
 {
-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+	ide_hwif_t *hwif = HWIF(drive);
+	if (HWGROUP(drive)->handler != NULL)
 		BUG();
-	ide_set_handler (drive, handler, WAIT_CMD, NULL);
+	ide_set_handler(drive, handler, WAIT_CMD, NULL);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive),drive,0);
-	OUT_BYTE(nsect,IDE_NSECTOR_REG);
-	OUT_BYTE(cmd,IDE_COMMAND_REG);
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive,0);
+	hwif->OUTB(nsect,IDE_NSECTOR_REG);
+	hwif->OUTB(cmd,IDE_COMMAND_REG);
 }
 
+EXPORT_SYMBOL(ide_cmd);
+
 /*
  * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
  */
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
-	byte *args = (byte *) rq->buffer;
-	byte stat = GET_STAT();
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 *args = (u8 *) rq->buffer;
+	u8 stat = hwif->INB(IDE_STATUS_REG);
 	int retries = 10;
 
 	local_irq_enable();
 	if ((stat & DRQ_STAT) && args && args[3]) {
-		byte io_32bit = drive->io_32bit;
+		u8 io_32bit = drive->io_32bit;
 		drive->io_32bit = 0;
-		ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
 		drive->io_32bit = io_32bit;
-		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
+		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
 			udelay(100);
 	}
 
 	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
-	ide_end_drive_cmd (drive, stat, GET_ERR());
+		return DRIVER(drive)->error(drive, "drive_cmd", stat);
+		/* calls ide_end_drive_cmd */
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(drive_cmd_intr);
+
 /*
  * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
  * commands to a drive.  It used to do much more, but has been scaled back.
  */
-static ide_startstop_t do_special (ide_drive_t *drive)
+ide_startstop_t do_special (ide_drive_t *drive)
 {
 	special_t *s = &drive->special;
 
@@ -973,12 +778,15 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(do_special);
+
 /*
  * execute_drive_cmd() issues a special drive command,
  * usually initiated by ioctl() from the external hdparm program.
  */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	if (rq->flags & REQ_DRIVE_TASKFILE) {
  		ide_task_t *args = rq->special;
  
@@ -989,8 +797,8 @@
 			return flagged_taskfile(drive, args);
 		return do_rw_taskfile(drive, args);
 	} else if (rq->flags & REQ_DRIVE_TASK) {
- 		byte *args = rq->buffer;
- 		byte sel;
+		u8 *args = rq->buffer;
+		u8 sel;
  
 		if (!args)
 			goto done;
@@ -1004,18 +812,18 @@
  		printk("hcyl=0x%02x ", args[5]);
  		printk("sel=0x%02x\n", args[6]);
 #endif
- 		OUT_BYTE(args[1], IDE_FEATURE_REG);
- 		OUT_BYTE(args[3], IDE_SECTOR_REG);
- 		OUT_BYTE(args[4], IDE_LCYL_REG);
- 		OUT_BYTE(args[5], IDE_HCYL_REG);
+ 		hwif->OUTB(args[1], IDE_FEATURE_REG);
+ 		hwif->OUTB(args[3], IDE_SECTOR_REG);
+ 		hwif->OUTB(args[4], IDE_LCYL_REG);
+ 		hwif->OUTB(args[5], IDE_HCYL_REG);
  		sel = (args[6] & ~0x10);
  		if (drive->select.b.unit)
  			sel |= 0x10;
- 		OUT_BYTE(sel, IDE_SELECT_REG);
+ 		hwif->OUTB(sel, IDE_SELECT_REG);
  		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
  		return ide_started;
  	} else if (rq->flags & REQ_DRIVE_CMD) {
- 		byte *args = rq->buffer;
+ 		u8 *args = rq->buffer;
 
 		if (!args)
 			goto done;
@@ -1027,14 +835,14 @@
  		printk("xx=0x%02x\n", args[3]);
 #endif
  		if (args[0] == WIN_SMART) {
- 			OUT_BYTE(0x4f, IDE_LCYL_REG);
- 			OUT_BYTE(0xc2, IDE_HCYL_REG);
- 			OUT_BYTE(args[2],IDE_FEATURE_REG);
- 			OUT_BYTE(args[1],IDE_SECTOR_REG);
+ 			hwif->OUTB(0x4f, IDE_LCYL_REG);
+ 			hwif->OUTB(0xc2, IDE_HCYL_REG);
+ 			hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 			hwif->OUTB(args[1],IDE_SECTOR_REG);
  			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
  			return ide_started;
  		}
- 		OUT_BYTE(args[2],IDE_FEATURE_REG);
+ 		hwif->OUTB(args[2],IDE_FEATURE_REG);
  		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
  		return ide_started;
  	}
@@ -1047,16 +855,20 @@
 #ifdef DEBUG
  	printk("%s: DRIVE_CMD (null)\n", drive->name);
 #endif
- 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ 	ide_end_drive_cmd(drive,
+			hwif->INB(IDE_STATUS_REG),
+			hwif->INB(IDE_ERROR_REG));
  	return ide_stopped;
 }
 
+EXPORT_SYMBOL(execute_drive_cmd);
+
 /*
  * start_request() initiates handling of a new I/O request
  * needed to reverse the perverted changes anonymously made back
  * 2.3.99-pre6
  */
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
 	unsigned long block;
@@ -1088,15 +900,9 @@
 			hwif->name, kdevname(rq->rq_dev));
 		goto kill_rq;
 	}
-#ifdef DEBUG
-	if (rq->bh && !buffer_locked(rq->bh)) {
-		printk("%s: block not locked\n", drive->name);
-		goto kill_rq;
-	}
-#endif
-	block    = rq->sector;
 
-	if ((rq->flags & REQ_CMD) &&
+	block    = rq->sector;
+	if (blk_fs_request(rq) &&
 	    (drive->media == ide_disk || drive->media == ide_floppy)) {
 		block += drive->sect0;
 	}
@@ -1109,7 +915,7 @@
 	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
 #endif
 
-	SELECT_DRIVE(hwif, drive);
+	SELECT_DRIVE(drive);
 	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
 		printk("%s: drive not ready for command\n", drive->name);
 		return startstop;
@@ -1129,18 +935,22 @@
 	return do_special(drive);
 kill_rq:
 	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(drive, 0);
+		DRIVER(drive)->end_request(drive, 0, 0);
 	else
-		ide_end_request(drive, 0);
+		ide_end_request(drive, 0, 0);
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(start_request);
+
 int restart_request (ide_drive_t *drive, struct request *rq)
 {
 	(void) start_request(drive, rq);
 	return 0;
 }
 
+EXPORT_SYMBOL(restart_request);
+
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
  * to the hwgroup by sleeping for timeout jiffies.
@@ -1152,6 +962,8 @@
 	drive->sleep = timeout + jiffies;
 }
 
+EXPORT_SYMBOL(ide_stall_queue);
+
 #define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
 
 /*
@@ -1242,10 +1054,11 @@
 	struct request	*rq;
 	ide_startstop_t	startstop;
 
-	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */
+	/* for atari only: POSSIBLY BROKEN HERE(?) */
+	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
 
+	/* necessary paranoia: ensure IRQs are masked on local CPU */
 	local_irq_disable();
-		/* necessary paranoia: ensure IRQs are masked on local CPU */
 
 	while (!hwgroup->busy) {
 		hwgroup->busy = 1;
@@ -1271,20 +1084,30 @@
 				if (timer_pending(&hwgroup->timer))
 					printk("ide_set_handler: timer already active\n");
 #endif
-				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
+				/* so that ide_timer_expiry knows what to do */
+				hwgroup->sleeping = 1;
 				mod_timer(&hwgroup->timer, sleep);
-				/* we purposely leave hwgroup->busy==1 while sleeping */
+				/* we purposely leave hwgroup->busy==1
+				 * while sleeping */
 			} else {
-				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
-				ide_release_lock(&ide_lock);	/* for atari only */
+				/* Ugly, but how can we sleep for the lock
+				 * otherwise? perhaps from tq_disk?
+				 */
+
+				/* for atari only */
+				ide_release_lock(&ide_lock);
 				hwgroup->busy = 0;
 			}
-			return;		/* no more work for this hwgroup (for now) */
+
+			/* no more work for this hwgroup (for now) */
+			return;
 		}
 		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
+		if (hwgroup->hwif->sharing_irq &&
+		    hwif != hwgroup->hwif &&
+		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
 			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(hwif, drive);
+			SELECT_INTERRUPT(drive);
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
@@ -1317,6 +1140,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_do_request);
+
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
@@ -1327,6 +1152,8 @@
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
 
+EXPORT_SYMBOL(ide_get_queue);
+
 /*
  * Passes the stuff to ide_do_request
  */
@@ -1335,7 +1162,6 @@
 	ide_do_request(q->queuedata, 0);
 }
 
-#ifndef __IDEDMA_TIMEOUT
 /*
  * un-busy the hwgroup etc, and clear any pending DMA status. we want to
  * retry the current request in pio mode instead of risking tossing it
@@ -1349,13 +1175,13 @@
 	/*
 	 * end current dma transaction
 	 */
-	(void) hwif->dmaproc(ide_dma_end, drive);
+	(void) hwif->ide_dma_end(drive);
 
 	/*
 	 * complain a little, later we might remove some of this verbosity
 	 */
 	printk("%s: timeout waiting for DMA\n", drive->name);
-	(void) hwif->dmaproc(ide_dma_timeout, drive);
+	(void) hwif->ide_dma_timeout(drive);
 
 	/*
 	 * disable dma for now, but remember that we did so because of
@@ -1364,7 +1190,7 @@
 	 */
 	drive->retry_pio++;
 	drive->state = DMA_PIO_RETRY;
-	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
+	(void) hwif->ide_dma_off_quietly(drive);
 
 	/*
 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1379,15 +1205,9 @@
 	rq->hard_cur_sectors = rq->current_nr_sectors;
 	if (rq->bio)
 		rq->buffer = NULL;
-
-	/*
-	 * FIXME or DELETE ME
-	 *
-	 * so what do we do if the device is left in an invalid state
-	 * and will not accept commands. SOFT RESET is the only chance.
-	 */
 }
-#endif
+
+EXPORT_SYMBOL(ide_dma_timeout_retry);
 
 /*
  * ide_timer_expiry() is our timeout function for all drive operations.
@@ -1441,38 +1261,34 @@
 			hwgroup->handler = NULL;
 			/*
 			 * We need to simulate a real interrupt when invoking
-			 * the handler() function, which means we need to globally
-			 * mask the specific IRQ:
+			 * the handler() function, which means we need to
+			 * globally mask the specific IRQ:
 			 */
 			spin_unlock(&ide_lock);
 			hwif  = HWIF(drive);
 #if DISABLE_IRQ_NOSYNC
 			disable_irq_nosync(hwif->irq);
 #else
-			disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+			/* disable_irq_nosync ?? */
+			disable_irq(hwif->irq);
 #endif /* DISABLE_IRQ_NOSYNC */
+			/* local CPU only,
+			 * as if we were handling an interrupt */
 			local_irq_disable();
-				/* local CPU only, as if we were handling an interrupt */
 			if (hwgroup->poll_timeout != 0) {
 				startstop = handler(drive);
 			} else if (drive_is_ready(drive)) {
 				if (drive->waiting_for_dma)
-					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
+					(void) hwgroup->hwif->ide_dma_lostirq(drive);
 				(void)ide_ack_intr(hwif);
 				printk("%s: lost interrupt\n", drive->name);
 				startstop = handler(drive);
 			} else {
 				if (drive->waiting_for_dma) {
-#ifndef __IDEDMA_TIMEOUT
 					startstop = ide_stopped;
 					ide_dma_timeout_retry(drive);
-#else /* __IDEDMA_TIMEOUT */
-					(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
-					printk("%s: timeout waiting for DMA\n", drive->name);
-					(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
-#endif /* __IDEDMA_TIMEOUT */
 				} else
-					startstop = DRIVER(drive)->error(drive, "irq timeout", GET_STAT());
+					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
 			}
 			set_recovery_timer(hwif);
 			drive->service_time = jiffies - drive->service_start;
@@ -1486,6 +1302,8 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_timer_expiry);
+
 /*
  * There's nothing really useful we can do with an unexpected interrupt,
  * other than reading the status register (to clear it), and logging it.
@@ -1511,7 +1329,7 @@
  */
 static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
-	byte stat;
+	u8 stat;
 	ide_hwif_t *hwif = hwgroup->hwif;
 
 	/*
@@ -1519,15 +1337,17 @@
 	 */
 	do {
 		if (hwif->irq == irq) {
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
 			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
 				/* Try to not flood the console with msgs */
 				static unsigned long last_msgtime, count;
 				++count;
 				if (time_after(jiffies, last_msgtime + HZ)) {
 					last_msgtime = jiffies;
-					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
-					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
+					printk("%s%s: unexpected interrupt, "
+						"status=0x%02x, count=%ld\n",
+						hwif->name,
+						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
 				}
 			}
 		}
@@ -1554,7 +1374,9 @@
 		return;
 	}
 
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
+	if ((handler = hwgroup->handler) == NULL ||
+	    hwgroup->poll_timeout != 0) {
+		printk("ide_intr: unexpected interrupt!\n");
 		/*
 		 * Not expecting an interrupt from this drive.
 		 * That means this could be:
@@ -1568,7 +1390,7 @@
 		 * so in that case we just ignore it and hope it goes away.
 		 */
 #ifdef CONFIG_BLK_DEV_IDEPCI
-		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+		if (hwif->pci_dev && !hwif->pci_dev->vendor)
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 		{
 			/*
@@ -1582,7 +1404,7 @@
 			 * Whack the status register, just in case
 			 * we have a leftover pending IRQ.
 			 */
-			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			(void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 		}
 		spin_unlock_irqrestore(&ide_lock, flags);
@@ -1618,7 +1440,8 @@
 
 	if (drive->unmask)
 		local_irq_enable();
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);
 	spin_lock_irq(&ide_lock);
 
 	/*
@@ -1635,12 +1458,15 @@
 			hwgroup->busy = 0;
 			ide_do_request(hwgroup, hwif->irq);
 		} else {
-			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
+			printk("%s: ide_intr: huh? expected NULL handler "
+				"on exit\n", drive->name);
 		}
 	}
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_intr);
+
 /*
  * get_info_ptr() returns the (ide_drive_t *) for a given device number.
  * It returns NULL if the given device number does not match any present drives.
@@ -1648,9 +1474,6 @@
 ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
 	int		major = major(i_rdev);
-#if 0
-	int		minor = minor(i_rdev) & PARTN_MASK;
-#endif
 	unsigned int	h;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
@@ -1659,11 +1482,7 @@
 			unsigned unit = DEVICE_NR(i_rdev);
 			if (unit < MAX_DRIVES) {
 				ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-				if (drive->present && get_capacity(drive->disk))
-#else
 				if (drive->present)
-#endif
 					return drive;
 			}
 			break;
@@ -1672,6 +1491,8 @@
 	return NULL;
 }
 
+EXPORT_SYMBOL(get_info_ptr);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1681,6 +1502,8 @@
 	rq->flags = REQ_DRIVE_CMD;
 }
 
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
 /*
  * This function issues a special IDE device request
  * onto the request queue.
@@ -1738,18 +1561,24 @@
 	ide_do_request(hwgroup, 0);
 	spin_unlock_irqrestore(&ide_lock, flags);
 	if (action == ide_wait) {
-		wait_for_completion(&wait);	/* wait for it to be serviced */
-		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+		/* wait for it to be serviced */
+		wait_for_completion(&wait);
+		/* return -EIO if errors */
+		return rq->errors ? -EIO : 0;
 	}
 	return 0;
 
 }
 
+EXPORT_SYMBOL(ide_do_drive_cmd);
+
 void ide_revalidate_drive (ide_drive_t *drive)
 {
 	set_capacity(drive->disk, current_capacity(drive));
 }
 
+EXPORT_SYMBOL(ide_revalidate_drive);
+
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -1758,7 +1587,7 @@
  * usage == 1 (we need an open channel to use an ioctl :-), so this
  * is our limit.
  */
-static int ide_revalidate_disk (kdev_t i_rdev)
+int ide_revalidate_disk (kdev_t i_rdev)
 {
 	ide_drive_t *drive;
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
@@ -1768,7 +1597,9 @@
 	return  0;
 }
 
-static void ide_probe_module (void)
+EXPORT_SYMBOL(ide_revalidate_disk);
+
+void ide_probe_module (void)
 {
 	if (!ide_probe) {
 #if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -1779,32 +1610,30 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_probe_module);
+
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
-#ifdef CONFIG_KMOD
 	if (drive->driver == NULL) {
 		if (drive->media == ide_disk)
 			(void) request_module("ide-disk");
+		if (drive->scsi)
+			(void) request_module("ide-scsi");
 		if (drive->media == ide_cdrom)
 			(void) request_module("ide-cd");
 		if (drive->media == ide_tape)
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-		if (drive->media == ide_scsi)
-			(void) request_module("ide-scsi");
-#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
-#endif /* CONFIG_KMOD */
 	drive->usage++;
 	if (drive->driver != NULL)
 		return DRIVER(drive)->open(inode, filp, drive);
-	printk ("%s: driver not present\n", drive->name);
+	printk (KERN_WARNING "%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
 }
@@ -1864,33 +1693,6 @@
 	show:	show_driver
 };
 
-/*
- *	Locking is badly broken here - since way back.  That sucker is
- * root-only, but that's not an excuse...  The real question is what
- * exclusion rules do we want here.
- */
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	if (ata_attach(drive)) {
-		spin_lock(&drives_lock);
-		list_del_init(&drive->list);
-		spin_unlock(&drives_lock);
-		drive->driver_req[0] = 0;
-		ata_attach(drive);
-	} else {
-		drive->driver_req[0] = 0;
-	}
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
 #ifdef CONFIG_PROC_FS
 ide_proc_entry_t generic_subdriver_entries[] = {
 	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
@@ -1898,6 +1700,10 @@
 };
 #endif
 
+
+#define hwif_release_region(addr, num) \
+	((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
+
 /*
  * Note that we only release the standard ports,
  * and do not even try to handle any extra ports
@@ -1905,35 +1711,32 @@
  */
 void hwif_unregister (ide_hwif_t *hwif)
 {
-	if (hwif->straight8) {
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-		goto jump_eight;
-	}
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
+	u32 i = 0;
+
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+
+	if (hwif->straight8) {
+		hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		return;
+	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		if (hwif->io_ports[i]) {
+			hwif_release_region(hwif->io_ports[i], 1);
+		}
+	}
 }
 
+EXPORT_SYMBOL(hwif_unregister);
+
+extern void init_hwif_data(unsigned int index);
+
 void ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
@@ -1994,7 +1797,7 @@
 		g = g->next;
 	} while (g != hwgroup->hwif);
 	if (irq_count == 1)
-		ide_free_irq(hwif->irq, hwgroup);
+		free_irq(hwif->irq, hwgroup);
 
 	/*
 	 * Note that we only release the standard ports,
@@ -2011,7 +1814,7 @@
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
 		if (drive->de) {
-			devfs_unregister (drive->de);
+			devfs_unregister(drive->de);
 			drive->de = NULL;
 		}
 		if (!drive->present)
@@ -2041,7 +1844,14 @@
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
 		(void) ide_release_dma(hwif);
+
 		hwif->dma_base = 0;
+		hwif->dma_master = 0;
+		hwif->dma_command = 0;
+		hwif->dma_vendor1 = 0;
+		hwif->dma_status = 0;
+		hwif->dma_vendor3 = 0;
+		hwif->dma_prdtable = 0;
 	}
 #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
 
@@ -2059,43 +1869,134 @@
 			hwif->drives[i].disk = NULL;
 		kfree(gd);
 	}
-	old_hwif		= *hwif;
-	init_hwif_data (index);	/* restore hwif data to pristine status */
-	hwif->hwgroup		= old_hwif.hwgroup;
-	hwif->tuneproc		= old_hwif.tuneproc;
-	hwif->speedproc		= old_hwif.speedproc;
-	hwif->selectproc	= old_hwif.selectproc;
-	hwif->resetproc		= old_hwif.resetproc;
-	hwif->intrproc		= old_hwif.intrproc;
-	hwif->maskproc		= old_hwif.maskproc;
-	hwif->quirkproc		= old_hwif.quirkproc;
-	hwif->rwproc		= old_hwif.rwproc;
-	hwif->ideproc		= old_hwif.ideproc;
-	hwif->dmaproc		= old_hwif.dmaproc;
-	hwif->busproc		= old_hwif.busproc;
-	hwif->bus_state		= old_hwif.bus_state;
-	hwif->dma_base		= old_hwif.dma_base;
-	hwif->dma_extra		= old_hwif.dma_extra;
-	hwif->config_data	= old_hwif.config_data;
-	hwif->select_data	= old_hwif.select_data;
-	hwif->proc		= old_hwif.proc;
-#ifndef CONFIG_BLK_DEV_IDECS
-	hwif->irq		= old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
-	hwif->major		= old_hwif.major;
-	hwif->chipset		= old_hwif.chipset;
-	hwif->autodma		= old_hwif.autodma;
-	hwif->udma_four		= old_hwif.udma_four;
+	old_hwif			= *hwif;
+	init_hwif_data(index);	/* restore hwif data to pristine status */
+	hwif->hwgroup			= old_hwif.hwgroup;
+
+	hwif->proc			= old_hwif.proc;
+
+	hwif->major			= old_hwif.major;
+//	hwif->index			= old_hwif.index;
+//	hwif->channel			= old_hwif.channel;
+	hwif->straight8			= old_hwif.straight8;
+	hwif->bus_state			= old_hwif.bus_state;
+
+	hwif->atapi_dma			= old_hwif.atapi_dma;
+	hwif->ultra_mask		= old_hwif.ultra_mask;
+	hwif->mwdma_mask		= old_hwif.mwdma_mask;
+	hwif->swdma_mask		= old_hwif.swdma_mask;
+
+	hwif->chipset			= old_hwif.chipset;
+
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	hwif->pci_dev		= old_hwif.pci_dev;
-	hwif->pci_devid		= old_hwif.pci_devid;
+	hwif->pci_dev			= old_hwif.pci_dev;
+	hwif->cds			= old_hwif.cds;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
-	hwif->straight8		= old_hwif.straight8;
-	hwif->hwif_data		= old_hwif.hwif_data;
+
+#if 0
+	hwif->hwifops			= old_hwif.hwifops;
+#else
+	hwif->identify			= old_hwif.identify;
+	hwif->tuneproc			= old_hwif.tuneproc;
+	hwif->speedproc			= old_hwif.speedproc;
+	hwif->selectproc		= old_hwif.selectproc;
+	hwif->reset_poll		= old_hwif.reset_poll;
+	hwif->pre_reset			= old_hwif.pre_reset;
+	hwif->resetproc			= old_hwif.resetproc;
+	hwif->intrproc			= old_hwif.intrproc;
+	hwif->maskproc			= old_hwif.maskproc;
+	hwif->quirkproc			= old_hwif.quirkproc;
+	hwif->busproc			= old_hwif.busproc;
+#endif
+
+#if 0
+	hwif->pioops			= old_hwif.pioops;
+#else
+	hwif->ata_input_data		= old_hwif.ata_input_data;
+	hwif->ata_output_data		= old_hwif.ata_output_data;
+	hwif->atapi_input_bytes		= old_hwif.atapi_input_bytes;
+	hwif->atapi_output_bytes	= old_hwif.atapi_output_bytes;
+#endif
+
+#if 0
+	hwif->dmaops			= old_hwif.dmaops;
+#else
+	hwif->ide_dma_read		= old_hwif.ide_dma_read;
+	hwif->ide_dma_write		= old_hwif.ide_dma_write;
+	hwif->ide_dma_begin		= old_hwif.ide_dma_begin;
+	hwif->ide_dma_end		= old_hwif.ide_dma_end;
+	hwif->ide_dma_check		= old_hwif.ide_dma_check;
+	hwif->ide_dma_on		= old_hwif.ide_dma_on;
+	hwif->ide_dma_off		= old_hwif.ide_dma_off;
+	hwif->ide_dma_off_quietly	= old_hwif.ide_dma_off_quietly;
+	hwif->ide_dma_test_irq		= old_hwif.ide_dma_test_irq;
+	hwif->ide_dma_host_on		= old_hwif.ide_dma_host_on;
+	hwif->ide_dma_host_off		= old_hwif.ide_dma_host_off;
+	hwif->ide_dma_bad_drive		= old_hwif.ide_dma_bad_drive;
+	hwif->ide_dma_good_drive	= old_hwif.ide_dma_good_drive;
+	hwif->ide_dma_count		= old_hwif.ide_dma_count;
+	hwif->ide_dma_verbose		= old_hwif.ide_dma_verbose;
+	hwif->ide_dma_retune		= old_hwif.ide_dma_retune;
+	hwif->ide_dma_lostirq		= old_hwif.ide_dma_lostirq;
+	hwif->ide_dma_timeout		= old_hwif.ide_dma_timeout;
+#endif
+
+#if 0
+	hwif->iops			= old_hwif.iops;
+#else
+	hwif->OUTB		= old_hwif.OUTB;
+	hwif->OUTW		= old_hwif.OUTW;
+	hwif->OUTL		= old_hwif.OUTL;
+	hwif->OUTBP		= old_hwif.OUTBP;
+	hwif->OUTWP		= old_hwif.OUTWP;
+	hwif->OUTLP		= old_hwif.OUTLP;
+	hwif->OUTSW		= old_hwif.OUTSW;
+	hwif->OUTSWP		= old_hwif.OUTSWP;
+	hwif->OUTSL		= old_hwif.OUTSL;
+	hwif->OUTSLP		= old_hwif.OUTSLP;
+
+	hwif->INB		= old_hwif.INB;
+	hwif->INW		= old_hwif.INW;
+	hwif->INL		= old_hwif.INL;
+	hwif->INBP		= old_hwif.INBP;
+	hwif->INWP		= old_hwif.INWP;
+	hwif->INLP		= old_hwif.INLP;
+	hwif->INSW		= old_hwif.INSW;
+	hwif->INSWP		= old_hwif.INSWP;
+	hwif->INSL		= old_hwif.INSL;
+	hwif->INSLP		= old_hwif.INSLP;
+#endif
+
+	hwif->mmio			= old_hwif.mmio;
+	hwif->rqsize			= old_hwif.rqsize;
+	hwif->addressing		= old_hwif.addressing;
+#ifndef CONFIG_BLK_DEV_IDECS
+	hwif->irq			= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
+	hwif->initializing		= old_hwif.initializing;
+
+	hwif->dma_base			= old_hwif.dma_base;
+	hwif->dma_master		= old_hwif.dma_master;
+	hwif->dma_command		= old_hwif.dma_command;
+	hwif->dma_vendor1		= old_hwif.dma_vendor1;
+	hwif->dma_status		= old_hwif.dma_status;
+	hwif->dma_vendor3		= old_hwif.dma_vendor3;
+	hwif->dma_prdtable		= old_hwif.dma_prdtable;
+
+	hwif->dma_extra			= old_hwif.dma_extra;
+	hwif->config_data		= old_hwif.config_data;
+	hwif->select_data		= old_hwif.select_data;
+	hwif->autodma			= old_hwif.autodma;
+	hwif->udma_four			= old_hwif.udma_four;
+	hwif->no_dsc			= old_hwif.no_dsc;
+
+	hwif->hwif_data			= old_hwif.hwif_data;
 abort:
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_unregister);
+
 /*
  * Setup hw_regs_t structure described by parameters.  You
  * may set up the hw structure yourself OR use this routine to
@@ -2104,7 +2005,11 @@
 void ide_setup_ports (	hw_regs_t *hw,
 			ide_ioreg_t base, int *offsets,
 			ide_ioreg_t ctrl, ide_ioreg_t intr,
-			ide_ack_intr_t *ack_intr, int irq)
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
 {
 	int i;
 
@@ -2130,8 +2035,13 @@
 	hw->irq = irq;
 	hw->dma = NO_DMA;
 	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
 }
 
+EXPORT_SYMBOL(ide_setup_ports);
+
 /*
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
@@ -2181,6 +2091,8 @@
 	return (initializing || hwif->present) ? index : -1;
 }
 
+EXPORT_SYMBOL(ide_register_hw);
+
 /*
  * Compatability function with existing drivers.  If you want
  * something different, use the function above.
@@ -2193,6 +2105,8 @@
 	return ide_register_hw(&hw, NULL);
 }
 
+EXPORT_SYMBOL(ide_register);
+
 void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
@@ -2204,12 +2118,18 @@
 	memset(setting, 0, sizeof(*setting));
 	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
 		goto abort;
-	strcpy(setting->name, name);		setting->rw = rw;
-	setting->read_ioctl = read_ioctl;	setting->write_ioctl = write_ioctl;
-	setting->data_type = data_type;		setting->min = min;
-	setting->max = max;			setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;	setting->data = data;
-	setting->set = set;			setting->next = *p;
+	strcpy(setting->name, name);
+	setting->rw = rw;
+	setting->read_ioctl = read_ioctl;
+	setting->write_ioctl = write_ioctl;
+	setting->data_type = data_type;
+	setting->min = min;
+	setting->max = max;
+	setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;
+	setting->data = data;
+	setting->set = set;
+	setting->next = *p;
 	if (drive->driver)
 		setting->auto_remove = 1;
 	*p = setting;
@@ -2219,6 +2139,8 @@
 		kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_add_setting);
+
 void ide_remove_setting (ide_drive_t *drive, char *name)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
@@ -2232,6 +2154,8 @@
 	kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_remove_setting);
+
 static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
 {
 	ide_settings_t *setting = drive->settings;
@@ -2316,6 +2240,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+
 /*
  * FIXME:  This should be changed to enqueue a special request
  * to the driver to change settings, and then wait on a sema for completion.
@@ -2356,6 +2282,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_write_setting);
+
 static int set_io_32bit(ide_drive_t *drive, int arg)
 {
 	drive->io_32bit = arg;
@@ -2370,10 +2298,15 @@
 {
 	if (!drive->driver || !DRIVER(drive)->supports_dma)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+	if (!drive->id || !(drive->id->capability & 1))
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
-		return -EIO;
+	if (HWIF(drive)->ide_dma_check == NULL)
+		return -EPERM;
+	if (arg) {
+		if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+	} else {
+		if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
+	}
 	return 0;
 }
 
@@ -2386,9 +2319,46 @@
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
-	drive->tune_req = (byte) arg;
+	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+	return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+	int err = ide_wait_cmd(drive,
+			WIN_SETFEATURES, (u8) arg,
+			SETFEATURES_XFER, 0, NULL);
+
+	if (!err && arg) {
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, (u8) arg);
+		ide_driveid_update(drive);
+	}
+	return err;
+}
+
+int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
+{
+	if (drive->media == ide_disk) {
+		drive->scsi = 0;
+		return 0;
+	}
+
+	if (drive->driver != NULL) {
+#if 0
+		ide_unregister_subdriver(drive);
+#else
+		if (DRIVER(drive)->cleanup(drive)) {
+			drive->scsi = 0;
+			return 0;
+		}
+#endif
+	}
+
+	drive->scsi = (u8) arg;
+	ata_attach(drive);
 	return 0;
 }
 
@@ -2404,37 +2374,11 @@
 	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
 	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
 	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"ide_scsi",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			NULL);
 	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		NULL);
+	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
 	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
-}
-
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
-{
-	struct request rq;
-	byte buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.flags = REQ_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	if (drive->media != ide_disk)
+		ide_add_setting(drive,	"ide-scsi",		SETTING_RW,					-1,		HDIO_SET_IDE_SCSI,		TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			ide_atapi_to_scsi);
 }
 
 /*
@@ -2455,11 +2399,44 @@
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
+EXPORT_SYMBOL(ide_delay_50ms);
+
 int system_bus_clock (void)
 {
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
+EXPORT_SYMBOL(system_bus_clock);
+
+/*
+ *	Locking is badly broken here - since way back.  That sucker is
+ * root-only, but that's not an excuse...  The real question is what
+ * exclusion rules do we want here.
+ */
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->usage)
+		goto abort;
+	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	if (ata_attach(drive)) {
+		spin_lock(&drives_lock);
+		list_del_init(&drive->list);
+		spin_unlock(&drives_lock);
+		drive->driver_req[0] = 0;
+		ata_attach(drive);
+	} else {
+		drive->driver_req[0] = 0;
+	}
+	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_replace_subdriver);
+
 int ata_attach(ide_drive_t *drive)
 {
 	struct list_head *p;
@@ -2469,7 +2446,7 @@
 		if (!try_inc_mod_count(driver->owner))
 			continue;
 		spin_unlock(&drivers_lock);
-		if (driver->reinit(drive) == 0) {
+		if (driver->attach(drive) == 0) {
 			if (driver->owner)
 				__MOD_DEC_USE_COUNT(driver->owner);
 			return 0;
@@ -2480,11 +2457,13 @@
 	}
 	spin_unlock(&drivers_lock);
 	spin_lock(&drives_lock);
-	list_add(&drive->list, &ata_unused);
+	list_add_tail(&drive->list, &ata_unused);
 	spin_unlock(&drives_lock);
 	return 1;
 }
 
+EXPORT_SYMBOL(ata_attach);
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2514,11 +2493,11 @@
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+			u16 bios_cyl = drive->bios_cyl; /* truncate */
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)get_start_sect(inode->i_bdev),
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2528,8 +2507,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)get_start_sect(inode->i_bdev),
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2679,33 +2658,6 @@
 	return 0;
 }
 
-void ide_fixstring (byte *s, const int bytecount, const int byteswap)
-{
-	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-	if (byteswap) {
-		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;) {
-			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = ntohs(*pp);
-		}
-	}
-
-	/* strip leading blanks */
-	while (s != end && *s == ' ')
-		++s;
-
-	/* compress internal blanks and strip trailing blanks */
-	while (s != end && *s) {
-		if (*s++ != ' ' || (s != end && *s && *s != ' '))
-			*p++ = *(s-1);
-	}
-
-	/* wipe out trailing garbage */
-	while (p != end)
-		*p++ = '\0';
-}
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -3170,14 +3122,12 @@
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_BLK_DEV_IDEPCI
 	if (pci_present())
 	{
-#ifdef CONFIG_BLK_DEV_IDEPCI
 		ide_scan_pcibus(ide_scan_direction);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -3267,22 +3217,13 @@
 	probe_for_hwifs ();
 
 #ifdef CONFIG_BLK_DEV_IDE
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_intr_lock, NULL, NULL);/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
 
 	(void) ideprobe_init();
 
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_lock);	/* for atari only */
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_release_lock(&ide_intr_lock);	/* for atari only */
 #endif /* CONFIG_BLK_DEV_IDE */
 
 #ifdef CONFIG_PROC_FS
@@ -3317,21 +3258,21 @@
 
 static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	ide_end_request(drive, 0);
+	ide_end_request(drive, 0, 0);
 	return ide_stopped;
 }
 
-static int default_end_request (ide_drive_t *drive, int uptodate)
+static int default_end_request (ide_drive_t *drive, int uptodate, int nr_sects)
 {
-	return ide_end_request(drive, uptodate);
+	return ide_end_request(drive, uptodate, nr_sects);
 }
 
-static byte default_sense (ide_drive_t *drive, const char *msg, byte stat)
+static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
 {
 	return ide_dump_status(drive, msg, stat);
 }
 
-static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, byte stat)
+static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
 	return ide_error(drive, msg, stat);
 }
@@ -3375,9 +3316,10 @@
 	return ide_stopped;
 }
 
-static int default_reinit (ide_drive_t *drive)
+static int default_attach (ide_drive_t *drive)
 {
-	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
+	printk(KERN_ERR "%s: does not support hotswap of device class !\n",
+		drive->name);
 
 	return 0;
 }
@@ -3402,7 +3344,7 @@
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
-	if (d->reinit == NULL)		d->reinit = default_reinit;
+	if (d->attach == NULL)		d->attach = default_attach;
 }
 
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
@@ -3422,8 +3364,10 @@
 	list_add(&drive->list, &driver->drives);
 	spin_unlock(&drives_lock);
 	if (drive->autotune != 2) {
-		if (!driver->supports_dma && HWIF(drive)->dmaproc != NULL)
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
+		/* DMA timings and setup moved to ide-probe.c */
+		if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
+//			HWIF(drive)->ide_dma_off_quietly(drive);
+			HWIF(drive)->ide_dma_off(drive);
 		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
 		drive->nice1 = 1;
 	}
@@ -3435,6 +3379,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_subdriver);
+
 int ide_unregister_subdriver (ide_drive_t *drive)
 {
 	unsigned long flags;
@@ -3460,6 +3406,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
 int ide_register_driver(ide_driver_t *driver)
 {
 	struct list_head list;
@@ -3481,6 +3429,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_driver);
+
 void ide_unregister_driver(ide_driver_t *driver)
 {
 	ide_drive_t *drive;
@@ -3505,6 +3455,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_unregister_driver);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3514,10 +3466,7 @@
 	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_driver);
-EXPORT_SYMBOL(ide_unregister_driver);
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(ide_fops);
 
 /*
  * Probe module
@@ -3526,58 +3475,7 @@
 
 EXPORT_SYMBOL(ide_lock);
 EXPORT_SYMBOL(ide_probe);
-EXPORT_SYMBOL(drive_is_flashcard);
-EXPORT_SYMBOL(ide_timer_expiry);
-EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_fops);
-EXPORT_SYMBOL(ide_get_queue);
-EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(ide_devfs_handle);
-EXPORT_SYMBOL(do_ide_request);
-/*
- * Driver module
- */
-EXPORT_SYMBOL(ide_register_subdriver);
-EXPORT_SYMBOL(ide_unregister_subdriver);
-EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
-EXPORT_SYMBOL(ide_error);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(ide_do_reset);
-EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ide_init_drive_cmd);
-EXPORT_SYMBOL(ide_do_drive_cmd);
-EXPORT_SYMBOL(ide_end_drive_cmd);
-EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_drive);
-EXPORT_SYMBOL(ide_cmd);
-EXPORT_SYMBOL(ide_wait_cmd);
-EXPORT_SYMBOL(ide_wait_cmd_task);
-EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_stall_queue);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(ide_add_proc_entries);
-EXPORT_SYMBOL(ide_remove_proc_entries);
-EXPORT_SYMBOL(proc_ide_read_geometry);
-EXPORT_SYMBOL(create_proc_ide_interfaces);
-EXPORT_SYMBOL(recreate_proc_ide_device);
-EXPORT_SYMBOL(destroy_proc_ide_device);
-#endif
-EXPORT_SYMBOL(ide_add_setting);
-EXPORT_SYMBOL(ide_remove_setting);
-
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_register);
-EXPORT_SYMBOL(ide_unregister);
-EXPORT_SYMBOL(ide_setup_ports);
-EXPORT_SYMBOL(hwif_unregister);
-EXPORT_SYMBOL(get_info_ptr);
-EXPORT_SYMBOL(current_capacity);
-
-EXPORT_SYMBOL(system_bus_clock);
-
-EXPORT_SYMBOL(ata_attach);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -3594,7 +3492,7 @@
 			return NOTIFY_DONE;
 	}
 
-	printk("flushing ide devices: ");
+	printk(KERN_INFO "flushing ide devices: ");
 
 	for (i = 0; i < MAX_HWIFS; i++) {
 		hwif = &ide_hwifs[i];
@@ -3633,12 +3531,12 @@
 	static char banner_printed;
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+		ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
 		system_bus_speed = ide_system_bus_speed();
 		banner_printed = 1;
 	}
 
-	init_ide_data ();
+	init_ide_data();
 
 	initializing = 1;
 	ide_init_builtin_drivers();
diff -Nru a/drivers/ide/ide_modes.h b/drivers/ide/ide_modes.h
--- a/drivers/ide/ide_modes.h	Sun Sep 15 19:19:28 2002
+++ b/drivers/ide/ide_modes.h	Sun Sep 15 19:19:28 2002
@@ -31,17 +31,17 @@
 } ide_pio_timings_t;
 
 typedef struct ide_pio_data_s {
-	byte pio_mode;
-	byte use_iordy;
-	byte overridden;
-	byte blacklisted;
+	u8 pio_mode;
+	u8 use_iordy;
+	u8 overridden;
+	u8 blacklisted;
 	unsigned int cycle_time;
 } ide_pio_data_t;
 	
 #ifndef _IDE_C
 
 int ide_scan_pio_blacklist (char *model);
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
 extern const ide_pio_timings_t ide_pio_timings[6];
 
 #else /* _IDE_C */
@@ -159,7 +159,7 @@
 /*
  * Drive PIO mode auto selection
  */
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
 {
 	int pio_mode;
 	int cycle_time = 0;
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,389 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *      IT8172 IDE controller support
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *              stevel@mvista.com or source@mvista.com
- *
- *  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.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/it8172/it8172_int.h>
-
-#include "ide_modes.h"
-
-/*
- * Prototypes
- */
-static byte it8172_ratemask (ide_drive_t *drive);
-static byte it8172_ratefilter (ide_drive_t *drive, byte speed);
-static void it8172_tune_drive (ide_drive_t *drive, byte pio);
-static byte it8172_dma_2_pio (byte xfer_rate);
-static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int it8172_config_chipset_for_dma (ide_drive_t *drive);
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-#endif
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
-void __init ide_init_it8172 (ide_hwif_t *hwif);
-
-static byte it8172_ratemask (ide_drive_t *drive)
-{
-	byte mode	= 0x00;
-#if 1
-	mode |= 0x01;
-#endif
-	return (mode &= ~0xF8);
-}
-
-static byte it8172_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = it8172_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static void it8172_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (hwif->drives[1] == drive);
-	unsigned long flags;
-	u16 drive_enables;
-	u32 drive_timing;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	spin_lock_irqsave(&ide_lock, flags);
-	pci_read_config_word(dev, 0x40, &drive_enables);
-	pci_read_config_dword(dev, 0x44, &drive_timing);
-
-	/*
-	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
-	 * are being left at the default values of 8 PCI clocks (242 nsec
-	 * for a 33 MHz clock). These can be safely shortened at higher
-	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
-	 * apply to PIO modes, not to the DMA modes.
-	 */
-
-	/*
-	 * Enable port 0x44. The IT8172G spec is confused; it calls
-	 * this register the "Slave IDE Timing Register", but in fact,
-	 * it controls timing for both master and slave drives.
-	 */
-	drive_enables |= 0x4000;
-
-	if (is_slave) {
-		drive_enables &= 0xc006;
-		if (pio > 1)
-			/* enable prefetch and IORDY sample-point */
-			drive_enables |= 0x0060;
-	} else {
-		drive_enables &= 0xc060;
-		if (pio > 1)
-			/* enable prefetch and IORDY sample-point */
-			drive_enables |= 0x0006;
-	}
-
-	pci_write_config_word(dev, 0x40, drive_enables);
-	spin_unlock_irqrestore(&ide_lock, flags)
-}
-
-static byte it8172_dma_2_pio (byte xfer_rate)
-{
-	switch(xfer_rate) {
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-
-static int it8172_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= it8172_ratefilter(drive, xferspeed);
-	int a_speed		= 3 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	byte reg48, reg4a;
-
-	pci_read_config_byte(dev, 0x48, &reg48);
-	pci_read_config_byte(dev, 0x4a, &reg4a);
-
-    /*
-     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
-     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
-     * transfers on some drives, even though both numbers meet the minimum
-     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
-     * So the faster times are just commented out here. The good news is
-     * that the slower cycle time has very little affect on transfer
-     * performance.
-     */
-    
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:	break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_0:	break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-		reg4a &= ~a_speed;
-		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-	} else {
-		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-	}
-
-	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
-	return (ide_config_drive_speed(drive, speed));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= it8172_ratemask(drive);
-	byte speed, tspeed, dma = 1;
-
-	switch(mode) {
-		case 0x01:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-		default:
-			tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
-			speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
-			dma = 0;
-			break;
-	}
-
-	(void) it8172_tune_chipset(drive, speed);
-
-//	return ((int)(dma) ? ide_dma_on : ide_dma_off_quietly);
-	return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-		    ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-		    ((id->dma_mword >> 8) & 7) ? ide_dma_on :
-		    ((id->dma_1word >> 8) & 7) ? ide_dma_on :
-		    ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = it8172_config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = it8172_config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = it8172_config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		it8172_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
-{
-	unsigned char progif;
-    
-	/*
-	 * Place both IDE interfaces into PCI "native" mode
-	 */
-	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
-
-	return IT8172_IDE_IRQ;
-}
-
-
-void __init ide_init_it8172 (ide_hwif_t *hwif)
-{
-	struct pci_dev* dev = hwif->pci_dev;
-	unsigned long cmdBase, ctrlBase;
-    
-	hwif->autodma = 0;
-	hwif->tuneproc = &it8172_tune_drive;
-	hwif->speedproc = &it8172_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	cmdBase = dev->resource[0].start;
-	ctrlBase = dev->resource[1].start;
-    
-	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	hwif->noprobe = 0;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &it8172_dmaproc;
-# ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-# endif /* CONFIG_IDEDMA_AUTO */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_it8172 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-        if ((!(PCI_FUNC(dev->devfn) & 1) ||
-            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
-                return; /* IT8172 is more than only a IDE controller */
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
diff -Nru a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/Makefile	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,26 @@
+
+O_TARGET := idedriver-legacy.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
+obj-$(CONFIG_BLK_DEV_PDC4030)		+= pdc4030.o
+obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+
+obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+
+obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/ali14xx.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,304 @@
+/*
+ *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Works for ALI M1439/1443/1445/1487/1489 chipsets.
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function.  The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk.  I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg  (derekn@ece.cmu.edu)
+ * 95-sep-26
+ *
+ * Update 96-jul-13:
+ *
+ * I've since upgraded to two disks and a CD-ROM, with no trouble, and
+ * I've also heard from several others who have used it successfully.
+ * This driver appears to work with both the 1443/1445 and the 1487/1489
+ * chipsets.  I've added support for PIO mode 4 for the 1487.  This
+ * seems to work just fine on the 1443 also, although I'm not sure it's
+ * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
+ * mode 4 for a while now with no trouble.)  -Derek
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_ALI14XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_ALI14XX_MODULE */
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static RegInitializer initData[] __initdata = {
+	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+	{0x35, 0x03}, {0x00, 0x00}
+};
+
+#define ALI_MAX_PIO 4
+
+/* timing parameter registers for each drive */
+static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
+	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+};
+
+static int basePort;	/* base port address */
+static int regPort;	/* port for register number */
+static int dataPort;	/* port for register data */
+static u8 regOn;	/* output to base port to access registers */
+static u8 regOff;	/* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline u8 inReg (u8 reg)
+{
+	outb_p(reg, regPort);
+	return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg (u8 data, u8 reg)
+{
+	outb_p(reg, regPort);
+	outb_p(data, dataPort);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int driveNum;
+	int time1, time2;
+	u8 param1, param2, param3, param4;
+	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+
+	/* calculate timing, according to PIO mode */
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	if (pio < 3) {
+		param3 += 8;
+		param4 += 8;
+	}
+	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+		drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+	/* stuff timing parameters into controller registers */
+	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(regOn, basePort);
+	outReg(param1, regTab[driveNum].reg1);
+	outReg(param2, regTab[driveNum].reg2);
+	outReg(param3, regTab[driveNum].reg3);
+	outReg(param4, regTab[driveNum].reg4);
+	outb_p(regOff, basePort);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int __init findPort (void)
+{
+	int i;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < ALI_NUM_PORTS; ++i) {
+		basePort = ports[i];
+		regOff = inb(basePort);
+		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+			outb_p(regOn, basePort);
+			if (inb(basePort) == regOn) {
+				regPort = basePort + 4;
+				dataPort = basePort + 8;
+				t = inReg(0) & 0xf0;
+				outb_p(regOff, basePort);
+				local_irq_restore(flags);
+				if (t != 0x50)
+					return 0;
+				return 1;  /* success */
+			}
+		}
+		outb_p(regOff, basePort);
+	}
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int __init initRegisters (void) {
+	RegInitializer *p;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	outb_p(regOn, basePort);
+	for (p = initData; p->reg != 0; ++p)
+		outReg(p->data, p->reg);
+	outb_p(0x01, regPort);
+	t = inb(regPort) & 0x01;
+	outb_p(regOff, basePort);
+	local_irq_restore(flags);
+	return t;
+}
+
+int __init probe_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+	if (!findPort()) {
+		printk(KERN_ERR "ali14xx: not found.\n");
+		return 1;
+	}
+
+	printk(KERN_DEBUG "ali14xx: base= 0x%03x, regOn = 0x%02x.\n", basePort, regOn);
+	ide_hwifs[0].chipset = ide_ali14xx;
+	ide_hwifs[1].chipset = ide_ali14xx;
+	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+	/* initialize controller registers */
+	if (!initRegisters()) {
+		printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
+		return 1;
+	}
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init ali14xx_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx)
+		return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_ali14xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+        if (findPort())
+		if (probe_ali14xx())
+			goto no_detect;
+	return;
+
+no_detect:
+	printk(KERN_ERR "ali14xx: not found.\n");
+	ali14xx_release();
+}
+
+#else
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init ali14xx_mod_init(void)
+{
+	/* auto-detect IDE controller port */
+	if (findPort())
+		if (probe_ali14xx()) {
+			ali14xx_release();
+			return -ENODEV;
+		}
+
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx) {
+		ali14xx_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(ali14xx_mod_init);
+
+void __init ali14xx_mod_exit(void)
+{
+	ali14xx_release();
+}
+module_exit(ali14xx_mod_exit);
+#endif
+
diff -Nru a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/buddha.c	Sun Sep 15 19:19:34 2002
@@ -0,0 +1,233 @@
+/*
+ *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *
+ *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+ *
+ *  This driver was written based on the specifications in README.buddha and
+ *  the X-Surf info from Inside_XSurf.txt available at
+ *  http://www.jschoenfeld.com
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *  TODO:
+ *    - test it :-)
+ *    - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
+     */
+
+#define BUDDHA_NUM_HWIFS	2
+#define CATWEASEL_NUM_HWIFS	3
+#define XSURF_NUM_HWIFS         2
+
+    /*
+     *  Bases of the IDE interfaces (relative to the board address)
+     */
+
+#define BUDDHA_BASE1	0x800
+#define BUDDHA_BASE2	0xa00
+#define BUDDHA_BASE3	0xc00
+
+#define XSURF_BASE1     0xb000 /* 2.5" Interface */
+#define XSURF_BASE2     0xd000 /* 3.5" Interface */
+
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+     XSURF_BASE1, XSURF_BASE2
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define BUDDHA_DATA	0x00
+#define BUDDHA_ERROR	0x06		/* see err-bits */
+#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define BUDDHA_SECTOR	0x0e		/* starting sector */
+#define BUDDHA_LCYL	0x12		/* starting cylinder */
+#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
+#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS	0x1e		/* see status-bits */
+#define BUDDHA_CONTROL	0x11a
+#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
+
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
+};
+
+static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
+};
+
+    /*
+     *  Other registers
+     */
+
+#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2	0xf40		/* interrupt */
+#define BUDDHA_IRQ3	0xf80
+
+#define XSURF_IRQ1      0x7e
+#define XSURF_IRQ2      0x7e
+
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+    XSURF_IRQ1, XSURF_IRQ2
+};
+
+#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
+
+
+    /*
+     *  Board information
+     */
+
+typedef enum BuddhaType_Enum {
+    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+static int xsurf_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+    /*
+     *  Probe for a Buddha or Catweasel IDE interface
+     */
+
+void __init buddha_init(void)
+{
+	hw_regs_t hw;
+	int i, index;
+
+	struct zorro_dev *z = NULL;
+	u_long buddha_board = 0;
+	BuddhaType type;
+	int buddha_num_hwifs;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		unsigned long board;
+		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+			type=BOARD_BUDDHA;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
+			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+			type=BOARD_CATWEASEL;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
+			buddha_num_hwifs = XSURF_NUM_HWIFS;
+			type=BOARD_XSURF;
+		} else 
+			continue;
+		
+		board = z->resource.start;
+
+/*
+ * FIXME: we now have selectable mmio v/s iomio transports.
+ */
+
+		if(type != BOARD_XSURF) {
+			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
+				continue;
+		} else {
+			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+				continue;
+			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+				goto fail_base2;
+			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+				release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+				release_mem_region(board+XSURF_BASE1, 0x1000);
+				continue;
+			}
+		}	  
+		buddha_board = ZTWO_VADDR(board);
+		
+		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
+		/* X-Surf doesn't have this.  IRQs are always on */
+		if (type != BOARD_XSURF)
+			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+		
+		for(i=0;i<buddha_num_hwifs;i++) {
+			if(type != BOARD_XSURF) {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
+						buddha_offsets, 0,
+						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
+						buddha_ack_intr,
+//						budda_iops,
+						IRQ_AMIGA_PORTS);
+			} else {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
+						xsurf_offsets, 0,
+						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
+						xsurf_ack_intr,
+//						xsurf_iops,
+						IRQ_AMIGA_PORTS);
+			}	
+			
+			index = ide_register_hw(&hw, NULL);
+			if (index != -1) {
+				printk("ide%d: ", index);
+				switch(type) {
+				case BOARD_BUDDHA:
+					printk("Buddha");
+					break;
+				case BOARD_CATWEASEL:
+					printk("Catweasel");
+					break;
+				case BOARD_XSURF:
+					printk("X-Surf");
+					break;
+				}
+				printk(" IDE interface\n");	    
+			}		      
+		}
+	}
+}
diff -Nru a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/dtc2278.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,203 @@
+/*
+ *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_DTC2278_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_DTC2278_MODULE */
+
+/*
+ * Changing this #undef to #define may solve start up problems in some systems.
+ */
+#undef ALWAYS_SET_DTC2278_PIO_MODE
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem  corrupted with -u1, but under heavy disk load only :-)
+ *
+ * This card is now forced to use the "serialize" feature,
+ * and irq-unmasking is disallowed.  If io_32bit is enabled,
+ * it must be done for BOTH drives on each interface.
+ *
+ * This code was written for the DTC2278E, but might work with any of these:
+ *
+ * DTC2278S has only a single IDE interface.
+ * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
+ * DTC2278E also has serial ports and a printer port
+ * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
+ *
+ * There may be a fourth controller type. The S and D versions use the
+ * Winbond chip, and I think the E version does also.
+ *
+ */
+
+static void sub22 (char b, char c)
+{
+	int i;
+
+	for(i = 0; i < 3; ++i) {
+		inb(0x3f6);
+		outb_p(b,0xb0);
+		inb(0x3f6);
+		outb_p(c,0xb4);
+		inb(0x3f6);
+		if(inb(0xb4) == c) {
+			outb_p(7,0xb0);
+			inb(0x3f6);
+			return;	/* success */
+		}
+	}
+}
+
+static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	if (pio >= 3) {
+		spin_lock_irqsave(&ide_lock, flags);
+		/*
+		 * This enables PIO mode4 (3?) on the first interface
+		 */
+		sub22(1,0xc3);
+		sub22(0,0xa0);
+		spin_unlock_irqrestore(&ide_lock, flags);
+	} else {
+		/* we don't know how to set it back again.. */
+	}
+
+	/*
+	 * 32bit I/O has to be enabled for *both* drives at the same time.
+	 */
+	drive->io_32bit = 1;
+	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+}
+
+void __init probe_dtc2278 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * This enables the second interface
+	 */
+	outb_p(4,0xb0);
+	inb(0x3f6);
+	outb_p(0x20,0xb4);
+	inb(0x3f6);
+#ifdef ALWAYS_SET_DTC2278_PIO_MODE
+	/*
+	 * This enables PIO mode4 (3?) on the first interface
+	 * and may solve start-up problems for some people.
+	 */
+	sub22(1,0xc3);
+	sub22(0,0xa0);
+#endif
+	local_irq_restore(flags);
+
+	ide_hwifs[0].serialized = 1;
+	ide_hwifs[1].serialized = 1;
+	ide_hwifs[0].chipset = ide_dtc2278;
+	ide_hwifs[1].chipset = ide_dtc2278;
+	ide_hwifs[0].tuneproc = &tune_dtc2278;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init dtc2278_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278)
+		return;
+
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[0].drives[0].no_unmask = 0;
+	ide_hwifs[0].drives[1].no_unmask = 0;
+	ide_hwifs[1].drives[0].no_unmask = 0;
+	ide_hwifs[1].drives[1].no_unmask = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_dtc2278:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_dtc2278 (void)
+{
+	probe_dtc2278();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init dtc2278_mod_init(void)
+{
+	probe_dtc2278();
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278) {
+		dtc2278_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(dtc2278_mod_init);
+
+void __init dtc2278_mod_exit(void)
+{
+	dtc2278_release();
+}
+module_exit(dtc2278_mod_exit);
+#endif
+
diff -Nru a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/falconide.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
+ *
+ *     Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+
+    /*
+     *  Base of the IDE interface
+     */
+
+#define ATA_HD_BASE	0xfff00000
+
+    /*
+     *  Offsets from the above base
+     */
+
+#define ATA_HD_DATA	0x00
+#define ATA_HD_ERROR	0x05		/* see err-bits */
+#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
+#define ATA_HD_SECTOR	0x0d		/* starting sector */
+#define ATA_HD_LCYL	0x11		/* starting cylinder */
+#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
+#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS	0x1d		/* see status-bits */
+#define ATA_HD_CONTROL	0x39
+
+static int falconide_offsets[IDE_NR_PORTS] __initdata = {
+    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+    /*
+     *  Probe for a Falcon IDE interface
+     */
+
+void __init falconide_init(void)
+{
+    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+	hw_regs_t hw;
+	int index;
+
+	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
+			0, 0, NULL,
+//			falconide_iops,
+			IRQ_MFP_IDE);
+	index = ide_register_hw(&hw, NULL);
+
+	if (index != -1)
+	    printk("ide%d: Falcon IDE interface\n", index);
+    }
+}
diff -Nru a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/gayle.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,187 @@
+/*
+ *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
+ *
+ *     Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
+#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define GAYLE_DATA	0x00
+#define GAYLE_ERROR	0x06		/* see err-bits */
+#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define GAYLE_SECTOR	0x0e		/* starting sector */
+#define GAYLE_LCYL	0x12		/* starting cylinder */
+#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
+#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS	0x1e		/* see status-bits */
+#define GAYLE_CONTROL	0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
+    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+    /*
+     *  These are at different offsets from the base
+     */
+
+#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
+
+
+    /*
+     *  Offset of the secondary port for IDE doublers
+     *  Note that GAYLE_CONTROL is NOT available then!
+     */
+
+#define GAYLE_NEXT_PORT	0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS		1
+#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG	1
+#define GAYLE_IDEREG_SIZE	0x2000
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS		2
+#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
+					       GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
+#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
+int ide_doubler = 0;	/* support IDE doublers? */
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+    return 1;
+}
+
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
+
+void __init gayle_init(void)
+{
+    int a4000, i;
+
+    if (!MACH_IS_AMIGA)
+	return;
+
+    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
+	return;
+
+    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+	ide_ioreg_t base, ctrlport, irqport;
+	ide_ack_intr_t *ack_intr;
+	hw_regs_t hw;
+	int index;
+	unsigned long phys_base, res_start, res_n;
+
+	if (a4000) {
+	    phys_base = GAYLE_BASE_4000;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+	    ack_intr = gayle_ack_intr_a4000;
+	} else {
+	    phys_base = GAYLE_BASE_1200;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+	    ack_intr = gayle_ack_intr_a1200;
+	}
+/*
+ * FIXME: we now have selectable modes between mmio v/s iomio
+ */
+
+	phys_base += i*GAYLE_NEXT_PORT;
+
+	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+	res_n = GAYLE_IDEREG_SIZE;
+
+	if (!request_mem_region(res_start, res_n, "IDE"))
+	    continue;
+
+	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
+	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+	ide_setup_ports(&hw, base, gayle_offsets,
+			ctrlport, irqport, ack_intr,
+//			gaule_iops,
+			IRQ_AMIGA_PORTS);
+
+	index = ide_register_hw(&hw, NULL);
+	if (index != -1) {
+	    switch (i) {
+		case 0:
+		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+			   a4000 ? 4000 : 1200);
+		    break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+		case 1:
+		    printk("ide%d: IDE doubler\n", index);
+		    break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+	    }
+	} else
+	    release_mem_region(res_start, res_n);
+
+#if 1 /* TESTING */
+	if (i == 1) {
+	    volatile u_short *addr = (u_short *)base;
+	    u_short data;
+	    printk("+++ Probing for IDE doubler... ");
+	    *addr = 0xffff;
+	    data = *addr;
+	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
+	}
+#endif /* TESTING */
+    }
+}
diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/hd.c	Sun Sep 15 19:19:28 2002
@@ -0,0 +1,872 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ *
+ *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *
+ *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  in the early extended-partition checks and added DM partitions
+ *
+ *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ *  and general streamlining by Mark Lord.
+ *
+ *  Removed 99% of above. Use Mark's ide driver for those options.
+ *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ *  Modified 1995 Russell King for ARM processor.
+ *
+ *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ *  off in a hurry once you queue things up - Paul G. 02/2001
+ */
+
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+
+#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/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+#include <linux/hdreg.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#define DEVICE_NR(device) (minor(device)>>6)
+#include <linux/blk.h>
+
+#define HD_IRQ 14	/* the standard disk interrupt */
+
+#ifdef __arm__
+#undef  HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+/* Hd controller regster ports */
+
+#define HD_DATA		0x1f0		/* _CTL when writing */
+#define HD_ERROR	0x1f1		/* see err-bits */
+#define HD_NSECTOR	0x1f2		/* nr of sectors to read/write */
+#define HD_SECTOR	0x1f3		/* starting sector */
+#define HD_LCYL		0x1f4		/* starting cylinder */
+#define HD_HCYL		0x1f5		/* high byte of starting cyl */
+#define HD_CURRENT	0x1f6		/* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS	0x1f7		/* see status-bits */
+#define HD_FEATURE	HD_ERROR	/* same io address, read=error, write=feature */
+#define HD_PRECOMP	HD_FEATURE	/* obsolete use of this port - predates IDE */
+#define HD_COMMAND	HD_STATUS	/* same io address, read=status, write=cmd */
+
+#define HD_CMD		0x3f6		/* used for resets */
+#define HD_ALTSTATUS	0x3f6		/* same as HD_STATUS but doesn't clear irq */
+
+/* Bits of HD_STATUS */
+#define ERR_STAT		0x01
+#define INDEX_STAT		0x02
+#define ECC_STAT		0x04	/* Corrected error */
+#define DRQ_STAT		0x08
+#define SEEK_STAT		0x10
+#define SERVICE_STAT		SEEK_STAT
+#define WRERR_STAT		0x20
+#define READY_STAT		0x40
+#define BUSY_STAT		0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR		0x01	/* Bad address mark */
+#define TRK0_ERR		0x02	/* couldn't find track 0 */
+#define ABRT_ERR		0x04	/* Command aborted */
+#define MCR_ERR			0x08	/* media change request */
+#define ID_ERR			0x10	/* ID field not found */
+#define MC_ERR			0x20	/* media changed */
+#define ECC_ERR			0x40	/* Uncorrectable ECC error */
+#define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
+#define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
+
+static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
+
+#define TIMEOUT_VALUE	(6*HZ)
+#define	HD_DELAY	0
+
+#define MAX_ERRORS     16	/* Max read/write errors/sector */
+#define RESET_FREQ      8	/* Reset controller every 8th retry */
+#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
+#define MAX_HD		2
+
+#define STAT_OK		(READY_STAT|SEEK_STAT)
+#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+
+static int reset;
+static int hd_error;
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
+
+/*
+ *  This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+	unsigned int head,sect,cyl,wpcom,lzone,ctl;
+};
+	
+#ifdef HD_TYPE
+static struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct timer_list device_timer;
+
+#define TIMEOUT_VALUE (6*HZ)
+
+#define SET_TIMER							\
+	do {								\
+		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
+	} while (0)
+
+static void (*do_hd)(void) = NULL;
+#define SET_HANDLER(x) \
+if ((do_hd = (x)) != NULL) \
+	SET_TIMER; \
+else \
+	del_timer(&device_timer);
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+        extern spinlock_t i8253_lock;
+	unsigned long t, flags;
+	int i;
+
+	spin_lock_irqsave(&i8253_lock, flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb(0x40) << 8;
+	spin_unlock_irqrestore(&i8253_lock, flags);
+	return(t - i);
+}
+#endif
+
+void __init hd_setup(char *str, int *ints)
+{
+	int hdind = 0;
+
+	if (ints[0] != 3)
+		return;
+	if (hd_info[0].head != 0)
+		hdind=1;
+	hd_info[hdind].head = ints[2];
+	hd_info[hdind].sect = ints[3];
+	hd_info[hdind].cyl = ints[1];
+	hd_info[hdind].wpcom = 0;
+	hd_info[hdind].lzone = ints[1];
+	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+	NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+	char devc;
+
+	devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+#ifdef VERBOSE_ERRORS
+	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
+	if (stat & BUSY_STAT)	printk("Busy ");
+	if (stat & READY_STAT)	printk("DriveReady ");
+	if (stat & WRERR_STAT)	printk("WriteFault ");
+	if (stat & SEEK_STAT)	printk("SeekComplete ");
+	if (stat & DRQ_STAT)	printk("DataRequest ");
+	if (stat & ECC_STAT)	printk("CorrectedError ");
+	if (stat & INDEX_STAT)	printk("Index ");
+	if (stat & ERR_STAT)	printk("Error ");
+	printk("}\n");
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+		if (hd_error & BBD_ERR)		printk("BadSector ");
+		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
+		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
+		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
+		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
+				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+			if (!blk_queue_empty(QUEUE))
+				printk(", sector=%ld", CURRENT->sector);
+		}
+		printk("\n");
+	}
+#else
+	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+	}
+#endif
+}
+
+void check_status(void)
+{
+	int i = inb_p(HD_STATUS);
+
+	if (!OK_STATUS(i)) {
+		dump_status("check_status", i);
+		bad_rw_intr();
+	}
+}
+
+static int controller_busy(void)
+{
+	int retries = 100000;
+	unsigned char status;
+
+	do {
+		status = inb_p(HD_STATUS);
+	} while ((status & BUSY_STAT) && --retries);
+	return status;
+}
+
+static int status_ok(void)
+{
+	unsigned char status = inb_p(HD_STATUS);
+
+	if (status & BUSY_STAT)
+		return 1;	/* Ancient, but does it make sense??? */
+	if (status & WRERR_STAT)
+		return 0;
+	if (!(status & READY_STAT))
+		return 0;
+	if (!(status & SEEK_STAT))
+		return 0;
+	return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+	int retry = 100;
+
+	do {
+		if (controller_busy() & BUSY_STAT)
+			return 0;
+		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+		if (status_ok())
+			return 1;
+	} while (--retry);
+	return 0;
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+		unsigned int head,unsigned int cyl,unsigned int cmd,
+		void (*intr_addr)(void))
+{
+	unsigned short port;
+
+#if (HD_DELAY > 0)
+	while (read_timer() - last_req < HD_DELAY)
+		/* nothing */;
+#endif
+	if (reset)
+		return;
+	if (!controller_ready(drive, head)) {
+		reset = 1;
+		return;
+	}
+	SET_HANDLER(intr_addr);
+	outb_p(hd_info[drive].ctl,HD_CMD);
+	port=HD_DATA;
+	outb_p(hd_info[drive].wpcom>>2,++port);
+	outb_p(nsect,++port);
+	outb_p(sect,++port);
+	outb_p(cyl,++port);
+	outb_p(cyl>>8,++port);
+	outb_p(0xA0|(drive<<4)|head,++port);
+	outb_p(cmd,++port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+	unsigned int i;
+	unsigned char c;
+
+	for (i = 0; i < 500000 ; i++) {
+		c = inb_p(HD_STATUS);
+		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+			return 0;
+	}
+	dump_status("reset timed out", c);
+	return 1;
+}
+
+static void reset_controller(void)
+{
+	int	i;
+
+	outb_p(4,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	if (drive_busy())
+		printk("hd: controller still busy\n");
+	else if ((hd_error = inb(HD_ERROR)) != 1)
+		printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+	static int i;
+
+repeat:
+	if (reset) {
+		reset = 0;
+		i = -1;
+		reset_controller();
+	} else {
+		check_status();
+		if (reset)
+			goto repeat;
+	}
+	if (++i < NR_HD) {
+		special_op[i] = recalibrate[i] = 1;
+		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
+			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+		if (reset)
+			goto repeat;
+	} else
+		hd_request();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
+ * drive enters "idle", "standby", or "sleep" mode, so if the status looks
+ * "good", we just ignore the interrupt completely.
+ */
+void unexpected_hd_interrupt(void)
+{
+	unsigned int stat = inb_p(HD_STATUS);
+
+	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+		dump_status ("unexpected interrupt", stat);
+		SET_TIMER;
+	}
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
+static void bad_rw_intr(void)
+{
+	int dev;
+
+	if (blk_queue_empty(QUEUE))
+		return;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+		end_request(CURRENT, 0);
+		special_op[dev] = recalibrate[dev] = 1;
+	} else if (CURRENT->errors % RESET_FREQ == 0)
+		reset = 1;
+	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+		special_op[dev] = recalibrate[dev] = 1;
+	/* Otherwise just retry */
+}
+
+static inline int wait_DRQ(void)
+{
+	int retries = 100000, stat;
+
+	while (--retries > 0)
+		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+			return 0;
+	dump_status("wait_DRQ", stat);
+	return -1;
+}
+
+static void read_intr(void)
+{
+	int i, retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if (i & DRQ_STAT)
+			goto ok_to_read;
+	} while (--retries > 0);
+	dump_status("read_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_read:
+	insw(HD_DATA,CURRENT->buffer,256);
+	CURRENT->sector++;
+	CURRENT->buffer += 512;
+	CURRENT->errors = 0;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+#ifdef DEBUG
+	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+		(unsigned long) CURRENT->buffer+512));
+#endif
+	if (CURRENT->current_nr_sectors <= 0)
+		end_request(CURRENT, 1);
+	if (i > 0) {
+		SET_HANDLER(&read_intr);
+		return;
+	}
+	(void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	if (!blk_queue_empty(QUEUE))
+		hd_request();
+	return;
+}
+
+static void write_intr(void)
+{
+	int i;
+	int retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
+			goto ok_to_write;
+	} while (--retries > 0);
+	dump_status("write_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_write:
+	CURRENT->sector++;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+	CURRENT->buffer += 512;
+	if (!i || (CURRENT->bio && !SUBSECTOR(i)))
+		end_request(CURRENT, 1);
+	if (i > 0) {
+		SET_HANDLER(&write_intr);
+		outsw(HD_DATA,CURRENT->buffer,256);
+		local_irq_enable();
+	} else {
+#if (HD_DELAY > 0)
+		last_req = read_timer();
+#endif
+		hd_request();
+	}
+	return;
+}
+
+static void recal_intr(void)
+{
+	check_status();
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+	unsigned int dev;
+
+	do_hd = NULL;
+
+	if (blk_queue_empty(QUEUE))
+		return;
+
+	disable_irq(HD_IRQ);
+	local_irq_enable();
+	reset = 1;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	printk("hd%c: timeout\n", dev+'a');
+	if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+		printk("hd%c: too many errors\n", dev+'a');
+#endif
+		end_request(CURRENT, 0);
+	}
+	local_irq_disable();
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+	if (recalibrate[dev]) {
+		recalibrate[dev] = 0;
+		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+		return reset;
+	}
+	if (hd_info[dev].head > 16) {
+		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+		end_request(CURRENT, 0);
+	}
+	special_op[dev] = 0;
+	return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible.  In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * 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. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+	unsigned int dev, block, nsect, sec, track, head, cyl;
+
+	if (do_hd)
+		return;
+repeat:
+	del_timer(&device_timer);
+	local_irq_enable();
+
+	if (blk_queue_empty(QUEUE)) {
+		do_hd = NULL;
+		return;
+	}
+
+	if (reset) {
+		local_irq_disable();
+		reset_hd();
+		return;
+	}
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+	if (dev >= NR_HD || block >= get_capacity(hd_gendisk+dev) ||
+	    ((block+nsect) > get_capacity(hd_gendisk+unit))) {
+		if (dev >= NR_HD)
+			printk("hd: bad minor number: device=%s\n",
+			       kdevname(CURRENT->rq_dev));
+		else
+			printk("hd%c: bad access: block=%d, count=%d\n",
+				dev+'a', block, nsect);
+		end_request(CURRENT, 0);
+		goto repeat;
+	}
+
+	if (special_op[dev]) {
+		if (do_special_op(dev))
+			goto repeat;
+		return;
+	}
+	sec   = block % hd_info[dev].sect + 1;
+	track = block / hd_info[dev].sect;
+	head  = track % hd_info[dev].head;
+	cyl   = track / hd_info[dev].head;
+#ifdef DEBUG
+	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
+#endif
+	if(CURRENT->flags & REQ_CMD) {
+		switch (rq_data_dir(CURRENT)) {
+		case READ:
+			hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+			if (reset)
+				goto repeat;
+			break;
+		case WRITE:
+			hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+			if (reset)
+				goto repeat;
+			if (wait_DRQ()) {
+				bad_rw_intr();
+				goto repeat;
+			}
+			outsw(HD_DATA,CURRENT->buffer,256);
+			break;
+		default:
+			printk("unknown hd-command\n");
+			end_request(CURRENT, 0);
+			break;
+		}
+	}
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+	disable_irq(HD_IRQ);
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+	int dev;
+
+	if ((!inode) || kdev_none(inode->i_rdev))
+		return -EINVAL;
+	dev = DEVICE_NR(inode->i_rdev);
+	if (dev >= NR_HD)
+		return -EINVAL;
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g; 
+			if (!loc)  return -EINVAL;
+			g.heads = hd_info[dev].head;
+			g.sectors = hd_info[dev].sect;
+			g.cylinders = hd_info[dev].cyl;
+			g.start = get_start_sect(inode->i_bdev);
+			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+		}
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+	int target =  DEVICE_NR(inode->i_rdev);
+	if (target >= NR_HD)
+		return -ENODEV;
+	return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+
+extern struct block_device_operations hd_fops;
+
+static struct gendisk hd_gendisk[2] = {
+{
+	.major =	MAJOR_NR,
+	.first_minor =	0,
+	.major_name =	"hda",
+	.minor_shift =	6,
+	.fops =		&hd_fops,
+},{
+	.major =	MAJOR_NR,
+	.first_minor =	64,
+	.major_name =	"hdb",
+	.minor_shift =	6,
+	.fops =		&hd_fops,
+}
+};
+	
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*handler)(void) = do_hd;
+
+	do_hd = NULL;
+	del_timer(&device_timer);
+	if (!handler)
+		handler = unexpected_hd_interrupt;
+	handler();
+	local_irq_enable();
+}
+
+static struct block_device_operations hd_fops = {
+	.open =		hd_open,
+	.ioctl =	hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run 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 in some of the routines after making sure it's
+ * safe.
+ */
+static void __init hd_geninit(void)
+{
+	int drive;
+
+	blk_queue_hardsect_size(QUEUE, 512);
+
+#ifdef __i386__
+	if (!NR_HD) {
+		extern struct drive_info drive_info;
+		unsigned char *BIOS = (unsigned char *) &drive_info;
+		unsigned long flags;
+		int cmos_disks;
+
+		for (drive=0 ; drive<2 ; drive++) {
+			hd_info[drive].cyl = *(unsigned short *) BIOS;
+			hd_info[drive].head = *(2+BIOS);
+			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+			hd_info[drive].ctl = *(8+BIOS);
+			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+			hd_info[drive].sect = *(14+BIOS);
+#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
+			if (hd_info[drive].cyl && NR_HD == drive)
+				NR_HD++;
+#endif
+			BIOS += 16;
+		}
+
+	/*
+		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
+		BIOS table, but not register compatible, and therefore
+		not present in CMOS.
+
+		Furthermore, we will assume that our ST-506 drives
+		<if any> are the primary drives in the system, and 
+		the ones reflected as drive 1 or 2.
+
+		The first drive is stored in the high nibble of CMOS
+		byte 0x12, the second in the low nibble.  This will be
+		either a 4 bit drive type or 0xf indicating use byte 0x19 
+		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+		Needless to say, a non-zero value means we have 
+		an AT controller hard disk for that drive.
+
+		Currently the rtc_lock is a bit academic since this
+		driver is non-modular, but someday... ?         Paul G.
+	*/
+
+		spin_lock_irqsave(&rtc_lock, flags);
+		cmos_disks = CMOS_READ(0x12);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
+		if (cmos_disks & 0xf0) {
+			if (cmos_disks & 0x0f)
+				NR_HD = 2;
+			else
+				NR_HD = 1;
+		}
+	}
+#endif /* __i386__ */
+#ifdef __arm__
+	if (!NR_HD) {
+		/* We don't know anything about the drive.  This means
+		 * that you *MUST* specify the drive parameters to the
+		 * kernel yourself.
+		 */
+		printk("hd: no drives specified - use hd=cyl,head,sectors"
+			" on kernel command line\n");
+	}
+#endif
+
+	for (drive=0 ; drive < NR_HD ; drive++) {
+		sector_t size = hd_info[drive].head *
+			hd_info[drive].sect * hd_info[drive].cyl;
+		set_capacity(hd_gendisk + drive, size);
+		printk ("%s: %ldMB, CHS=%d/%d/%d\n", hd_gendisk[drive].major_name,
+			size / 2048, hd_info[drive].cyl,
+			hd_info[drive].head, hd_info[drive].sect);
+	}
+	if (!NR_HD)
+		return;
+
+	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+		printk("hd: unable to get IRQ%d for the hard disk driver\n",
+			HD_IRQ);
+		NR_HD = 0;
+		return;
+	}
+	if (!request_region(HD_DATA, 8, "hd")) {
+		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+		NR_HD = 0;
+		free_irq(HD_IRQ, NULL);
+		return;
+	}
+	if (!request_region(HD_CMD, 1, "hd(cmd)")) {
+		printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
+		NR_HD = 0;
+		free_irq(HD_IRQ, NULL);
+		release_region(HD_DATA, 8);
+		return;
+	}
+
+	for(drive=0; drive < NR_HD; drive++) {
+		add_gendisk(hd_gendisk + drive);
+		register_disk(hd_gendisk + drive,
+			mk_kdev(MAJOR_NR,drive<<6), 1<<6,
+			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
+			hd_info[drive].cyl);
+	}
+}
+
+int __init hd_init(void)
+{
+	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+		return -1;
+	}
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_hd_request, &hd_lock);
+	blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 255);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
+	hd_geninit();
+	return 0;
+}
+
+static int parse_hd_setup (char *line) {
+	int ints[6];
+
+	(void) get_options(line, ARRAY_SIZE(ints), ints);
+	hd_setup(NULL, ints);
+
+	return 1;
+}
+__setup("hd=", parse_hd_setup);
+
diff -Nru a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/ht6560b.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,430 @@
+/*
+ *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
+ *
+ *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+ */
+
+/*
+ *
+ *  Version 0.01        Initial version hacked out of ide.c
+ *
+ *  Version 0.02        Added support for PIO modes, auto-tune
+ *
+ *  Version 0.03        Some cleanups
+ *
+ *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
+ *
+ *  Version 0.06        Prefetch mode now defaults no OFF. To set
+ *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
+ *                      Unmask irq is disabled when prefetch mode
+ *                      is enabled.
+ *
+ *  Version 0.07        Trying to fix CD-ROM detection problem.
+ *                      "Prefetch" mode bit OFF for ide disks and
+ *                      ON for anything else.
+ *
+ *
+ *  HT-6560B EIDE-controller support
+ *  To activate controller support use kernel parameter "ide0=ht6560b".
+ *  Use hdparm utility to enable PIO mode support.
+ *
+ *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
+ *             Jan Evert van Grootheest   <janevert@iae.nl>
+ *
+ *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_HT6560B_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_HT6560B_MODULE */
+
+/* #define DEBUG */  /* remove comments for DEBUG messages */
+
+/*
+ * The special i/o-port that HT-6560B uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit2 (0x04): "1" enables FIFO function
+ *    bit5 (0x20): "1" enables prefetched data read function  (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit1 (0x02): "1" enables prefetched data read function
+ *    bit2 (0x04): "0" enables multi-master system	      (?)
+ *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
+ */
+#define HT_CONFIG_PORT	  0x3e6
+#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+/*
+ * FIFO + PREFETCH (both a/b-model)
+ */
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF	  0x01
+#define HT_PREFETCH_MODE  0x20
+
+/*
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use IDE_SELECT_REG to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives.   [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
+ * of the value is the Active Time  (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
+ *
+ * Timing byte consists of
+ *	High nibble:  Recovery Cycle Time  (rt)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ *	Low nibble:   Active Cycle Time	   (at)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ * You can obtain optimized timing values by running Holtek IDESETUP.COM
+ * for DOS. DOS drivers get their timing values from command line, where
+ * the first value is the Recovery Time and the second value is the
+ * Active Time for each drive. Smaller value gives higher speed.
+ * In case of failures you should probably fall back to a higher value.
+ */
+#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
+
+/*
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+static void ht6560b_selectproc (ide_drive_t *drive)
+{
+	unsigned long flags;
+	static u8 current_select = 0;
+	static u8 current_timing = 0;
+	u8 select, timing;
+	
+	local_irq_save(flags);
+	
+	select = HT_CONFIG(drive);
+	timing = HT_TIMING(drive);
+	
+	if (select != current_select || timing != current_timing) {
+		current_select = select;
+		current_timing = timing;
+		if (drive->media != ide_disk || !drive->present)
+			select |= HT_PREFETCH_MODE;
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+		/*
+		 * Set timing for this drive:
+		 */
+		HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
+#ifdef DEBUG
+		printk("ht6560b: %s: select=%#x timing=%#x\n",
+			drive->name, select, timing);
+#endif
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+static int __init try_to_init_ht6560b(void)
+{
+	u8 orig_value;
+	int i;
+	
+	/* Autodetect ht6560b */
+	if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
+		return 0;
+	
+	for (i=3;i>0;i--) {
+		outb(0x00, HT_CONFIG_PORT);
+		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+			outb(orig_value, HT_CONFIG_PORT);
+			return 0;
+		}
+	}
+	outb(0x00, HT_CONFIG_PORT);
+	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+		outb(orig_value, HT_CONFIG_PORT);
+		return 0;
+	}
+	/*
+	 * Ht6560b autodetected
+	 */
+	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+	(void) inb(0x1f7);               /* IDE_STATUS_REG */
+	
+	printk("\nht6560b " HT6560B_VERSION
+	       ": chipset detected and initialized"
+#ifdef DEBUG
+	       " with debug enabled"
+#endif
+		);
+	return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+{
+	int active_time, recovery_time;
+	int active_cycles, recovery_cycles;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+	
+        if (pio) {
+		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+		
+		/*
+		 *  Just like opti621.c we try to calculate the
+		 *  actual cycle time for recovery and activity
+		 *  according system bus speed.
+		 */
+		active_time = ide_pio_timings[pio].active_time;
+		recovery_time = d.cycle_time 
+			- active_time
+			- ide_pio_timings[pio].setup_time;
+		/*
+		 *  Cycle times should be Vesa bus cycles
+		 */
+		active_cycles   = (active_time   * bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+		/*
+		 *  Upper and lower limits
+		 */
+		if (active_cycles   < 2)  active_cycles   = 2;
+		if (recovery_cycles < 2)  recovery_cycles = 2;
+		if (active_cycles   > 15) active_cycles   = 15;
+		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+		
+		return (u8)((recovery_cycles << 4) | active_cycles);
+	} else {
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+		
+		return HT_TIMING_DEFAULT;    /* default setting */
+	}
+}
+
+/*
+ *  Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, u8 state)
+{
+	unsigned long flags;
+	int t = HT_PREFETCH_MODE << 8;
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	
+	/*
+	 *  Prefetch mode and unmask irq seems to conflict
+	 */
+	if (state) {
+		drive->drive_data |= t;   /* enable prefetch mode */
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+	} else {
+		drive->drive_data &= ~t;  /* disable prefetch mode */
+		drive->no_unmask = 0;
+	}
+	
+	spin_unlock_irqrestore(&ide_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	u8 timing;
+	
+	switch (pio) {
+	case 8:         /* set prefetch off */
+	case 9:         /* set prefetch on */
+		ht_set_prefetch(drive, pio & 1);
+		return;
+	}
+	
+	timing = ht_pio2timings(drive, pio);
+	
+	spin_lock_irqsave(&ide_lock, flags);
+	
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	
+	spin_unlock_irqrestore(&ide_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+void __init probe_ht6560b (void)
+{
+	int t;
+	
+	request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
+	ide_hwifs[0].chipset = ide_ht6560b;
+	ide_hwifs[1].chipset = ide_ht6560b;
+	ide_hwifs[0].selectproc = &ht6560b_selectproc;
+	ide_hwifs[1].selectproc = &ht6560b_selectproc;
+	ide_hwifs[0].tuneproc = &tune_ht6560b;
+	ide_hwifs[1].tuneproc = &tune_ht6560b;
+	ide_hwifs[0].serialized = 1;  /* is this needed? */
+	ide_hwifs[1].serialized = 1;  /* is this needed? */
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+			
+	/*
+	 * Setting default configurations for drives
+	 */
+	t = (HT_CONFIG_DEFAULT << 8);
+	t |= HT_TIMING_DEFAULT;
+	ide_hwifs[0].drives[0].drive_data = t;
+	ide_hwifs[0].drives[1].drive_data = t;
+	t |= (HT_SECONDARY_IF << 8);
+	ide_hwifs[1].drives[0].drive_data = t;
+	ide_hwifs[1].drives[1].drive_data = t;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init ht6560b_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ht6560b &&
+	    ide_hwifs[1].chipset != ide_ht6560b)
+                return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].selectproc = NULL;
+	ide_hwifs[1].selectproc = NULL;
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+
+	ide_hwifs[0].drives[0].drive_data = 0;
+	ide_hwifs[0].drives[1].drive_data = 0;
+	ide_hwifs[1].drives[0].drive_data = 0;
+	ide_hwifs[1].drives[1].drive_data = 0;
+	release_region(HT_CONFIG_PORT, 1);
+}
+
+#ifndef MODULE
+/*
+ * init_ht6560b:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ht6560b (void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return;
+	}
+	if (!try_to_init_ht6560b()) {
+                printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return;
+	}
+	probe_ht6560b();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
+
+int __init ht6560b_mod_init(void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return -ENODEV;
+	}
+
+	if (!try_to_init_ht6560b()) {
+		printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	probe_ht6560b();
+        if (ide_hwifs[0].chipset != ide_ht6560b &&
+            ide_hwifs[1].chipset != ide_ht6560b) {
+                ht6560b_release();
+                return -ENODEV;
+        }
+        return 0;
+}
+module_init(ht6560b_mod_init);
+
+void __init ht6560b_mod_exit(void)
+{
+        ht6560b_release();
+}
+module_exit(ht6560b_mod_exit);
+#endif
+
diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/ide-cs.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,492 @@
+/*======================================================================
+
+    A driver for PCMCIA IDE/ATA disk cards
+
+    ide_cs.c 1.26 1999/11/16 02:10:49
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/major.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+#ifdef IDE4_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
+#endif
+};
+
+typedef struct ide_info_t {
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
+} ide_info_t;
+
+static void ide_config(dev_link_t *link);
+static void ide_release(u_long arg);
+static int ide_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide-cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ide_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ide_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ide_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	ide_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* ide_detach */
+
+/*======================================================================
+
+    ide_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+int idecs_register (int arg1, int arg2, int irq)
+{
+        hw_regs_t hw;
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+        hw.irq = irq;
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
+        return ide_register_hw(&hw, NULL);
+}
+
+void ide_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
+	}
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
+	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* retry registration in case device is still spinning up */
+    for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (hd >= 0) break;
+	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
+	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
+			      link->irq.AssignedIRQ);
+	    if (hd >= 0) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release((u_long)link);
+
+} /* ide_config */
+
+/*======================================================================
+
+    After a card is removed, ide_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+void ide_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    ide_info_t *info = link->priv;
+    
+    DEBUG(0, "ide_release(0x%p)\n", link);
+
+    if (info->ndev) {
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+
+    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+    if (link->io.NumPorts2)
+	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+    
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* ide_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the ide drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
+
+/*====================================================================*/
+
+static int __init init_ide_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
+}
+
+static void __exit exit_ide_cs(void)
+{
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
diff -Nru a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/macide.c	Sun Sep 15 19:19:28 2002
@@ -0,0 +1,153 @@
+/*
+ *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
+ *
+ *     Copyright (C) 1998 by Michael Schmitz
+ *
+ *  This driver was written based on information obtained from the MacOS IDE
+ *  driver binary by Mikael Forselius
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_baboon.h>
+
+#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
+
+/*
+ * Generic IDE registers as offsets from the base
+ * These match MkLinux so they should be correct.
+ */
+
+#define IDE_DATA	0x00
+#define IDE_ERROR	0x04	/* see err-bits */
+#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
+#define IDE_SECTOR	0x0c	/* starting sector */
+#define IDE_LCYL	0x10	/* starting cylinder */
+#define IDE_HCYL	0x14	/* high byte of starting cyl */
+#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS	0x1c	/* see status-bits */
+#define IDE_CONTROL	0x38	/* control/altstatus */
+
+/*
+ * Mac-specific registers
+ */
+
+/*
+ * this register is odd; it doesn't seem to do much and it's
+ * not word-aligned like virtually every other hardware register
+ * on the Mac...
+ */
+
+#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
+				 *
+				 * Bit 0+1: some interrupt flags
+				 * Bit 2+3: some interrupt enable
+				 * Bit 4:   ??
+				 * Bit 5:   IDE interrupt flag (any hwif)
+				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
+				 * Bit 7:   Any interrupt condition
+				 */
+
+volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
+
+static int macide_offsets[IDE_NR_PORTS] = {
+    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
+    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
+};
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+	if (*ide_ifr & 0x20) {
+		*ide_ifr &= ~0x20;
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int state = baboon->mb_status & 0x04;
+
+	printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
+}
+#endif
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+void macide_init(void)
+{
+	hw_regs_t hw;
+	int index = -1;
+
+	switch (macintosh_config->ide_type) {
+	case MAC_IDE_QUADRA:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				quadra_ide_iops,
+				IRQ_NUBUS_F);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_PB:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				macide_pb_iops,
+				IRQ_NUBUS_C);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_BABOON:
+		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
+				0, 0, NULL,
+//				macide_baboon_iops,
+				IRQ_BABOON_1);
+		index = ide_register_hw(&hw, NULL);
+		if (index == -1) break;
+		if (macintosh_config->ident == MAC_MODEL_PB190) {
+
+			/* Fix breakage in ide-disk.c: drive capacity	*/
+			/* is not initialized for drives without a 	*/
+			/* hardware ID, and we can't get that without	*/
+			/* probing the drive which freezes a 190.	*/
+
+			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+        		drive->capacity = drive->cyl*drive->head*drive->sect;
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
+					IRQ_FLG_FAST, "mediabay",
+					macide_mediabay_interrupt);
+#endif
+		}
+		break;
+
+	default:
+	    return;
+	}
+
+        if (index != -1) {
+		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_PB)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+		else
+			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+	}
+}
diff -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/pdc4030.c	Sun Sep 15 19:19:46 2002
@@ -0,0 +1,858 @@
+/*  -*- linux-c -*-
+ *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
+ *
+ *  Copyright (C) 1995-2002  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  Peter Denison <promise@pnd-pc.demon.co.uk>
+ *
+ *  This file provides support for the second port and cache of Promise
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
+ *
+ *  Thanks are due to Mark Lord for advice and patiently answering stupid
+ *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
+ *  especially Andre Hedrick.
+ *
+ *  Version 0.01	Initial version, #include'd in ide.c rather than
+ *                      compiled separately.
+ *                      Reads use Promise commands, writes as before. Drives
+ *                      on second channel are read-only.
+ *  Version 0.02        Writes working on second channel, reads on both
+ *                      channels. Writes fail under high load. Suspect
+ *			transfers of >127 sectors don't work.
+ *  Version 0.03        Brought into line with ide.c version 5.27.
+ *                      Other minor changes.
+ *  Version 0.04        Updated for ide.c version 5.30
+ *                      Changed initialization strategy
+ *  Version 0.05	Kernel integration.  -ml
+ *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
+ *  Version 0.07	Added support for DC4030 variants
+ *			Secondary interface autodetection
+ *  Version 0.08	Renamed to pdc4030.c
+ *  Version 0.09	Obsolete - never released - did manual write request
+ *			splitting before max_sectors[major][minor] available.
+ *  Version 0.10	Updated for 2.1 series of kernels
+ *  Version 0.11	Updated for 2.3 series of kernels
+ *			Autodetection code added.
+ *
+ *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
+ */
+
+/*
+ * Once you've compiled it in, you'll have to also enable the interface
+ * setup routine from the kernel command line, as in 
+ *
+ *	'linux ide0=dc4030' or 'linux ide1=dc4030'
+ *
+ * It should now work as a second controller also ('ide1=dc4030') but only
+ * if you DON'T have BIOS V4.44, which has a bug. If you have this version
+ * and EPROM programming facilities, you need to fix 4 bytes:
+ * 	2496:	81	81
+ *	2497:	3E	3E
+ *	2498:	22	98	*
+ *	2499:	06	05	*
+ *	249A:	F0	F0
+ *	249B:	01	01
+ *	...
+ *	24A7:	81	81
+ *	24A8:	3E	3E
+ *	24A9:	22	98	*
+ *	24AA:	06	05	*
+ *	24AB:	70	70
+ *	24AC:	01	01
+ *
+ * As of January 1999, Promise Technology Inc. have finally supplied me with
+ * some technical information which has shed a glimmer of light on some of the
+ * problems I was having, especially with writes. 
+ *
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
+ */
+
+#define DEBUG_READ
+#define DEBUG_WRITE
+#define __PROMISE_4030
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "pdc4030.h"
+
+/*
+ * promise_selectproc() is invoked by ide.c
+ * in preparation for access to the specified drive.
+ */
+static void promise_selectproc (ide_drive_t *drive)
+{
+	unsigned int number;
+
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	HWIF(drive)->OUTB(number, IDE_FEATURE_REG);
+}
+
+/*
+ * pdc4030_cmd handles the set of vendor specific commands that are initiated
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
+ */
+int pdc4030_cmd(ide_drive_t *drive, u8 cmd)
+{
+	u32 timeout;
+	u8 status_val;
+
+	promise_selectproc(drive);	/* redundant? */
+	HWIF(drive)->OUTB(0xF3, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(cmd, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	timeout = HZ * 10;
+	timeout += jiffies;
+	do {
+		if(time_after(jiffies, timeout)) {
+			return 2; /* device timed out */
+		}
+		/* Delays at least 10ms to give interface a chance */
+		mdelay(10);
+		status_val = HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (status_val != 0x50 && status_val != 0x70);
+
+	if(status_val == 0x50)
+		return 0; /* device returned success */
+	else
+		return 1; /* device returned failure */
+}
+
+/*
+ * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
+ */
+int pdc4030_identify(ide_drive_t *drive)
+{
+	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
+}
+
+int enable_promise_support;
+
+/*
+ * setup_pdc4030()
+ * Completes the setup of a Promise DC4030 controller card, once found.
+ */
+int __init setup_pdc4030(ide_hwif_t *hwif)
+{
+        ide_drive_t *drive;
+	ide_hwif_t *hwif2;
+	struct dc_ident ident;
+	int i;
+	ide_startstop_t startstop;
+	
+	if (!hwif) return 0;
+
+	drive = &hwif->drives[0];
+	hwif2 = &ide_hwifs[hwif->index+1];
+	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+		return 1;
+
+	if (hwif->INB(IDE_NSECTOR_REG) == 0xFF ||
+	    hwif->INB(IDE_SECTOR_REG) == 0xFF) {
+		return 0;
+	}
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(0x08, IDE_CONTROL_REG);
+	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
+		return 0;
+	}
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+		printk(KERN_INFO
+			"%s: Failed Promise read config!\n",hwif->name);
+		return 0;
+	}
+	hwif->ata_input_data(drive, &ident, SECTOR_WORDS);
+	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+		return 0;
+	}
+	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
+	switch(ident.type) {
+		case 0x43:	printk("DC4030VL-2, "); break;
+		case 0x41:	printk("DC4030VL-1, "); break;
+		case 0x40:	printk("DC4030VL, "); break;
+		default:
+			printk("unknown - type 0x%02x - please report!\n"
+			       ,ident.type);
+			printk("Please e-mail the following data to "
+			       "promise@pnd-pc.demon.co.uk along with\n"
+			       "a description of your card and drives:\n");
+			for (i=0; i < 0x90; i++) {
+				printk("%02x ", ((unsigned char *)&ident)[i]);
+				if ((i & 0x0f) == 0x0f) printk("\n");
+			}
+			return 0;
+	}
+	printk("%dKB cache, ",(int)ident.cache_mem);
+	switch(ident.irq) {
+            case 0x00: hwif->irq = 14; break;
+            case 0x01: hwif->irq = 12; break;
+            default:   hwif->irq = 15; break;
+	}
+	printk("on IRQ %d\n",hwif->irq);
+
+	/*
+	 * Once found and identified, we set up the next hwif in the array
+	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
+	 * and other settings as the main hwif. This gives us two "mated"
+	 * hwifs pointing to the Promise card.
+	 *
+	 * We also have to shift the default values for the remaining
+	 * interfaces "up by one" to make room for the second interface on the
+	 * same set of values.
+	 */
+
+	hwif->chipset	= hwif2->chipset = ide_pdc4030;
+	hwif->mate	= hwif2;
+	hwif2->mate	= hwif;
+	hwif2->channel	= 1;
+	hwif->rqsize	= hwif2->rqsize = 127;
+	hwif->addressing = hwif2->addressing = 1;
+	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
+	hwif->serialized = hwif2->serialized = 1;
+	/* DC4030 hosted drives need their own identify... */
+	hwif->identify = hwif2->identify = &pdc4030_identify;
+
+	/* Shift the remaining interfaces up by one */
+	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
+		ide_hwif_t *h = &ide_hwifs[i];
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif /* DEBUG */
+		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
+		h->noprobe = (h-1)->noprobe;
+	}
+	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
+	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
+	hwif2->irq = hwif->irq;
+	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
+	for (i=0; i<2 ; i++) {
+		hwif->drives[i].io_32bit = 3;
+		hwif2->drives[i].io_32bit = 3;
+		hwif->drives[i].keep_settings = 1;
+		hwif2->drives[i].keep_settings = 1;
+		if (!ident.current_tm[i].cyl)
+			hwif->drives[i].noprobe = 1;
+		if (!ident.current_tm[i+2].cyl)
+			hwif2->drives[i].noprobe = 1;
+	}
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[hwif->index]);
+	probe_hwif_init(&ide_hwifs[hwif2->index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+        return 1;
+}
+
+/*
+ * detect_pdc4030()
+ * Tests for the presence of a DC4030 Promise card on this interface
+ * Returns: 1 if found, 0 if not found
+ */
+int __init detect_pdc4030(ide_hwif_t *hwif)
+{
+	ide_drive_t *drive = &hwif->drives[0];
+
+	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
+		return 0;
+	}
+	hwif->OUTB(0xF3, IDE_SECTOR_REG);
+	hwif->OUTB(0x14, IDE_SELECT_REG);
+	hwif->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	
+	ide_delay_50ms();
+
+	if (hwif->INB(IDE_ERROR_REG) == 'P' &&
+	    hwif->INB(IDE_NSECTOR_REG) == 'T' &&
+	    hwif->INB(IDE_SECTOR_REG) == 'I') {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+#ifndef MODULE
+void __init ide_probe_for_pdc4030(void)
+#else
+int ide_probe_for_pdc4030(void)
+#endif
+{
+	unsigned int	index;
+	ide_hwif_t	*hwif;
+
+#ifndef MODULE
+	if (enable_promise_support == 0)
+		return;
+#endif
+
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
+#ifndef MODULE
+			setup_pdc4030(hwif);
+#else
+			return setup_pdc4030(hwif);
+#endif
+		}
+	}
+#ifdef MODULE
+	return 0;
+#endif
+}
+
+void __init release_pdc4030(ide_hwif_t *hwif, ide_hwif_t *mate)
+{
+	hwif->chipset = ide_unknown;
+	hwif->selectproc = NULL;
+	hwif->serialized = 0;
+	hwif->drives[0].io_32bit = 0;
+	hwif->drives[1].io_32bit = 0;
+	hwif->drives[0].keep_settings = 0;
+	hwif->drives[1].keep_settings = 0;
+	hwif->drives[0].noprobe = 0;
+	hwif->drives[1].noprobe = 0;
+
+	if (mate != NULL) {
+		mate->chipset = ide_unknown;
+		mate->selectproc = NULL;
+		mate->serialized = 0;
+		mate->drives[0].io_32bit = 0;
+		mate->drives[1].io_32bit = 0;
+		mate->drives[0].keep_settings = 0;
+		mate->drives[1].keep_settings = 0;
+		mate->drives[0].noprobe = 0;
+		mate->drives[1].noprobe = 0;
+	}
+}
+
+#ifndef MODULE
+/*
+ * init_pdc4030:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_pdc4030(void)
+{
+	enable_promise_support = 1;
+}
+
+#else
+
+MODULE_AUTHOR("Peter Denison");
+MODULE_DESCRIPTION("Support of Promise 4030 VLB series IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init pdc4030_mod_init(void)
+{
+	if (enable_promise_support == 0)
+		enable_promise_support = 1;
+
+	if (!ide_probe_for_pdc4030())
+		return -ENODEV;
+        return 0;
+}
+module_init(pdc4030_mod_init);
+
+void __init pdc4030_mod_exit(void)
+{
+	unsigned int    index;
+	ide_hwif_t      *hwif;
+
+	if (enable_promise_support == 0)
+		return;
+ 
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_pdc4030) {
+			ide_hwif_t *mate = &ide_hwifs[hwif->index+1];
+			if (mate->chipset == ide_pdc4030)
+				release_pdc4030(hwif, mate);
+			else
+				release_pdc4030(hwif, NULL);
+                }
+        }
+	enable_promise_support = 0;
+}
+module_exit(pdc4030_mod_exit);
+#endif
+
+/*
+ * promise_read_intr() is the handler for disk read/multread interrupts
+ */
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
+{
+	int total_remaining;
+	unsigned int sectors_left, sectors_avail, nsect;
+	struct request *rq;
+	ata_status_t status;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	unsigned long flags;
+	char *to;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	if (!OK_STAT(status.all, DATA_READY, BAD_R_STAT))
+		return DRIVER(drive)->error(drive,
+			"promise_read_intr", status.all);
+
+read_again:
+	do {
+		sectors_left = HWIF(drive)->INB(IDE_NSECTOR_REG);
+		HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (HWIF(drive)->INB(IDE_NSECTOR_REG) != sectors_left);
+	rq = HWGROUP(drive)->rq;
+	sectors_avail = rq->nr_sectors - sectors_left;
+	if (!sectors_avail)
+		goto read_again;
+
+read_next:
+	rq = HWGROUP(drive)->rq;
+	nsect = rq->current_nr_sectors;
+	if (nsect > sectors_avail)
+		nsect = sectors_avail;
+	sectors_avail -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	to = ide_map_buffer(rq, &flags);
+	HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef DEBUG_READ
+	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+	       rq->sector+nsect-1,
+#ifdef CONFIG_IDE_TASKFILE_IO
+		(unsigned long) to,
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		(unsigned long) rq->buffer,
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	       rq->nr_sectors-nsect);
+#endif /* DEBUG_READ */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	ide_unmap_buffer(to, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	rq->buffer += nsect<<9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	rq->sector += nsect;
+	rq->errors = 0;
+	rq->nr_sectors -= nsect;
+	total_remaining = rq->nr_sectors;
+	if ((rq->current_nr_sectors -= nsect) <= 0) {
+		DRIVER(drive)->end_request(drive, 1);
+	}
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
+	if (total_remaining > 0) {
+		if (sectors_avail)
+			goto read_next;
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		if (status.b.drq)
+			goto read_again;
+		if (status.b.bsy) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_read_intr,
+					WAIT_CMD,
+					NULL);
+#ifdef DEBUG_READ
+			printk(KERN_DEBUG "%s: promise_read: waiting for"
+			       "interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+			return ide_started;
+		}
+		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+		       "!DRQ !BUSY\n", drive->name);
+		return DRIVER(drive)->error(drive,
+				"promise read intr", status.all);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
+ */
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	int i;
+
+	if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_complete_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: completion timeout - still busy!\n",
+		       drive->name);
+		return DRIVER(drive)->error(drive, "busy timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	hwgroup->poll_timeout = 0;
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+#endif /* DEBUG_WRITE */
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		DRIVER(drive)->end_request(drive, 1);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	struct request *rq	= &hwgroup->wrq;
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		unsigned long flags;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		buffer = rq->buffer;
+
+		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct buffer_head *bh = rq->bh->b_reqnext;
+
+			/* end early early we ran out of requests */
+			if (!bh) {
+				mcount = 0;
+			} else {
+				rq->bh			= bh;
+				rq->current_nr_sectors	= bh->b_size >> 9;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer		= bh->b_data;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+#ifdef CONFIG_IDE_TASKFILE_IO
+		ide_unmap_buffer(buffer, &flags);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	} while (mcount);
+
+	return 0;
+}
+
+/*
+ * promise_write_pollfunc() is the handler for disk write completion polling.
+ */
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_write_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+		return DRIVER(drive)->error(drive, "write timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	/*
+	 * Now write out last 4 sectors and poll for not BUSY
+	 */
+	promise_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (hwgroup->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
+		drive->name, HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+	return ide_started;
+}
+
+/*
+ * promise_write() transfers a block of one or more sectors of data to a
+ * drive as part of a disk write operation. All but 4 sectors are transferred
+ * in the first attempt, then the interface is polled (nicely!) for completion
+ * before the final 4 sectors are transferred. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
+ */
+static ide_startstop_t promise_write (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
+
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+	       "buffer=%p\n", drive->name, rq->sector,
+	       rq->sector + rq->nr_sectors - 1, rq->buffer);
+#endif /* DEBUG_WRITE */
+
+	/*
+	 * If there are more than 4 sectors to transfer, do n-4 then go into
+	 * the polling strategy as defined above.
+	 */
+	if (rq->nr_sectors > 4) {
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
+	} else {
+	/*
+	 * There are 4 or fewer sectors to transfer, do them all in one go
+	 * and wait for NOT BUSY.
+	 */
+		if (promise_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&promise_complete_pollfunc,
+				HZ/100,
+				NULL);
+
+#ifdef DEBUG_WRITE
+		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
+			"status = %02x\n", drive->name,
+			HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+		return ide_started;
+	}
+}
+
+/*
+ * do_pdc4030_io() is called from promise_rw_disk, having had the block number
+ * already set up. It issues a READ or WRITE command to the Promise
+ * controller, assuming LBA has been used to set up the block number.
+ */
+#ifndef CONFIG_IDE_TASKFILE_IO
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+{
+#else /* CONFIG_IDE_TASKFILE_IO */
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
+{
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	ide_startstop_t startstop;
+	unsigned long timeout;
+	u8 stat = 0;
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	if (IDE_CONTROL_REG)
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive, 0);
+	HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+	HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	switch(rq->cmd) {
+	case READ:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
+		timeout = jiffies + HZ/20; /* 50ms wait */
+		do {
+			stat = HWIF(drive)->INB(IDE_STATUS_REG);
+			if (stat & DRQ_STAT) {
+				udelay(1);
+				return promise_read_intr(drive);
+			}
+			if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {
+#ifdef DEBUG_READ
+				printk(KERN_DEBUG "%s: read: waiting for "
+						"interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+				ide_set_handler(drive,
+						&promise_read_intr,
+						WAIT_CMD,
+						NULL);
+				return ide_started;
+			}
+			udelay(1);
+		} while (time_before(jiffies, timeout));
+
+		printk(KERN_ERR "%s: reading: No DRQ and not "
+				"waiting - Odd!\n", drive->name);
+		return ide_stopped;
+	case WRITE:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing "
+				"PROMISE_WRITE\n", drive->name);
+			return startstop;
+	    	}
+		if (!drive->unmask)
+			local_irq_disable();
+		HWGROUP(drive)->wrq = *rq; /* scratchpad */
+		return promise_write(drive);
+	default:
+		printk("KERN_WARNING %s: bad command: %d\n",
+			drive->name, rq->cmd);
+		DRIVER(drive)->end_request(drive, 0);
+		return ide_stopped;
+	}
+}
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	/* The four drives on the two logical (one physical) interfaces
+	   are distinguished by writing the drive number (0-3) to the
+	   Feature register.
+	   FIXME: Is promise_selectproc now redundant??
+	*/
+	int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+#ifndef CONFIG_IDE_TASKFILE_IO
+	ide_hwif_t *hwif = HWIF(drive);
+
+	BUG_ON(rq->nr_sectors > 127);
+
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+#ifdef DEBUG
+	printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+		"buffer=0x%08lx\n", drive->name,
+		(rq->cmd==READ)?"read":"writ", block,
+		rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+	hwif->OUTB(drive_number, IDE_FEATURE_REG);
+	hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG);
+	hwif->OUTB(block,IDE_SECTOR_REG);
+	hwif->OUTB(block>>=8,IDE_LCYL_REG);
+	hwif->OUTB(block>>=8,IDE_HCYL_REG);
+	hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+
+	return do_pdc4030_io(drive, rq);
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+	struct hd_drive_task_hdr	taskfile;
+	ide_task_t			args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.feature	= drive_number;
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));
+	/* We can't call ide_cmd_type_parser here, since it won't understand
+	   our command, but that doesn't matter, since we don't use the
+	   generic interrupt handlers either. Setup the bits of args that we
+	   do need.
+	*/
+	args.handler		= NULL;
+	args.rq			= (struct request *) rq;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+}
diff -Nru a/drivers/ide/legacy/pdc4030.h b/drivers/ide/legacy/pdc4030.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/pdc4030.h	Sun Sep 15 19:20:08 2002
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/pdc4030.h
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & authors
+ */
+
+/*
+ * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
+ */
+
+#ifndef IDE_PROMISE_H
+#define IDE_PROMISE_H
+
+#include <linux/config.h>
+
+#ifndef CONFIG_BLK_DEV_PDC4030
+# ifdef _IDE_DISK
+
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ide_startstop_t promise_rw_disk(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+        return ide_stopped;
+}
+# endif /* _IDE_DISK */
+#else /* CONFIG_BLK_DEV_PDC4030 */
+# ifdef _IDE_DISK
+#  define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+# endif /* _IDE_DISK */
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+#ifdef __PROMISE_4030
+#define	PROMISE_EXTENDED_COMMAND	0xF0
+#define	PROMISE_READ			0xF2
+#define	PROMISE_WRITE			0xF3
+/* Extended commands - main command code = 0xf0 */
+#define	PROMISE_GET_CONFIG		0x10
+#define	PROMISE_IDENTIFY		0x20
+
+struct translation_mode {
+	u16	cyl;
+	u8	head;
+	u8	sect;
+};
+
+struct dc_ident {
+	u8	type;
+	u8	unknown1;
+	u8	hw_revision;
+	u8	firmware_major;
+	u8	firmware_minor;
+	u8	bios_address;
+	u8	irq;
+	u8	unknown2;
+	u16	cache_mem;
+	u16	unknown3;
+	u8	id[2];
+	u16	info;
+	struct translation_mode current_tm[4];
+	u8	pad[SECTOR_WORDS*4 - 32];
+};
+
+#endif /* __PROMISE_4030 */
+
+#endif /* IDE_PROMISE_H */
diff -Nru a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/q40ide.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,93 @@
+/*
+ *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ *     (c) Richard Zidlicky
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/ide.h>
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define Q40IDE_NUM_HWIFS	2
+
+#define PCIDE_BASE1	0x1f0
+#define PCIDE_BASE2	0x170
+#define PCIDE_BASE3	0x1e8
+#define PCIDE_BASE4	0x168
+#define PCIDE_BASE5	0x1e0
+#define PCIDE_BASE6	0x160
+
+static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
+    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
+    PCIDE_BASE6 */
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+
+/* HD_DATA was redefined in asm-m68k/ide.h */
+#undef HD_DATA
+#define HD_DATA  0x1f0
+
+
+#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
+    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
+    PCIDE_REG(CMD)
+};
+
+static int q40ide_default_irq(q40ide_ioreg_t base)
+{
+           switch (base) { 
+	            case 0x1f0: return 14;
+		    case 0x170: return 15;
+		    case 0x1e8: return 11;
+		    default:
+			return 0;
+	   }
+}
+
+
+
+    /*
+     *  Probe for Q40 IDE interfaces
+     */
+
+void q40ide_init(void)
+{
+    int i;
+
+    if (!MACH_IS_Q40)
+      return ;
+
+    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+	hw_regs_t hw;
+
+	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
+			pcide_bases[i]+0x206, 
+			0, NULL,
+//			pcide_iops,
+			q40ide_default_irq(pcide_bases[i]));
+	ide_register_hw(&hw, NULL);
+    }
+}
+
diff -Nru a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/qd65xx.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
+ *
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Version 0.03	Cleaned auto-tune, added probe
+ *  Version 0.04	Added second channel tuning
+ *  Version 0.05	Enhanced tuning ; added qd6500 support
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
+ *
+ * QDI QD6500/QD6580 EIDE controller fast support
+ *
+ * Please set local bus speed using kernel parameter idebus
+ * 	for example, "idebus=33" stands for 33Mhz VLbus
+ * To activate controller support, use "ide0=qd65xx"
+ * To enable tuning, use "ide0=autotune"
+ * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_QD65XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_QD65XX_MODULE */
+
+#include "qd65xx.h"
+
+/*
+ * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
+ *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
+ *	-- qd6500 is a single IDE interface
+ *	-- qd6580 is a dual IDE interface
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ * More Information given by Petr Soucek (petr@ryston.cz)
+ * http://www.ryston.cz/petr/vlb
+ */
+
+/*
+ * base: Timer1
+ *
+ *
+ * base+0x01: Config (R/O)
+ *
+ * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
+ * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
+ * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
+ * bit 3: qd6500: 1 = disabled, 0 = enabled
+ *        qd6580: 1
+ * upper nibble:
+ *        qd6500: 1100
+ *        qd6580: either 1010 or 0101
+ *
+ *
+ * base+0x02: Timer2 (qd6580 only)
+ *
+ *
+ * base+0x03: Control (qd6580 only)
+ *
+ * bits 0-3 must always be set 1
+ * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
+ * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
+ *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
+ *                                                   channel 1 for hdc & hdd
+ * bit 1 : 1 = only disks on primary port
+ *         0 = disks & ATAPI devices on primary port
+ * bit 2-4 : always 0
+ * bit 5 : status, but of what ?
+ * bit 6 : always set 1 by dos driver
+ * bit 7 : set 1 for non-ATAPI devices on primary port
+ *	(maybe read-ahead and post-write buffer ?)
+ */
+
+static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
+
+static void qd_write_reg (u8 content, u8 reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(content,reg);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+u8 __init qd_read_reg (u8 reg)
+{
+	unsigned long flags;
+	u8 read;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	read = inb(reg);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return read;
+}
+
+/*
+ * qd_select:
+ *
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+
+static void qd_select (ide_drive_t *drive)
+{
+	u8 index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
+			(QD_TIMREG(drive) & 0x02);
+
+	if (timings[index] != QD_TIMING(drive))
+		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+}
+
+/*
+ * qd6500_compute_timing
+ *
+ * computes the timing value where
+ *	lower nibble represents active time,   in count of VLB clocks
+ *	upper nibble represents recovery time, in count of VLB clocks
+ */
+
+static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+{
+	u8 active_cycle,recovery_cycle;
+
+	if (system_bus_clock()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	} else {
+		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+	}
+
+	return((recovery_cycle<<4) | 0x08 | active_cycle);
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+	u8 active_cycle   = 17 - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
+	u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+
+	return((recovery_cycle<<4) | active_cycle);
+}
+
+/*
+ * qd_find_disk_type
+ *
+ * tries to find timing from dos driver's table
+ */
+
+static int qd_find_disk_type (ide_drive_t *drive,
+		int *active_time, int *recovery_time)
+{
+	struct qd65xx_timing_s *p;
+	char model[40];
+
+	if (!*drive->id->model) return 0;
+
+	strncpy(model,drive->id->model,40);
+	ide_fixstring(model,40,1); /* byte-swap */
+
+	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
+		if (!strncmp(p->model, model+p->offset, 4)) {
+			printk(KERN_DEBUG "%s: listed !\n", drive->name);
+			*active_time = p->active;
+			*recovery_time = p->recovery;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * qd_timing_ok:
+ *
+ * check whether timings don't conflict
+ */
+
+static int qd_timing_ok (ide_drive_t drives[])
+{
+	return (IDE_IMPLY(drives[0].present && drives[1].present,
+			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
+			          QD_TIMING(drives) == QD_TIMING(drives+1))));
+	/* if same timing register, must be same timing */
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing, and enables selectproc as needed
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	if (qd_timing_ok(hwif->drives)) {
+		qd_select(drive); /* selects once */
+		hwif->selectproc = NULL;
+	} else
+		hwif->selectproc = &qd_select;
+
+	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
+		&& drive->id->eide_pio >= 240) {
+
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+				drive->id->tPIO);
+		active_time = 110;
+		recovery_time = drive->id->eide_pio - 120;
+	}
+
+	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	int base = HWIF(drive)->select_data;
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+		pio = IDE_MIN(pio,4);
+
+		switch (pio) {
+			case 0: break;
+			case 3:
+				if (d.cycle_time >= 110) {
+					active_time = 86;
+					recovery_time = d.cycle_time - 102;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			case 4:
+				if (d.cycle_time >= 69) {
+					active_time = 70;
+					recovery_time = d.cycle_time - 61;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			default:
+				if (d.cycle_time >= 180) {
+					active_time = 110;
+					recovery_time = d.cycle_time - 120;
+				} else {
+					active_time = ide_pio_timings[pio].active_time;
+					recovery_time = d.cycle_time
+							-active_time;
+				}
+		}
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+	}
+
+	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+		qd_write_reg(0x5f, QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
+			"and post-write buffer on %s.\n",
+			drive->name, HWIF(drive)->name);
+	}
+
+	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+}
+
+/*
+ * qd_testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init qd_testreg(int port)
+{
+	u8 savereg;
+	u8 readreg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	savereg = inb_p(port);
+	outb_p(QD_TESTVAL, port);	/* safe value */
+	readreg = inb_p(port);
+	outb(savereg, port);
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	if (savereg == QD_TESTVAL) {
+		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
+		printk(KERN_ERR "Assuming qd65xx is not present.\n");
+		return 1;
+	}
+
+	return (readreg != QD_TESTVAL);
+}
+
+/*
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+void __init qd_setup (int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (ide_drive_t *, u8 pio))
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+
+	hwif->chipset = ide_qd65xx;
+	hwif->channel = unit;
+	hwif->select_data = base;
+	hwif->config_data = config;
+	hwif->drives[0].drive_data = data0;
+	hwif->drives[1].drive_data = data1;
+	hwif->drives[0].io_32bit =
+	hwif->drives[1].io_32bit = 1;
+	hwif->tuneproc = tuneproc;
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+void __init qd_unsetup (int unit)
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+	u8 config = hwif->config_data;
+	int base = hwif->select_data;
+	void *tuneproc = (void *) hwif->tuneproc;
+
+	if (!(hwif->chipset == ide_qd65xx)) return;
+
+	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+	hwif->selectproc = NULL;
+	hwif->tuneproc = NULL;
+
+	if (tuneproc == (void *) qd6500_tune_drive) {
+		// will do it for both
+		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+	} else if (tuneproc == (void *) qd6580_tune_drive) {
+		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+		} else {
+			qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+		}
+	} else {
+		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+		printk(KERN_WARNING "keeping settings !\n");
+	}
+}
+
+/*
+ * qd_probe:
+ *
+ * looks at the specified baseport, and if qd found, registers & initialises it
+ * return 1 if another qd may be probed
+ */
+
+int __init qd_probe (int base)
+{
+	u8 config;
+	u8 unit;
+
+	config = qd_read_reg(QD_CONFIG_PORT);
+
+	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+		return 1;
+
+	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+	if ((config & 0xf0) == QD_CONFIG_QD6500) {
+
+		if (qd_testreg(base)) return 1;		/* bad register */
+
+		/* qd6500 found */
+
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+			ide_hwifs[unit].name, base);
+		
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+			config, QD_ID3);
+		
+		if (config & QD_CONFIG_DISABLED) {
+			printk(KERN_WARNING "qd6500 is disabled !\n");
+			return 1;
+		}
+
+		qd_setup(unit, base, config, QD6500_DEF_DATA,
+			QD6500_DEF_DATA, &qd6500_tune_drive);
+		return 1;
+	}
+
+	if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
+	    ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
+
+		u8 control;
+
+		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
+			/* bad registers */
+
+		/* qd6580 found */
+
+		control = qd_read_reg(QD_CONTROL_PORT);
+
+		printk(KERN_NOTICE "qd6580 at %#x\n", base);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+			config, control, QD_ID3);
+
+		if (control & QD_CONTR_SEC_DISABLED) {
+			/* secondary disabled */
+			printk(KERN_INFO "%s: qd6580: single IDE board\n",
+					ide_hwifs[unit].name);
+			qd_setup(unit, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 1;
+		} else {
+			/* secondary enabled */
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+					ide_hwifs[0].name,ide_hwifs[1].name);
+
+			qd_setup(0, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA,
+				&qd6580_tune_drive);
+			qd_setup(1, base, config | (control << 8),
+				QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 0; /* no other qd65xx possible */
+		}
+	}
+	/* no qd65xx found */
+	return 1;
+}
+
+#ifndef MODULE
+/*
+ * init_qd65xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_qd65xx (void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+}
+
+#else
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
+
+int __init qd65xx_mod_init(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+	if (ide_hwifs[0].chipset != ide_qd65xx &&
+	    ide_hwifs[1].chipset != ide_qd65xx)
+		return -ENODEV;
+	return 0;
+}
+module_init(qd65xx_mod_init);
+
+void __init qd65xx_mod_exit(void)
+{
+	qd_unsetup(0);
+	qd_unsetup(1);
+}
+module_exit(qd65xx_mod_exit);
+#endif
diff -Nru a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/qd65xx.h	Sun Sep 15 19:19:39 2002
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/qd65xx.h
+ *
+ * Copyright (c) 2000	Linus Torvalds & authors
+ */
+
+/*
+ * Authors:	Petr Soucek <petr@ryston.cz>
+ * 		Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+#define IDE_IMPLY(a,b)	((!(a)) || (b))
+
+#define QD_TIM1_PORT		(base)
+#define QD_CONFIG_PORT		(base+0x01)
+#define QD_TIM2_PORT		(base+0x02)
+#define QD_CONTROL_PORT		(base+0x03)
+
+#define QD_CONFIG_IDE_BASEPORT	0x01
+#define QD_CONFIG_BASEPORT	0x02
+#define QD_CONFIG_ID3		0x04
+#define QD_CONFIG_DISABLED	0x08
+#define QD_CONFIG_QD6500	0xc0
+#define QD_CONFIG_QD6580_A	0xa0
+#define QD_CONFIG_QD6580_B	0x50
+
+#define QD_CONTR_SEC_DISABLED	0x01
+
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
+
+#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
+#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
+
+#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
+
+#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
+#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
+
+#define QD_TESTVAL		0x19	/* safe value */
+
+/* Drive specific timing taken from DOS driver v3.7 */
+
+struct qd65xx_timing_s {
+	char	offset;   /* ofset from the beginning of Model Number" */
+	char	model[4];    /* 4 chars from Model number, no conversion */
+	short	active;   /* active time */
+	short	recovery; /* recovery time */
+} qd65xx_timing [] = {
+	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
+	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
+	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
+	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
+	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
+	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
+	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
+	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
+	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
+	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
+	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
+	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
+	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
+	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
+	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
+	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
+	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
+	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
+	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
+	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
+	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
+	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
+	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
+	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
+	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
+	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
+	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
+	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
+	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
+	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
+	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
+	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
+	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
+	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
+	{  6, "61 0", 135, 285 },  /* WD AC160				*/
+	{  6, "1107", 135, 235 },  /* WD AC1170				*/
+	{  6, "2101", 110, 220 },  /* WD AC1210				*/
+	{  6, "4202", 135, 245 },  /* WD AC2420				*/
+	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
+	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
+	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
+	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
+	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
+	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
+	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
+	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
+	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
+	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
+	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
+	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
+	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
+	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
+	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
+	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
+	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
+	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
+	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
+	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
+	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
+	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
+	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
+	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
+	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
+	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
+	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
+	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
+	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
+	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
+	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
+	{  2, "2309", 175, 295 },  /* ST3290A				*/
+	{  2, "3358", 180, 310 },  /* ST3385A				*/
+	{  2, "6355", 180, 310 },  /* ST3655A				*/
+	{  2, "1900", 175, 270 },  /* ST9100A				*/
+	{  2, "1954", 175, 270 },  /* ST9145A				*/
+	{  2, "1909", 175, 270 },  /* ST9190AG				*/
+	{  2, "2953", 175, 270 },  /* ST9235A				*/
+	{  2, "1359", 175, 270 },  /* ST3195A				*/
+	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
+	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
+	{  4, "2253", 175, 300 },  /* HP C2235A				*/
+	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
+	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
+	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
+	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
+	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
+};
diff -Nru a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/legacy/umc8672.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,237 @@
+/*
+ *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ *  This file provides support for the advanced features
+ *  of the UMC 8672 IDE interface.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	now configs/compiles separate from ide.c  -ml
+ *  Version 0.03	enhanced auto-tune, fix display bug
+ *  Version 0.05	replace sti() with restore_flags()  -ml
+ *			add detection of possible race condition  -ml
+ */
+
+/*
+ * VLB Controller Support from 
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="ide0=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test program supplied from UMC. 11 is the 
+ * highest speed (about PIO mode 3)
+ */
+#define REALLY_SLOW_IO		/* some systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_UMC8672_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_UMC8672_MODULE */
+
+/*
+ * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
+ */
+#define UMC_DRIVE0      1              /* DOS measured drive speeds */
+#define UMC_DRIVE1      1              /* 0 to 11 allowed */
+#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
+#define UMC_DRIVE3      1              /* In case of crash reduce speed */
+
+static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const u8 pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
+
+/*       0    1    2    3    4    5    6    7    8    9    10   11      */
+static const u8 speedtab [3][12] = {
+	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+
+static void out_umc (char port,char wert)
+{
+	outb_p(port,0x108);
+	outb_p(wert,0x109);
+}
+
+static inline u8 in_umc (char port)
+{
+	outb_p(port,0x108);
+	return inb_p(0x109);
+}
+
+static void umc_set_speeds (u8 speeds[])
+{
+	int i, tmp;
+
+	outb_p(0x5A,0x108); /* enable umc */
+
+	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+	tmp = 0;
+	for (i = 3; i >= 0; i--) {
+		tmp = (tmp << 2) | speedtab[1][speeds[i]];
+	}
+	out_umc (0xdc,tmp);
+	for (i = 0;i < 4; i++) {
+		out_umc (0xd0+i,speedtab[2][speeds[i]]);
+		out_umc (0xd8+i,speedtab[2][speeds[i]]);
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+		speeds[0], speeds[1], speeds[2], speeds[3]);
+}
+
+static void tune_umc (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+		drive->name, pio, pio_to_umc[pio]);
+	spin_lock_irqsave(&ide_lock, flags);
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+int __init probe_umc8672 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (check_region(0x108, 2)) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+		return 1;
+	}
+	outb_p(0x5A,0x108); /* enable umc */
+	if (in_umc (0xd5) != 0xa0) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: not found\n");
+		return 1;  
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	umc_set_speeds (current_speeds);
+	local_irq_restore(flags);
+
+	request_region(0x108, 2, "umc8672");
+	ide_hwifs[0].chipset = ide_umc8672;
+	ide_hwifs[1].chipset = ide_umc8672;
+	ide_hwifs[0].tuneproc = &tune_umc;
+	ide_hwifs[1].tuneproc = &tune_umc;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init umc8672_release (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		local_irq_restore(flags);
+		return;
+	}
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;	
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+	ide_hwifs[0].channel = 0;
+	ide_hwifs[1].channel = 0;
+
+	outb_p(0xa5,0x108); /* disable umc */
+
+	release_region(0x108, 2);
+	local_irq_restore(flags);
+}
+
+#ifndef MODULE
+/*
+ * init_umc8672:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_umc8672 (void)
+{
+	if (probe_umc8672())
+		printk(KERN_ERR "init_umc8672: umc8672 controller not found.\n");
+}
+
+#else
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
+
+int __init umc8672_mod_init(void)
+{
+	if (probe_umc8672())
+		return -ENODEV;
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		umc8672_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(umc8672_mod_init);
+
+void __init umc8672_mod_exit(void)
+{
+        umc8672_release();
+}
+module_exit(umc8672_mod_exit);
+#endif
+
diff -Nru a/drivers/ide/macide.c b/drivers/ide/macide.c
--- a/drivers/ide/macide.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
- *
- *     Copyright (C) 1998 by Michael Schmitz
- *
- *  This driver was written based on information obtained from the MacOS IDE
- *  driver binary by Mikael Forselius
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/machw.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_baboon.h>
-
-#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_DATA	0x00
-#define IDE_ERROR	0x04	/* see err-bits */
-#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
-#define IDE_SECTOR	0x0c	/* starting sector */
-#define IDE_LCYL	0x10	/* starting cylinder */
-#define IDE_HCYL	0x14	/* high byte of starting cyl */
-#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS	0x1c	/* see status-bits */
-#define IDE_CONTROL	0x38	/* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
-				 *
-				 * Bit 0+1: some interrupt flags
-				 * Bit 2+3: some interrupt enable
-				 * Bit 4:   ??
-				 * Bit 5:   IDE interrupt flag (any hwif)
-				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
-				 * Bit 7:   Any interrupt condition
-				 */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-static int macide_offsets[IDE_NR_PORTS] = {
-    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
-    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
-};
-
-int macide_ack_intr(ide_hwif_t* hwif)
-{
-	if (*ide_ifr & 0x20) {
-		*ide_ifr &= ~0x20;
-		return 1;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int state = baboon->mb_status & 0x04;
-
-	printk("macide: media bay %s detected\n", state? "removal":"insertion");
-}
-#endif
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-void macide_init(void)
-{
-	hw_regs_t hw;
-	int index = -1;
-
-	switch (macintosh_config->ide_type) {
-	case MAC_IDE_QUADRA:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_PB:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_BABOON:
-		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
-				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
-
-			/* Fix breakage in ide-disk.c: drive capacity	*/
-			/* is not initialized for drives without a 	*/
-			/* hardware ID, and we cna't get that without	*/
-			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
-        		drive->capacity = drive->cyl*drive->head*drive->sect;
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
-					IRQ_FLG_FAST, "mediabay",
-					macide_mediabay_interrupt);
-#endif
-		}
-		break;
-
-	default:
-	    return;
-	}
-
-        if (index != -1) {
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk("ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk("ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk("ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk("ide%d: Unknown Macintosh IDE interface\n", index);
-	}
-}
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Sun Sep 15 19:19:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,204 +0,0 @@
-/*
- * linux/drivers/ide/ns87415.c		Version 1.01  Mar. 18, 2000
- *
- * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	new = *old;
-
-	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->channel);
-	new = drive->present ? (new & ~bit) : (new | bit);
-
-	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
-	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
-	if (new != *old) {
-		unsigned char stat;
-
-		/*
-		 * Don't change DMA engine settings while Write Buffers
-		 * are busy.
-		 */
-		(void) pci_read_config_byte(dev, 0x43, &stat);
-		while (stat & 0x03) {
-			udelay(1);
-			(void) pci_read_config_byte(dev, 0x43, &stat);
-		}
-
-		*old = new;
-		(void) pci_write_config_dword(dev, 0x40, new);
-
-		/*
-		 * And let things settle...
-		 */
-		udelay(10);
-	}
-
-	local_irq_restore(flags);
-}
-
-static void ns87415_selectproc (ide_drive_t *drive)
-{
-	ns87415_prepare_drive (drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	byte		dma_stat;
-
-	switch (func) {
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			dma_stat = IN_BYTE(hwif->dma_base+2);
-			/* stop DMA */
-			OUT_BYTE(IN_BYTE(hwif->dma_base)&~1, hwif->dma_base);
-			/* from ERRATA: clear the INTR & ERROR bits */
-			OUT_BYTE(IN_BYTE(hwif->dma_base)|6, hwif->dma_base);
-			/* and free any DMA resources */
-			ide_destroy_dmatable(drive);
-			/* verify good DMA status */
-			return (dma_stat & 7) != 4;
-		case ide_dma_write:
-		case ide_dma_read:
-			/* select DMA xfer */
-			ns87415_prepare_drive(drive, 1);
-			/* use standard DMA stuff */
-			if (!ide_dmaproc(func, drive))
-				return 0;
-			/* DMA failed: select PIO xfer */
-			ns87415_prepare_drive(drive, 0);
-			return 1;
-		case ide_dma_check:
-			if (drive->media != ide_disk)
-				return ide_dmaproc(ide_dma_off_quietly, drive);
-			/* Fallthrough... */
-		default:
-			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned int ctrl, using_inta;
-	byte progif;
-#ifdef __sparc_v9__
-	int timeout;
-	byte stat;
-#endif
-
-	hwif->autodma = 0;
-	hwif->selectproc = &ns87415_selectproc;
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-	/*
-	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
-	 * Also, leave IRQ masked during drive probing, to prevent infinite
-	 * interrupts from a potentially floating INTA..
-	 *
-	 * IRQs get unmasked in selectproc when drive is first used.
-	 */
-	(void) pci_read_config_dword(dev, 0x40, &ctrl);
-	(void) pci_read_config_byte(dev, 0x09, &progif);
-	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->channel << 1));
-	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->channel));
-	if (hwif->mate) {
-		hwif->select_data = hwif->mate->select_data;
-	} else {
-		hwif->select_data = (unsigned long)
-					&ns87415_control[ns87415_count++];
-		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
-		if (using_inta)
-			ctrl &= ~(1 << 6);	/* unmask INTA */
-		*((unsigned int *)hwif->select_data) = ctrl;
-		(void) pci_write_config_dword(dev, 0x40, ctrl);
-
-		/*
-		 * Set prefetch size to 512 bytes for both ports,
-		 * but don't turn on/off prefetching here.
-		 */
-		pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
-		/*
-		 * XXX: Reset the device, if we don't it will not respond
-		 *      to SELECT_DRIVE() properly during first probe_hwif().
-		 */
-		timeout = 10000;
-		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			udelay(50);
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
-#endif
-	}
-
-	if (!using_inta)
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	OUT_BYTE(0x60, hwif->dma_base + 2);
-	hwif->dmaproc = &ns87415_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Nru a/drivers/ide/opti621.c b/drivers/ide/opti621.c
--- a/drivers/ide/opti621.c	Sun Sep 15 19:19:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,339 +0,0 @@
-/*
- *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
- *
- *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- *
- * OPTi is trademark of OPTi, Octek is trademark of Octek.
- *
- * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
- * and disassembled/traced setupvic.exe (DOS program).
- * It increases kernel code about 2 kB.
- * I don't have this card no more, but I hope I can get some in case
- * of needed development.
- * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
- * It has a place for a secondary connector in circuit, but nothing
- * is there. Also BIOS says no address for
- * secondary controller (see bellow in ide_init_opti621).
- * I've only tested this on my system, which only has one disk.
- * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
- * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
- * lockups). I tried the OCTEK double speed CD-ROM and
- * it does not work! But I can't boot DOS also, so it's probably
- * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
- * problems) and Seagate 1GB (as slave, WD as master). My experiences
- * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
- * it slows to about 100kB/s! I don't know why and I have
- * not this drive now, so I can't try it again.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe changes
- * in hdparm test).
- * After release of 0.1, I got some successful reports, so it might work.
- *
- * The main problem with OPTi is that some timings for master
- * and slave must be the same. For example, if you have master
- * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
- * got only one drive to set, but have to set both drives.
- * This is solved in compute_pios. If you don't set
- * the second drive, compute_pios use ide_get_best_pio_mode
- * for autoselect mode (you can change it to PIO 0, if you want).
- * If you then set the second drive to another PIO, the old value
- * (automatically selected) will be overrided by yours.
- * There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency which get
- * (use idebus=xx to select PCI bus speed).
- * Use ide0=autotune for automatical tune of the PIO modes.
- * If you get strange results, do not use this and set PIO manually
- * by hdparm.
- *
- * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8. 
- * Initial version of driver.
- * 
- * Version 0.2
- * Number 0.2 skipped.
- *
- * Version 0.3, Nov 29, 1997
- * by Mark Lord (probably), for 2.1.68
- * Updates for use with new IDE block driver.
- *
- * Version 0.4, Dec 14, 1997
- * by Jan Harkes
- * Fixed some errors and cleaned the code.
- *
- * Version 0.5, Jan 2, 1998
- * by Jaromir Koutek
- * Updates for use with (again) new IDE block driver.
- * Update of documentation.
- * 
- * Version 0.6, Jan 2, 1999
- * by Jaromir Koutek
- * Reversed to version 0.3 of the driver, because
- * 0.5 doesn't work.
- */
-
-#undef REALLY_SLOW_IO	/* most systems can safely undef this */
-#define OPTI621_DEBUG		/* define for debug messages */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define OPTI621_MAX_PIO 3
-/* In fact, I do not have any PIO 4 drive
- * (address: 25 ns, data: 70 ns, recovery: 35 ns),
- * but OPTi 82C621 is programmable and it can do (minimal values):
- * on 40MHz PCI bus (pulse 25 ns):
- *  address: 25 ns, data: 25 ns, recovery: 50 ns;
- * on 20MHz PCI bus (pulse 50 ns):
- *  address: 50 ns, data: 50 ns, recovery: 100 ns.
- */
-
-/* #define READ_PREFETCH 0 */
-/* Uncommnent for disable read prefetch.
- * There is some readprefetch capatibility in hdparm,
- * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inaccessible.
- * This (hw) read prefetch is safe on my drive.
- */
-
-#ifndef READ_PREFETCH
-#define READ_PREFETCH 0x40 /* read prefetch is enabled */
-#endif /* else read prefetch is disabled */
-
-#define READ_REG 0	/* index of Read cycle timing register */
-#define WRITE_REG 1	/* index of Write cycle timing register */
-#define CNTRL_REG 3	/* index of Control register */
-#define STRAP_REG 5	/* index of Strap register */
-#define MISC_REG 6	/* index of Miscellaneous register */
-
-int reg_base;
-
-#define PIO_NOT_EXIST 254
-#define PIO_DONT_KNOW 255
-
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-
-static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->drive_data
- *	second_contr - 0 for primary controller, 1 for secondary
- *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
- *	pio - PIO mode for selected drive (for other we don't know)
- */
-{
-	int d;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
-	for (d = 0; d < 2; ++d) {
-		drive = &hwif->drives[d];
-		if (drive->present) {
-			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
-#ifdef OPTI621_DEBUG
-			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
-#endif
-		} else {
-			drive->drive_data = PIO_NOT_EXIST;
-		}
-	}
-}
-
-int cmpt_clk(int time, int bus_speed)
-/* Returns (rounded up) time in clocks for time in ns,
- * with bus_speed in MHz.
- * Example: bus_speed = 40 MHz, time = 80 ns
- * 1000/40 = 25 ns (clk value),
- * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
- * Use idebus=xx to select right frequency.
- */
-{
-	return ((time*bus_speed+999)/1000);
-}
-
-static void write_reg(byte value, int reg)
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	IN_WORD(reg_base+1);
-	IN_WORD(reg_base+1);
-	OUT_BYTE(3, reg_base+2);
-	OUT_BYTE(value, reg_base+reg);
-	OUT_BYTE(0x83, reg_base+2);
-}
-
-static byte read_reg(int reg)
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	byte ret;
-	IN_WORD(reg_base+1);
-	IN_WORD(reg_base+1);
-	OUT_BYTE(3, reg_base+2);
-	ret=IN_BYTE(reg_base+reg);
-	OUT_BYTE(0x83, reg_base+2);
-	return ret;
-}
-
-typedef struct pio_clocks_s {
-	int	address_time;	/* Address setup (clocks) */
-	int	data_time;	/* Active/data pulse (clocks) */
-	int	recovery_time;	/* Recovery time (clocks) */
-} pio_clocks_t;
-
-static void compute_clocks(int pio, pio_clocks_t *clks)
-{
-        if (pio != PIO_NOT_EXIST) {
-        	int adr_setup, data_pls;
-		int bus_speed = system_bus_clock();
-
- 	       	adr_setup = ide_pio_timings[pio].setup_time;
-  	      	data_pls = ide_pio_timings[pio].active_time;
-	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
-	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
-     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			- adr_setup-data_pls, bus_speed);
-     		if (clks->address_time<1) clks->address_time = 1;
-     		if (clks->address_time>4) clks->address_time = 4;
-     		if (clks->data_time<1) clks->data_time = 1;
-     		if (clks->data_time>16) clks->data_time = 16;
-     		if (clks->recovery_time<2) clks->recovery_time = 2;
-     		if (clks->recovery_time>17) clks->recovery_time = 17;
-	} else {
-		clks->address_time = 1;
-		clks->data_time = 1;
-		clks->recovery_time = 2;
-		/* minimal values */
-	}
- 
-}
-
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, byte pio)
-{
-	/* primary and secondary drives share some registers,
-	 * so we have to program both drives
-	 */
-	unsigned long flags;
-	byte pio1, pio2;
-	pio_clocks_t first, second;
-	int ax, drdy;
-	byte cycle1, cycle2, misc;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	/* sets drive->drive_data for both drives */
-	compute_pios(drive, pio);
- 	pio1 = hwif->drives[0].drive_data;
- 	pio2 = hwif->drives[1].drive_data;
-
-	compute_clocks(pio1, &first);
-	compute_clocks(pio2, &second);
-
-	/* ax = max(a1,a2) */
-	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
-
-	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
-
-	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
-	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
-	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
-
-#ifdef OPTI621_DEBUG
-	printk("%s: master: address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, first.data_time, first.recovery_time, drdy);
-	printk("%s: slave:  address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, second.data_time, second.recovery_time, drdy);
-#endif
-
-	spin_lock_irqsave(&ide_lock, flags);
-
-     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	OUT_BYTE(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	OUT_BYTE(0xff, reg_base+5);	/* hmm, setupvic.exe does this ;-) */
-	IN_BYTE(reg_base+CNTRL_REG); 	/* if reads 0xff, adapter not exist? */
-	read_reg(CNTRL_REG);		/* if reads 0xc0, no interface exist? */
-	read_reg(STRAP_REG);		/* read version, probably 0 */
-
-	/* program primary drive */
-	write_reg(0,      MISC_REG);	/* select Index-0 for Register-A */
-	write_reg(cycle1, READ_REG);	/* set read cycle timings */
-	write_reg(cycle1, WRITE_REG);	/* set write cycle timings */
-
-	/* program secondary drive */
-	write_reg(1,      MISC_REG);	/* select Index-1 for Register-B */
-	write_reg(cycle2, READ_REG);	/* set read cycle timings */
-	write_reg(cycle2, WRITE_REG);	/* set write cycle timings */
-
-	write_reg(0x85, CNTRL_REG);	/* use Register-A for drive 0 */
-					/* use Register-B for drive 1 */
-
- 	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
- 					/*  and read prefetch for both drives */
-
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-/*
- * ide_init_opti621() is called once for each hwif found at boot.
- */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
-{
-	hwif->autodma = 0;
-	hwif->drives[0].drive_data = PIO_DONT_KNOW;
-	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
-
-	/* safety call for Anton A */
-	hwif->dma_base = 0;
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-#if 0
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) &&
-	    !(PCI_FUNC(dev->devfn) & 1))
-#else
-	if ((dev->device == PCI_DEVICE_ID_OPTI_82C558) &&
-	    (!(PCI_FUNC(dev->devfn) & 1)))
-#endif
-		return; /* OPTI621 is more than only a IDE controller */
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
diff -Nru a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,39 @@
+
+O_TARGET := idedriver-pci.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma100.o
+obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX)		+= amd74xx.o
+obj-$(CONFIG_BLK_DEV_CMD640)		+= cmd640.o
+obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
+obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_GENERIC)		+= generic.o
+obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
+obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
+#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.o
+obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
+obj-$(CONFIG_BLK_DEV_NFORCE)		+= nvidia.o
+obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)	+= pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PDC_ADMA)		+= pdcadma.o ide-adma.o
+obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000)		+= rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/pci/adma100.c b/drivers/ide/pci/adma100.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/adma100.c	Sun Sep 15 19:19:30 2002
@@ -0,0 +1,30 @@
+/*
+ *  linux/drivers/ide/adma100.c -- basic support for Pacific Digital ADMA-100 boards
+ *
+ *     Created 09 Apr 2002 by Mark Lord
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void __init ide_init_adma100 (ide_hwif_t *hwif)
+{
+	u32  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	void *v_admctl;
+
+	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
+	hwif->dma_base = 0;		// disable DMA completely
+	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
+	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
+	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
+	iounmap(v_admctl);				// all done; unmap config regs
+}
diff -Nru a/drivers/ide/pci/adma100.h b/drivers/ide/pci/adma100.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/adma100.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,36 @@
+#ifndef ADMA_100_H
+#define ADMA_100_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+extern void init_hwif_pdcadma(ide_hwif_t *);
+extern void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __initdata = {
+	{
+		vendor:	PCI_VENDOR_ID_PDC,
+		device:	PCI_DEVICE_ID_PDC_1841,
+		name:		"ADMA100",
+		init_setup:	init_setup_pdcadma,
+		init_chipset:	init_chipset_pdcadma,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdcadma,
+		init_dma:	init_dma_pdcadma,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+}
+
+#endif /* ADMA_100_H */
diff -Nru a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/aec62xx.c	Sun Sep 15 19:20:20 2002
@@ -0,0 +1,537 @@
+/*
+ * linux/drivers/ide/aec62xx.c		Version 0.11	March 27, 2002
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "aec62xx.h"
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc = 0;
+
+#define AEC_MAX_DEVS		5
+
+static struct pci_dev *aec_devs[AEC_MAX_DEVS];
+static int n_aec_devs;
+
+#undef DEBUG_AEC_REGS
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	char *chipset_nums[] = {"error", "error", "error", "error",
+				"error", "error", "850UF",   "860",
+				 "860R",   "865",  "865R", "error"  };
+//	char *modes_33[] = {};
+//	char *modes_34[] = {};
+	int i;
+
+	for (i = 0; i < n_aec_devs; i++) {
+		struct pci_dev *dev	= aec_devs[i];
+		u32 iobase		= pci_resource_start(dev, 4);
+		u8 c0 = 0, c1 = 0, art	= 0;
+#ifdef DEBUG_AEC_REGS
+		u8 uart			= 0;
+#endif /* DEBUG_AEC_REGS */
+
+		c0 = inb(iobase + 0x02);
+		c1 = inb(iobase + 0x0a);
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		(void) pci_read_config_byte(dev, 0x4a, &art);
+		p += sprintf(p, "                %sabled ",
+			(art&0x02)?" en":"dis");
+		p += sprintf(p, "                        %sabled\n",
+			(art&0x04)?" en":"dis");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s ",
+			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
+		p += sprintf(p, "            %s               %s\n",
+			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+			(void) pci_read_config_byte(dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0");
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+#endif /* DEBUG_AEC_REGS */
+		} else {
+			/*
+			 * case PCI_DEVICE_ID_ARTOP_ATP860:
+			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
+			 */
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+#endif /* DEBUG_AEC_REGS */
+		}
+	}
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return chipset_table->chipset_settings;
+}
+
+static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return chipset_table->ultra_settings;
+}
+
+static u8 aec62xx_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+#if 0
+			mode = (hwif->INB(hwif->dma_master) & 0x10) ? 4 : 3;
+#else
+			mode = (hwif->INB(((hwif->channel) ?
+					hwif->mate->dma_status :
+					hwif->dma_status)) & 0x10) ? 4 : 3;
+#endif
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		default:
+			return 1;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 d_conf		= 0;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 ultra = 0, ultra_conf = 0;
+	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+	tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 unit		= (drive->select.b.unit & 0x01);
+	u8 tmp1 = 0, tmp2 = 0;
+	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+	pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	switch (HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return ((int) aec6260_tune_chipset(drive, speed));
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return ((int) aec6210_tune_chipset(drive, speed));
+		default:
+			return -1;
+	}
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));	
+
+	if (!(speed))
+		return 0;
+
+	(void) aec62xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+	u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) aec62xx_tune_chipset(drive, speed);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int aec62xx_irq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+			printk(" AEC62XX time out ");
+#if 0
+			{
+				int i = 0;
+				u8 reg49h = 0;
+				pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+				for (i=0;i<256;i++)
+					pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+			}
+			return 0;
+#endif
+		default:
+			break;
+	}
+#if 0
+	{
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u8 tmp1 = 0, tmp2 = 0, mode6 = 0;
+
+		pci_read_config_byte(dev, 0x44, &tmp1);
+		pci_read_config_byte(dev, 0x45, &tmp2);
+		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+		mode6 = HWIF(drive)->INB(((hwif->channel) ?
+					   hwif->mate->dma_status :
+					   hwif->dma_status));
+		printk(" AEC6280 133=%x ", (mode6 & 0x10));
+	}
+#endif
+	return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name)
+{
+	int bus_speed = system_bus_clock();
+
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	aec_devs[n_aec_devs++] = dev;
+
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		ide_pci_register_host_proc(&aec62xx_procs[0]);
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	if (bus_speed <= 33)
+		pci_set_drvdata(dev, (void *) aec6xxx_33_base);
+	else
+		pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+
+	return dev->irq;
+}
+
+static void __init init_hwif_aec62xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->speedproc = &aec62xx_tune_chipset;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		hwif->serialized = hwif->channel;
+		hwif->no_dsc = 1;
+	}
+
+	if (hwif->mate)
+		hwif->mate->serialized = hwif->serialized;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq	= &aec62xx_irq_timeout;
+	hwif->ide_dma_timeout	= &aec62xx_irq_timeout;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		u8 reg54h = 0;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ide_lock, flags);
+		pci_read_config_byte(dev, 0x54, &reg54h);
+		pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+		spin_unlock_irqrestore(&ide_lock, flags);
+	} else {
+		u8 ata66	= 0;
+		pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+	        if (!(hwif->udma_four))
+			hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+	}
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_aec62xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u32 bar4reg = pci_resource_start(dev, 4);
+
+	if (inb(bar4reg+2) & 0x10) {
+		strcpy(d->name, "AEC6880");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6880R");
+	} else {
+		strcpy(d->name, "AEC6280");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6280R");
+	}
+
+	ide_setup_pci_device(dev, d);
+}
+
+int __init aec62xx_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_ARTOP)
+		return 0;
+
+	for (d = aec62xx_chipsets;
+		d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/aec62xx.h b/drivers/ide/pci/aec62xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/aec62xx.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,180 @@
+#ifndef AEC62XX_H
+#define AEC62XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AEC62XX_TIMINGS
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	byte		chipset_settings;
+	byte		ultra_settings;
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	{	XFER_UDMA_6,	0x31,	0x07	},
+	{	XFER_UDMA_5,	0x31,	0x06	},
+	{	XFER_UDMA_4,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x0a,	0x00	},
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	{	XFER_PIO_4,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	{	XFER_UDMA_6,	0x41,	0x06	},
+	{	XFER_UDMA_5,	0x41,	0x05	},
+	{	XFER_UDMA_4,	0x41,	0x04	},
+	{	XFER_UDMA_3,	0x41,	0x03	},
+	{	XFER_UDMA_2,	0x41,	0x02	},
+	{	XFER_UDMA_1,	0x41,	0x01	},
+	{	XFER_UDMA_0,	0x41,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00	},
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	{	XFER_PIO_4,	0x41,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
+
+#define BUSCLOCK(D)	\
+	((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D)))
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc;
+
+static int aec62xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t aec62xx_procs[] __initdata = {
+	{
+		name:		"aec62xx",
+		set:		1,
+		get_info:	aec62xx_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_aec6x80(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_aec62xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_aec62xx(struct pci_dev *, const char *);
+static void init_hwif_aec62xx(ide_hwif_t *);
+static void init_dma_aec62xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t aec62xx_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_ARTOP,
+		device:		PCI_DEVICE_ID_ARTOP_ATP850UF,
+		name:		"AEC6210",
+		init_setup:	init_setup_aec62xx,
+		init_chipset:	init_chipset_aec62xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_aec62xx,
+		init_dma:	init_dma_aec62xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_ARTOP,
+		device:		PCI_DEVICE_ID_ARTOP_ATP860,
+		name:		"AEC6260",
+		init_setup:	init_setup_aec62xx,
+		init_chipset:	init_chipset_aec62xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_aec62xx,
+		init_dma:	init_dma_aec62xx,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_ARTOP,
+		device:		PCI_DEVICE_ID_ARTOP_ATP860R,
+		name:		"AEC6260R",
+		init_setup:	init_setup_aec62xx,
+		init_chipset:	init_chipset_aec62xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_aec62xx,
+		init_dma:	init_dma_aec62xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		bootable:	NEVER_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_ARTOP,
+		device:		PCI_DEVICE_ID_ARTOP_ATP865,
+		name:		"AEC6X80",
+		init_setup:	init_setup_aec6x80,
+		init_chipset:	init_chipset_aec62xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_aec62xx,
+		init_dma:	init_dma_aec62xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_ARTOP,
+		device:		PCI_DEVICE_ID_ARTOP_ATP865R,
+		name:		"AEC6X80R",
+		init_setup:	init_setup_aec6x80,
+		init_chipset:	init_chipset_aec62xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_aec62xx,
+		init_dma:	init_dma_aec62xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* AEC62XX_H */
diff -Nru a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/alim15x3.c	Sun Sep 15 19:19:30 2002
@@ -0,0 +1,885 @@
+/*
+ * linux/drivers/ide/alim15x3.c		Version 0.15	2002/08/19
+ *
+ *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ *
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
+ *
+ **********************************************************************
+ *  9/7/99 --Parts from the above author are included and need to be
+ *  converted into standard interface, once I finish the thought.
+ *
+ *  Recent changes
+ *	Don't use LBA48 mode on ALi <= 0xC4
+ *	Don't poke 0x79 with a non ALi northbridge
+ *	Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "alim15x3.h"
+
+/*
+ *	ALi devices are not plug in. Otherwise these static values would
+ *	need to go. They ought to go away anyway
+ */
+ 
+static u8 m5229_revision;
+static u8 chip_is_1543c_e;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+static char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+static char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+
+/**
+ *	ali_get_info		-	generate proc file for ALi IDE
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the Ali devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	u32 bibma;
+	u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
+	char *q, *p = buffer;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	pci_read_config_dword(bmide_dev, 0x20, &bibma);
+	bibma = (bibma & 0xfff0) ;
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel"
+		"-------------------secondary channel"
+		"---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s"
+		"                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s"
+		"                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT"
+		"                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT"
+		"                                %dT\n"
+		"Command Rec. Count:   %dT"
+		"                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n\n");
+	p += sprintf(p,
+		"DMA enabled:      %s              %s"
+		"               %s              %s\n",
+		(c0&0x20) ? "Yes" : "No ",
+		(c0&0x40) ? "Yes" : "No ",
+		(c1&0x20) ? "Yes" : "No ",
+		(c1&0x40) ? "Yes" : "No " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) &&
+		    (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+		p += sprintf(p, q, t1, t2, t3, t4);
+	}
+
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings"
+		"--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s"
+		"                %s               %s\n"
+		"UDMA timings:     %s             %s"
+		"              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	ali15x3_tune_drive	-	set up a drive
+ *	@drive: drive to tune
+ *	@pio: unused
+ *
+ *	Select the best PIO timing for the drive in question. Then
+ *	program the controller for this drive set up
+ */
+ 
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	u8 s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = system_bus_clock();
+	int port = hwif->channel ? 0x5c : 0x58;
+	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	u8 cd_dma_fifo = 0;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+			r_clc = 0;
+	}
+	local_irq_save(flags);
+	
+	/* 
+	 * PIO mode => ATA FIFO on, ATAPI FIFO off
+	 */
+	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+	if (drive->media==ide_disk) {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
+		} else {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
+		}
+	} else {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+		} else {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+		}
+	}
+	
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	local_irq_restore(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+/**
+ *	ali15x3_can_ultra	-	check for ultra DMA support
+ *	@drive: drive to do the check
+ *
+ *	Check the drive and controller revisions. Return 0 if UDMA is
+ *	not available, or 1 if UDMA can be used. The actual rules for
+ *	the ALi are
+ *		No UDMA on revisions <= 0x20
+ *		Disk only for revisions < 0xC2
+ *		Not WDC drives for revisions < 0xC2
+ *
+ *	FIXME: WDC ifdef needs to die
+ */
+ 
+static u8 ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+	if (m5229_revision <= 0x20) {
+		return 0;
+	} else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+		    (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+		   (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ *	ali15x3_ratemask	-	generate DMA mode list
+ *	@drive: drive to compute against
+ *
+ *	Generate a list of the available DMA modes for the drive. 
+ *	FIXME: this function contains lots of bogus masking we can dump
+ *
+ *	Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
+ */
+ 
+static u8 ali15x3_ratemask (ide_drive_t *drive)
+{
+	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
+
+	if (m5229_revision >= 0xC4 && can_ultra) {
+		mode = 3;
+	} else if (m5229_revision >= 0xC2 && can_ultra) {
+		mode = 2;
+	} else if (can_ultra) {
+		return 1;
+	} else {
+		return 0;
+	}
+
+	/*
+	 *	If the drive sees no suitable cable then UDMA 33
+	 *	is the highest permitted mode
+	 */
+	 
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	ali15x3_tune_chipset	-	set up chiset for new speed
+ *	@drive: drive to configure for
+ *	@xferspeed: desired speed
+ *
+ *	Configure the hardware for the desired IDE transfer mode.
+ *	We also do the needed drive configuration through helpers
+ */
+ 
+static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 tmpbyte		= 0x00;
+	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
+
+	if (speed < XFER_UDMA_0) {
+		u8 ultra_enable	= (unit) ? 0x7f : 0xf7;
+		/*
+		 * clear "ultra enable" bit
+		 */
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= ultra_enable;
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+
+		if (speed < XFER_SW_DMA_0)
+			ali15x3_tune_drive(drive, speed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= (0x0f << ((1-unit) << 2));
+		/*
+		 * enable ultra dma and set timing
+		 */
+		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+		if (speed >= XFER_UDMA_3) {
+			pci_read_config_byte(dev, 0x4b, &tmpbyte);
+			tmpbyte |= 1;
+			pci_write_config_byte(dev, 0x4b, tmpbyte);
+		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+/**
+ *	config_chipset_for_dma	-	set up DMA mode
+ *	@drive: drive to configure for
+ *
+ *	Place a drive into DMA mode and tune the chipset for
+ *	the selected speed.
+ *
+ *	Returns true if DMA mode can be used
+ */
+ 
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) ali15x3_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	ali15x3_config_drive_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Configure a drive for DMA operation. If DMA is not possible we
+ *	drop the drive into PIO mode instead.
+ *
+ *	FIXME: exactly what are we trying to return here
+ */
+ 
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->ide_dma_off_quietly(drive);
+
+	drive->init_speed = 0;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	ali15x3_dma_write	-	do a DMA IDE write
+ *	@drive:	drive to issue write for
+ *
+ *	Returns 1 if the DMA write cannot be performed, zero on 
+ *	success.
+ */
+ 
+static int ali15x3_dma_write (ide_drive_t *drive)
+{
+	if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+		return 1;	/* try PIO instead of DMA */
+	return __ide_dma_write(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/**
+ *	init_chipset_ali15x3	-	Initialise an ALi IDE controller
+ *	@dev: PCI device
+ *	@name: Name of the controller
+ *
+ *	This function initializes the ALI IDE controller and where 
+ *	appropriate also sets up the 1533 southbridge.
+ */
+  
+static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	unsigned long flags;
+	u8 tmpbyte;
+	struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!ali_proc) {
+		ali_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&ali_procs[0]);
+	}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+	local_irq_save(flags);
+
+	if (m5229_revision < 0xC2) {
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	/*
+	 * 1543C-B?, 1535, 1535D, 1553
+	 * Note 1: not all "motherboard" support this detection
+	 * Note 2: if no udma 66 device, the detection may "error".
+	 *         but in this case, we will not set the device to
+	 *         ultra 66, the detection result is not important
+	 */
+
+	/*
+	 * enable "Cable Detection", m5229, 0x4b, bit3
+	 */
+	pci_read_config_byte(dev, 0x4b, &tmpbyte);
+	pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+	/*
+	 * We should only tune the 1533 enable if we are using an ALi
+	 * North bridge
+	 */
+	if (north->vendor != PCI_VENDOR_ID_AL) {
+		local_irq_restore(flags);
+	        return 0;
+	}
+
+	/*
+	 * set south-bridge's enable bit, m1533, 0x79
+	 */
+
+	pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+	if (m5229_revision == 0xC2) {
+		/*
+		 * 1543C-B0 (m1533, 0x79, bit 2)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+	} else if (m5229_revision >= 0xC3) {
+		/*
+		 * 1553/1535 (m1533, 0x79, bit 1)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/**
+ *	ata66_ali15x3	-	check for UDMA 66 support
+ *	@hwif: IDE interface
+ *
+ *	This checks if the controller and the cable are capable
+ *	of UDMA66 transfers. It doesn't check the drives.
+ *	But see note 2 below!
+ *
+ *	FIXME: frobs bits that are not defined on newer ALi devicea
+ */
+
+static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int ata66	= 0;
+	u8 cable_80_pin[2]	= { 0, 0 };
+
+	unsigned long flags;
+	u8 tmpbyte;
+
+	local_irq_save(flags);
+
+	if (m5229_revision >= 0xC2) {
+		/*
+		 * Ultra66 cable detection (from Host View)
+		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+		 */
+		pci_read_config_byte(dev, 0x4a, &tmpbyte);
+		/*
+		 * 0x4a, bit0 is 0 => primary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
+		/*
+		 * 0x4a, bit1 is 0 => secondary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
+		/*
+		 * Allow ata66 if cable of current channel has 80 pins
+		 */
+		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+	} else {
+		/*
+		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+		 */
+		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+	}
+
+	/*
+	 * CD_ROM DMA on (m5229, 0x53, bit0)
+	 *      Enable this bit even if we want to use PIO
+	 * PIO FIFO off (m5229, 0x53, bit1)
+	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
+	 *	(Not on later devices it seems)
+	 *
+	 *	0x53 changes meaning on later revs - we must no touch
+	 *	bit 1 on them. Need to check if 0x20 is the right break
+	 */
+	 
+	pci_read_config_byte(dev, 0x53, &tmpbyte);
+	
+	if(m5229_revision <= 0x20)
+		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+	else
+		tmpbyte |= 0x01;
+
+	pci_write_config_byte(dev, 0x53, tmpbyte);
+
+	local_irq_restore(flags);
+
+	return(ata66);
+}
+
+/**
+ *	init_hwif_common_ali15x3	-	Set up ALI IDE hardware
+ *	@hwif: IDE interface
+ *
+ *	Initialize the IDE structure side of the ALi 15x3 driver.
+ */
+ 
+static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &ali15x3_tune_drive;
+	hwif->speedproc = &ali15x3_tune_chipset;
+
+	/* Don't use LBA48 on ALi devices before rev 0xC5 */
+	hwif->addressing = (m5229_revision <= 0xC4) ? 1 : 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	if (m5229_revision > 0x20)
+		hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+        if (m5229_revision >= 0x20) {
+                /*
+                 * M1543C or newer for DMAing
+                 */
+                hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+                hwif->ide_dma_write = &ali15x3_dma_write;
+		if (!noautodma)
+			hwif->autodma = 1;
+		if (!(hwif->udma_four))
+			hwif->udma_four = ata66_ali15x3(hwif);
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+/**
+ *	init_hwif_ali15x3	-	Initialize the ALI IDE x86 stuff
+ *	@hwif: interface to configure
+ *
+ *	Obtain the IRQ tables for an ALi based IDE solution on the PC
+ *	class platforms. This part of the code isn't applicable to the
+ *	Sparc systems
+ */
+
+static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+	u8 ideic, inmir;
+	u8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+				      1, 11, 0, 12, 0, 14, 0, 15 };
+
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (isa_dev) {
+		/*
+		 * read IDE interface control
+		 */
+		pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+		/* bit0, bit1 */
+		ideic = ideic & 0x03;
+
+		/* get IRQ for IDE Controller */
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
+			/*
+			 * get SIRQ1 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x44, &inmir);
+			inmir = inmir & 0x0f;
+			hwif->irq = irq_routing_table[inmir];
+		} else if (hwif->channel && !(ideic & 0x01)) {
+			/*
+			 * get SIRQ2 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x75, &inmir);
+			inmir = inmir & 0x0f;
+			hwif->irq = irq_routing_table[inmir];
+		}
+	}
+
+	init_hwif_common_ali15x3(hwif);
+}
+
+/**
+ *	init_dma_ali15x3	-	set up DMA on ALi15x3
+ *	@hwif: IDE interface
+ *	@dmabase: DMA interface base PCI address
+ *
+ *	Set up the DMA functionality on the ALi 15x3. For the ALi
+ *	controllers this is generic so we can let the generic code do
+ *	the actual work.
+ */
+
+static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (m5229_revision < 0x20)
+		return;
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+/**
+ *	init_setup_ali15x3	-	set up an ALi15x3 IDE controller
+ *	@dev: PCI device to set up
+ *	@d: IDE PCI structures
+ *
+ *	Perform the actual set up for the ALi15x3.
+ */
+ 
+static void __init init_setup_ali15x3 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+#if defined(CONFIG_SPARC64)
+	d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	ali15x3_scan_pcidev	-	check for ali pci ide
+ *	@dev: device found by IDE ordered scan
+ *
+ *	If the device is a known ALi IDE controller we set it up and
+ *	then return 1. If we do not know it, or set up fails we return 0
+ *	and it will be offered to other drivers or taken generic
+ */
+ 
+int __init ali15x3_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_AL)
+		return 0;
+
+	for (d = ali15x3_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/alim15x3.h b/drivers/ide/pci/alim15x3.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/alim15x3.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,57 @@
+#ifndef ALI15X3_H
+#define ALI15X3_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc;
+
+static int ali_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t ali_procs[] __initdata = {
+	{
+		name:		"ali",
+		set:		1,
+		get_info:	ali_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_ALI_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_ali15x3(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_ali15x3(struct pci_dev *, const char *);
+static void init_hwif_common_ali15x3(ide_hwif_t *);
+static void init_hwif_ali15x3(ide_hwif_t *);
+static void init_dma_ali15x3(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ali15x3_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_AL,
+		device:		PCI_DEVICE_ID_AL_M5229,
+		name:		"ALI15X3",
+		init_setup:	init_setup_ali15x3,
+		init_chipset:	init_chipset_ali15x3,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_ali15x3,
+		init_dma:	init_dma_ali15x3,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* ALI15X3 */
diff -Nru a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/amd74xx.c	Sun Sep 15 19:19:45 2002
@@ -0,0 +1,417 @@
+/*
+ * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "amd74xx.h"
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8 c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"AMD %04X VIPER Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static int amd74xx_mode5_check (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+			return 1;
+		default:
+			return 0;
+	}
+}
+
+static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
+{
+	unsigned int class_rev;
+
+	if (amd74xx_mode5_check(dev))
+		return 1;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	return ((int) (class_rev >= 7) ? 1 : 0);
+}
+
+static u8 amd74xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+        switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_AMD_VIPER_7409:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_AMD_COBRA_7401:
+			return 1;
+		default:
+			return 0;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+
+	return mode;
+}
+
+/*
+ * Here is where all the hard work goes to program the chipset.
+ */
+static int amd74xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 drive_pci[]		= { 0x53, 0x52, 0x51, 0x50 };
+	u8 drive_pci2[]		= { 0x4b, 0x4a, 0x49, 0x48 };
+#if 0
+	u8 ultra_rate[]		= { 0x42, 0x41, 0x40, 0x44, 0x45, 0x46 };
+	u8 mwdma_rate[]		= { 0x77, 0x21, 0x20 };
+	u8 swdma_rate[]		= { 0xA8, 0x65, 0x42 };
+	u8 pio_rate[]		= { 0xA8, 0x65, 0x42, 0x22, 0x20};
+#endif
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(amd74xx_ratemask(drive), xferspeed);
+	u8 ultra_timing	= 0, dma_pio_timing = 0, pio_timing = 0;
+
+	pci_read_config_byte(dev, drive_pci[drive->dn], &ultra_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_pio_timing);
+	pci_read_config_byte(dev, 0x4c, &pio_timing);
+
+	ultra_timing	&= ~0xC7;
+	dma_pio_timing	&= ~0xFF;
+	pio_timing	&= ~(0x03 << drive->dn);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			ultra_timing |= 0x46;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_4:
+			ultra_timing |= 0x45;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_3:
+			ultra_timing |= 0x44;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_2:
+			ultra_timing |= 0x40;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_1:
+			ultra_timing |= 0x41;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_0:
+			ultra_timing |= 0x42;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_2:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_1:
+			dma_pio_timing |= 0x21;
+			break;
+		case XFER_MW_DMA_0:
+			dma_pio_timing |= 0x77;
+			break;
+		case XFER_SW_DMA_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_SW_DMA_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_SW_DMA_0:
+			dma_pio_timing |= 0xA8;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_PIO_3:
+			dma_pio_timing |= 0x22;
+			break;
+		case XFER_PIO_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_PIO_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_PIO_0:
+		default:
+			dma_pio_timing |= 0xA8;
+			break;
+        }
+
+	pio_timing |= (0x03 << drive->dn);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing);
+	pci_write_config_byte(dev, 0x4c, pio_timing);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void amd74xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) amd74xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, amd74xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) amd74xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int amd74xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		amd74xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_amd74xx (struct pci_dev *dev, const char *name)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!amd74xx_swdma_check(dev))
+		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!amd74xx_proc) {
+		amd74xx_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&amd74xx_procs[0]);
+	}
+#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 cable_80_pin[2]	= { 0, 0 };
+	u8 ata66		= 0;
+	u8 tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x42, &tmpbyte);
+
+	/*
+	 * 0x42, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x42, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_AMD_COBRA_7401:
+			cable_80_pin[hwif->channel] = 0;
+			return 0;
+		case PCI_DEVICE_ID_AMD_8111_IDE:
+		case PCI_DEVICE_ID_AMD_VIPER_7441:
+		case PCI_DEVICE_ID_AMD_VIPER_7411:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
+#ifdef CONFIG_AMD74XX_OVERRIDE
+	return(1);
+#else
+	return (unsigned int) ata66;
+#endif /* CONFIG_AMD74XX_OVERRIDE */
+}
+
+static void __init init_hwif_amd74xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &amd74xx_tune_drive;
+	hwif->speedproc = &amd74xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	if (amd74xx_swdma_check(hwif->pci_dev))
+		hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_amd74xx(hwif);
+	hwif->ide_dma_check = &amd74xx_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_amd74xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init amd74xx_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_AMD)
+		return 0;
+
+	for (d = amd74xx_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/amd74xx.h b/drivers/ide/pci/amd74xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/amd74xx.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,112 @@
+#ifndef AMD74XX_H
+#define AMD74XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIPER_TIMINGS
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc;
+
+static int amd74xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t amd74xx_procs[] __initdata = {
+	{
+		name:		"amd74xx",
+		set:		1,
+		get_info:	amd74xx_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_amd74xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *);
+static void init_hwif_amd74xx(ide_hwif_t *);
+static void init_dma_amd74xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t amd74xx_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_COBRA_7401,
+		name:		"AMD7401",
+		init_setup:	init_setup_amd74xx,
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7409,
+		name:		"AMD7409",
+		init_setup:	init_setup_amd74xx,
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7411,
+		name:		"AMD7411",
+		init_setup:	init_setup_amd74xx,
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_OPUS_7441,
+		name:		"AMD7441",
+		init_setup:	init_setup_amd74xx,
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_8111_IDE,
+		name:		"AMD8111",
+		init_setup:	init_setup_amd74xx,
+		init_chipset:	init_chipset_amd74xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_amd74xx,
+		init_dma:	init_dma_amd74xx,
+		autodma:	AUTODMA,
+		channels:	2,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* AMD74XX_H */
diff -Nru a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cmd640.c	Sun Sep 15 19:20:23 2002
@@ -0,0 +1,886 @@
+/*
+ *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
+ *  			mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for the advanced features and bugs
+ *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ *  These chips are basically fucked by design, and getting this driver
+ *  to work on every motherboard design that uses this screwed chip seems
+ *  bloody well impossible.  However, we're still trying.
+ *
+ *  Version 0.97 worked for everybody.
+ *
+ *  User feedback is essential.  Many thanks to the beta test team:
+ *
+ *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ *  liug@mama.indstate.edu, and others.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	Fixes for vlb initialization code, enable prefetch
+ *			for versions 'B' and 'C' of chip by default,
+ *			some code cleanup.
+ *
+ *  Version 0.03	Added reset of secondary interface,
+ *			and black list for devices which are not compatible
+ *			with prefetch mode. Separate function for setting
+ *			prefetch is added, possibly it will be called some
+ *			day from ioctl processing code.
+ *
+ *  Version 0.04	Now configs/compiles separate from ide.c
+ *
+ *  Version 0.05	Major rewrite of interface timing code.
+ *			Added new function cmd640_set_mode to set PIO mode
+ *			from ioctl call. New drives added to black list.
+ *
+ *  Version 0.06	More code cleanup. Prefetch is enabled only for
+ *			detected hard drives, not included in prefetch
+ *			black list.
+ *
+ *  Version 0.07	Changed to more conservative drive tuning policy.
+ *			Unknown drives, which report PIO < 4 are set to
+ *			(reported_PIO - 1) if it is supported, or to PIO0.
+ *			List of known drives extended by info provided by
+ *			CMD at their ftp site.
+ *
+ *  Version 0.08	Added autotune/noautotune support.
+ *
+ *  Version 0.09	Try to be smarter about 2nd port enabling.
+ *  Version 0.10	Be nice and don't reset 2nd port.
+ *  Version 0.11	Try to handle more weird situations.
+ *
+ *  Version 0.12	Lots of bug fixes from Laszlo Peter
+ *			irq unmasking disabled for reliability.
+ *			try to be even smarter about the second port.
+ *			tidy up source code formatting.
+ *  Version 0.13	permit irq unmasking again.
+ *  Version 0.90	massive code cleanup, some bugs fixed.
+ *			defaults all drives to PIO mode0, prefetch off.
+ *			autotune is OFF by default, with compile time flag.
+ *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ *			 (requires hdparm-3.1 or newer)
+ *  Version 0.91	first release to linux-kernel list.
+ *  Version 0.92	move initial reg dump to separate callable function
+ *			change "readahead" to "prefetch" to avoid confusion
+ *  Version 0.95	respect original BIOS timings unless autotuning.
+ *			tons of code cleanup and rearrangement.
+ *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ *			prevent use of unmask when prefetch is on
+ *  Version 0.96	prevent use of io_32bit when prefetch is off
+ *  Version 0.97	fix VLB secondary interface for sjd@slip.net
+ *			other minor tune-ups:  0.96 was very good.
+ *  Version 0.98	ignore PCI version when disabled by BIOS
+ *  Version 0.99	display setup/active/recovery clocks with PIO mode
+ *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
+ *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
+ *			 ("fast" is necessary for 32bit I/O in some systems)
+ *  Version 1.02	fix bug that resulted in slow "setup times"
+ *			 (patch courtesy of Zoltan Hidvegi)
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+#define CMD640_PREFETCH_MASKS 1
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+/*
+ * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
+ */
+int cmd640_vlb = 0;
+
+/*
+ * CMD640 specific registers definition.
+ */
+
+#define VID		0x00
+#define DID		0x02
+#define PCMD		0x04
+#define   PCMD_ENA	0x01
+#define PSTTS		0x06
+#define REVID		0x08
+#define PROGIF		0x09
+#define SUBCL		0x0a
+#define BASCL		0x0b
+#define BaseA0		0x10
+#define BaseA1		0x14
+#define BaseA2		0x18
+#define BaseA3		0x1c
+#define INTLINE		0x3c
+#define INPINE		0x3d
+
+#define	CFR		0x50
+#define   CFR_DEVREV		0x03
+#define   CFR_IDE01INTR		0x04
+#define	  CFR_DEVID		0x18
+#define	  CFR_AT_VESA_078h	0x20
+#define	  CFR_DSA1		0x40
+#define	  CFR_DSA0		0x80
+
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define DRWTIM23	0x58
+#define BRST		0x59
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*put_cmd640_reg)(u16 reg, u8 val);
+static u8 (*get_cmd640_reg)(u16 reg);
+
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
+
+/*
+ * The CMD640x chip does not support DWORD config write cycles, but some
+ * of the BIOSes use them to implement the config services.
+ * Therefore, we must use direct IO instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci1 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	b = inb_p((reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	outb_p(val, cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci2 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	b = inb_p(cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_vlb (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	b = inb_p(cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+static int __init match_pci_cmd640_device (void)
+{
+	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	unsigned int i;
+	for (i = 0; i < 4; i++) {
+		if (get_cmd640_reg(i) != ven_dev[i])
+			return 0;
+	}
+#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
+	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
+		printk("ide: cmd640 on PCI disabled by BIOS\n");
+		return 0;
+	}
+#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
+	return 1; /* success */
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+static int __init probe_for_cmd640_pci1 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci1;
+	put_cmd640_reg = put_cmd640_reg_pci1;
+	for (cmd640_key = 0x80000000;
+	     cmd640_key <= 0x8000f800;
+	     cmd640_key += 0x800) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+static int __init probe_for_cmd640_pci2 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci2;
+	put_cmd640_reg = put_cmd640_reg_pci2;
+	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+static int __init probe_for_cmd640_vlb (void)
+{
+	u8 b;
+
+	get_cmd640_reg = get_cmd640_reg_vlb;
+	put_cmd640_reg = put_cmd640_reg_vlb;
+	cmd640_key = 0x178;
+	b = get_cmd640_reg(CFR);
+	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+		cmd640_key = 0x78;
+		b = get_cmd640_reg(CFR);
+		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
+			return 0;
+	}
+	return 1; /* success */
+}
+
+/*
+ *  Returns 1 if an IDE interface/drive exists at 0x170,
+ *  Returns 0 otherwise.
+ */
+static int __init secondary_port_responding (void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
+	udelay(100);
+	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+		udelay(100);
+		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 0; /* nothing responded */
+		}
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 1; /* success */
+}
+
+#ifdef CMD640_DUMP_REGS
+/*
+ * Dump out all cmd640 registers.  May be called from ide.c
+ */
+static void cmd640_dump_regs (void)
+{
+	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
+
+	/* Dump current state of chip registers */
+	printk("ide: cmd640 internal register dump:");
+	for (; reg <= 0x59; reg++) {
+		if (!(reg & 0x0f))
+			printk("\n%04x:", reg);
+		printk(" %02x", get_cmd640_reg(reg));
+	}
+	printk("\n");
+}
+#endif
+
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch (unsigned int index)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+	if (b & prefetch_masks[index]) {	/* is prefetch off? */
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+	} else {
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+	}
+}
+
+/*
+ * Figure out which devices we control
+ */
+static void __init setup_device_ptrs (void)
+{
+	unsigned int i;
+
+	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		ide_hwif_t *hwif = &ide_hwifs[i];
+		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
+			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
+				cmd_hwif0 = hwif;
+			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+				cmd_hwif1 = hwif;
+		}
+	}
+	cmd_drives[0] = &cmd_hwif0->drives[0];
+	cmd_drives[1] = &cmd_hwif0->drives[1];
+	cmd_drives[2] = &cmd_hwif1->drives[0];
+	cmd_drives[3] = &cmd_hwif1->drives[1];
+}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode (unsigned int index, int mode)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	int reg = prefetch_regs[index];
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	b = get_cmd640_reg(reg);
+	if (mode) {	/* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+		b &= ~prefetch_masks[index];	/* enable prefetch */
+	} else {
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+		b |= prefetch_masks[index];	/* disable prefetch */
+	}
+	put_cmd640_reg(reg, b);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Dump out current drive clocks settings
+ */
+static void display_clocks (unsigned int index)
+{
+	u8 active_count, recovery_count;
+
+	active_count = active_counts[index];
+	if (active_count == 1)
+		++active_count;
+	recovery_count = recovery_counts[index];
+	if (active_count > 3 && recovery_count == 1)
+		++recovery_count;
+	if (cmd640_chip_version > 1)
+		recovery_count += 1;  /* cmd640b uses (count + 1)*/
+	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
+inline static u8 pack_nibbles (u8 upper, u8 lower)
+{
+	return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine retrieves the initial drive timings from the chipset.
+ */
+static void __init retrieve_drive_counts (unsigned int index)
+{
+	u8 b;
+
+	/*
+	 * Get the internal setup timing, and convert to clock count
+	 */
+	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+	switch (b) {
+		case 0x00: b = 4; break;
+		case 0x80: b = 3; break;
+		case 0x40: b = 2; break;
+		default:   b = 5; break;
+	}
+	setup_counts[index] = b;
+
+	/*
+	 * Get the active/recovery counts
+	 */
+	b = get_cmd640_reg(drwtim_regs[index]);
+	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
+	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
+}
+
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
+ */
+static void program_drive_counts (unsigned int index)
+{
+	unsigned long flags;
+	u8 setup_count    = setup_counts[index];
+	u8 active_count   = active_counts[index];
+	u8 recovery_count = recovery_counts[index];
+
+	/*
+	 * Set up address setup count and drive read/write timing registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * so we merge the timings, using the slowest value for each timing.
+	 */
+	if (index > 1) {
+		unsigned int mate;
+		if (cmd_drives[mate = index ^ 1]->present) {
+			if (setup_count < setup_counts[mate])
+				setup_count = setup_counts[mate];
+			if (active_count < active_counts[mate])
+				active_count = active_counts[mate];
+			if (recovery_count < recovery_counts[mate])
+				recovery_count = recovery_counts[mate];
+		}
+	}
+
+	/*
+	 * Convert setup_count to internal chipset representation
+	 */
+	switch (setup_count) {
+		case 4:	 setup_count = 0x00; break;
+		case 3:	 setup_count = 0x80; break;
+		case 1:
+		case 2:	 setup_count = 0x40; break;
+		default: setup_count = 0xc0; /* case 5 */
+	}
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 * (this converts counts of 16 into counts of zero -- okay).
+	 */
+	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
+	put_cmd640_reg(arttim_regs[index], setup_count);
+	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+{
+	int setup_time, active_time, recovery_time, clock_time;
+	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = system_bus_clock();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+	if (active_count < 2)
+		active_count = 2; /* minimum allowed by cmd640 */
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count < 2)
+		recovery_count = 2; /* minimum allowed by cmd640 */
+	if (recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd640 */
+	if (cmd640_chip_version > 1)
+		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
+	if (recovery_count > 16)
+		recovery_count = 16; /* maximum allowed by cmd640 */
+
+	setup_counts[index]    = setup_count;
+	active_counts[index]   = active_count;
+	recovery_counts[index] = recovery_count;
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (index);
+}
+
+/*
+ * Drive PIO mode selection:
+ */
+static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+{
+	u8 b;
+	ide_pio_data_t  d;
+	unsigned int index = 0;
+
+	while (drive != cmd_drives[index]) {
+		if (++index > 3) {
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
+		}
+	}
+	switch (mode_wanted) {
+		case 6: /* set fast-devsel off */
+		case 7: /* set fast-devsel on */
+			mode_wanted &= 1;
+			b = get_cmd640_reg(CNTRL) & ~0x27;
+			if (mode_wanted)
+				b |= 0x27;
+			put_cmd640_reg(CNTRL, b);
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			set_prefetch_mode(index, mode_wanted);
+			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+
+	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "");
+	display_clocks(index);
+	return;
+}
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static int pci_conf1(void)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x01, 0xCFB);
+	tmp = inl(0xCF8);
+	outl(0x80000000, 0xCF8);
+	if (inl(0xCF8) == 0x80000000) {
+		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	outl(tmp, 0xCF8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+static int pci_conf2(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x00, 0xCFB);
+	outb(0x00, 0xCF8);
+	outb(0x00, 0xCFA);
+	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ */
+int __init ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	int second_port_cmd640 = 0;
+	const char *bus_type, *port2;
+	unsigned int index;
+	u8 b, cfr;
+
+	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+		bus_type = "VLB";
+	} else {
+		cmd640_vlb = 0;
+		/* Find out what kind of PCI probing is supported otherwise
+		   Justin Gibbs will sulk.. */
+		if (pci_conf1() && probe_for_cmd640_pci1())
+			bus_type = "PCI (type1)";
+		else if (pci_conf2() && probe_for_cmd640_pci2())
+			bus_type = "PCI (type2)";
+		else
+			return 0;
+	}
+	/*
+	 * Undocumented magic (there is no 0x5b reg in specs)
+	 */
+	put_cmd640_reg(0x5b, 0xbd);
+	if (get_cmd640_reg(0x5b) != 0xbd) {
+		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		return 0;
+	}
+	put_cmd640_reg(0x5b, 0);
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+
+	/*
+	 * Documented magic begins here
+	 */
+	cfr = get_cmd640_reg(CFR);
+	cmd640_chip_version = cfr & CFR_DEVREV;
+	if (cmd640_chip_version == 0) {
+		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+		return 0;
+	}
+
+	/*
+	 * Initialize data for primary port
+	 */
+	setup_device_ptrs ();
+	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+	cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+	/*
+	 * Ensure compatibility by always using the slowest timings
+	 * for access to the drive's command register block,
+	 * and reset the prefetch burstsize to default (512 bytes).
+	 *
+	 * Maybe we need a way to NOT do these on *some* systems?
+	 */
+	put_cmd640_reg(CMDTIM, 0);
+	put_cmd640_reg(BRST, 0x40);
+
+	/*
+	 * Try to enable the secondary interface, if not already enabled
+	 */
+	if (cmd_hwif1->noprobe) {
+		port2 = "not probed";
+	} else {
+		b = get_cmd640_reg(CNTRL);
+		if (secondary_port_responding()) {
+			if ((b & CNTRL_ENA_2ND)) {
+				second_port_cmd640 = 1;
+				port2 = "okay";
+			} else if (cmd640_vlb) {
+				second_port_cmd640 = 1;
+				port2 = "alive";
+			} else
+				port2 = "not cmd640";
+		} else {
+			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+			if (secondary_port_responding()) {
+				second_port_cmd640 = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+				second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+				port2 = "enabled";
+			} else {
+				put_cmd640_reg(CNTRL, b); /* restore original setting */
+				port2 = "not responding";
+			}
+		}
+	}
+
+	/*
+	 * Initialize data for secondary cmd640 port, if enabled
+	 */
+	if (second_port_cmd640) {
+		cmd_hwif0->serialized = 1;
+		cmd_hwif1->serialized = 1;
+		cmd_hwif1->chipset = ide_cmd640;
+		cmd_hwif0->mate = cmd_hwif1;
+		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+		cmd_hwif0->serialized ? "" : "not ", port2);
+
+	/*
+	 * Establish initial timings/prefetch for all drives.
+	 * Do not unnecessarily disturb any prior BIOS setup of these.
+	 */
+	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+		ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		if (drive->autotune || ((index > 1) && second_port_toggled)) {
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
+			 * This way, the drive identify code has a better chance.
+			 */
+			setup_counts    [index] = 4;	/* max possible */
+			active_counts   [index] = 16;	/* max possible */
+			recovery_counts [index] = 16;	/* max possible */
+			program_drive_counts (index);
+			set_prefetch_mode (index, 0);
+			printk("cmd640: drive%d timings/prefetch cleared\n", index);
+		} else {
+			/*
+			 * Record timings/prefetch without changing them.
+			 * This preserves any prior BIOS setup.
+			 */
+			retrieve_drive_counts (index);
+			check_prefetch (index);
+			printk("cmd640: drive%d timings/prefetch(%s) preserved",
+				index, drive->no_io_32bit ? "off" : "on");
+			display_clocks(index);
+		}
+#else
+		/*
+		 * Set the drive unmask flags to match the prefetch setting
+		 */
+		check_prefetch (index);
+		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+	return 1;
+}
+
diff -Nru a/drivers/ide/pci/cmd640.h b/drivers/ide/pci/cmd640.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cmd640.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,32 @@
+#ifndef CMD640_H
+#define CMD640_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define IDE_IGNORE      ((void *)-1)
+
+static ide_pci_device_t cmd640_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_640,
+		name:		"CMD640",
+		init_setup:	NULL,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	IDE_IGNORE,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		bootable:	EOL,
+	}
+}
+
+#endif /* CMD640_H */
diff -Nru a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cmd64x.c	Sun Sep 15 19:20:23 2002
@@ -0,0 +1,798 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ *           Note, this driver is not used at all on other systems because
+ *           there the "BIOS" has done all of the following already.
+ *           Due to massive hardware bugs, UltraDMA is only supported
+ *           on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998		David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cmd64x.h"
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS		5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+#undef DEBUG_CMD_REGS
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
+	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
+	u8 reg72 = 0, reg73 = 0;			/* primary */
+	u8 reg7a = 0, reg7b = 0;			/* secondary */
+	u8 reg50 = 0, reg71 = 0;			/* extra */
+#ifdef DEBUG_CMD_REGS
+	u8 hi_byte = 0, lo_byte = 0;
+#endif /* DEBUG_CMD_REGS */
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	(void) pci_read_config_byte(dev, CFR,       &reg50);
+	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
+	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
+	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
+	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
+	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
+	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
+	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled           "
+			"              %sabled\n",
+		(reg72&0x80)?"dis":" en",
+		(reg7a&0x80)?"dis":" en");
+	p += sprintf(p, "--------------- drive0 "
+		"--------- drive1 -------- drive0 "
+		"---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s"
+			"             %s               %s\n",
+		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+		(reg72&0x20)?(
+			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+		(reg72&0x40)?(
+			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+			"X"):"?");
+	p += sprintf(p, "         %s(%s)           %s(%s)\n",
+		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x20)?(
+			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x40)?(
+			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+			"X"):"?" );
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	p += sprintf(p, "                %s                     %s\n",
+		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
+		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+#ifdef DEBUG_CMD_REGS
+	SPLIT_BYTE(reg50, hi_byte, lo_byte);
+	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
+	SPLIT_BYTE(reg57, hi_byte, lo_byte);
+	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+	SPLIT_BYTE(reg71, hi_byte, lo_byte);
+	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
+#endif /* DEBUG_CMD_REGS */
+
+	return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_cmd_devs; i++) {
+		struct pci_dev *dev	= cmd_devs[i];
+		p = print_cmd64x_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+	unsigned long flags;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	ide_drive_t *drives = HWIF(drive)->drives;
+	u8 temp_b;
+	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 recovery_counts[] =
+		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+	static const u8 arttim_regs[2][2] = {
+			{ ARTTIM0, ARTTIM1 },
+			{ ARTTIM23, ARTTIM23 }
+		};
+	static const u8 drwtim_regs[2][2] = {
+			{ DRWTIM0, DRWTIM1 },
+			{ DRWTIM2, DRWTIM3 }
+		};
+	int channel = (int) HWIF(drive)->channel;
+	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
+
+	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
+		setup_count, active_count, recovery_count, drive->present);
+	/*
+	 * Set up address setup count registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * for address setup so we merge these timings, using the slowest
+	 * value.
+	 */
+	if (channel) {
+		drive->drive_data = setup_count;
+		setup_count = IDE_MAX(drives[0].drive_data,
+					drives[1].drive_data);
+		cmdprintk("Secondary interface, setup_count = %d\n",
+					setup_count);
+	}
+
+	/*
+	 * Convert values to internal chipset representation
+	 */
+	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+	active_count &= 0xf; /* Remember, max value is 16 */
+	recovery_count = (int) recovery_counts[recovery_count];
+
+	cmdprintk("Final values = %d,%d,%d\n",
+		setup_count, active_count, recovery_count);
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	local_irq_save(flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 */
+	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+		((u8) setup_count) | (temp_b & 0x3f));
+	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+		(u8) ((active_count << 4) | recovery_count));
+	cmdprintk ("Write %x to %x\n",
+		((u8) setup_count) | (temp_b & 0x3f),
+		arttim_regs[channel][slave]);
+	cmdprintk ("Write %x to %x\n",
+		(u8) ((active_count << 4) | recovery_count),
+		drwtim_regs[channel][slave]);
+	local_irq_restore(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is 
+ * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+
+static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+{
+	int setup_time, active_time, recovery_time;
+	int clock_time, pio_mode, cycle_time;
+	u8 recovery_count2, cycle_count;
+	int setup_count, active_count, recovery_count;
+	int bus_speed = system_bus_clock();
+	/*byte b;*/
+	ide_pio_data_t  d;
+
+	switch (mode_wanted) {
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			/*set_prefetch_mode(index, mode_wanted);*/
+			cmdprintk("%s: %sabled cmd640 prefetch\n",
+				drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	pio_mode = d.pio_mode;
+	cycle_time = d.cycle_time;
+
+	/*
+	 * I copied all this complicated stuff from cmd640.c and made a few
+	 * minor changes.  For now I am just going to pray that it is correct.
+	 */
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd646 */
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it
+	 *		(proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (drive, setup_count, active_count, recovery_count);
+
+	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+		"clocks=%d/%d/%d\n",
+		drive->name, pio_mode, mode_wanted, cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "",
+		setup_count, active_count, recovery_count);
+}
+
+static u8 cmd64x_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode = 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_649:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_CMD_648:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_CMD_643:
+			return 0;
+
+		case PCI_DEVICE_ID_CMD_646:
+		{
+			unsigned int class_rev	= 0;
+			pci_read_config_dword(dev,
+				PCI_CLASS_REVISION, &class_rev);
+			class_rev &= 0xff;
+		/*
+		 * UltraDMA only supported on PCI646U and PCI646U2, which
+		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+		 * Actually, although the CMD tech support people won't
+		 * tell me the details, the 0x03 revision cannot support
+		 * UDMA correctly without hardware modifications, and even
+		 * then it only works with Quantum disks due to some
+		 * hold time assumptions in the 646U part which are fixed
+		 * in the 646U2.
+		 *
+		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+		 */
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					return 1;
+				case 0x03:
+				case 0x01:
+				default:
+					return 0;
+			}
+		}
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	u8 speed	= 0x00;
+	u8 set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	cmd64x_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	config_cmd64x_chipset_for_pio(drive, set_speed);
+}
+
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 regU = 0, pciU	= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+	u8 regD = 0, pciD	= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	u8 speed	= ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed > XFER_PIO_4) {
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+		regD &= ~(unit ? 0x40 : 0x20);
+		regU &= ~(unit ? 0xCA : 0x35);
+		(void) pci_write_config_byte(dev, pciD, regD);
+		(void) pci_write_config_byte(dev, pciU, regU);
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
+		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
+		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
+		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
+		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
+		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
+		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
+
+		default:
+			return 1;
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed > XFER_PIO_4) {
+		(void) pci_write_config_byte(dev, pciU, regU);
+		regD |= (unit ? 0x40 : 0x20);
+		(void) pci_write_config_byte(dev, pciD, regD);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, cmd64x_ratemask(drive));
+
+	config_chipset_for_pio(drive, (!(speed)));
+
+	if ((!(speed)))
+		return 0;
+
+	if (HWIF(drive)->speedproc(drive, speed))
+		return 0;
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+
+static int cmd64x_ide_dma_end (ide_drive_t *drive)
+{
+	u8 dma_stat = 0, dma_cmd = 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	drive->waiting_for_dma = 0;
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	if (cmd64x_alt_dma_status(dev)) {
+		u8 dma_intr	= 0;
+		u8 dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 :
+						    CFR_INTR_CH0;
+		u8 dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
+		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+		/* clear the INTR bit */
+		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+	}
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+	struct pci_dev *dev		= hwif->pci_dev;
+        u8 dma_alt_stat = 0, mask	= (hwif->channel) ? MRDMODE_INTR_CH1 :
+							    MRDMODE_INTR_CH0;
+	u8 dma_stat = hwif->INB(hwif->dma_status);
+
+	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+#ifdef DEBUG
+	printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+		"0x%02x mask: 0x%02x\n", drive->name,
+		dma_stat, dma_alt_stat, mask);
+#endif
+	if (!(dma_alt_stat & mask))
+		return 0;
+
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev = 0;
+	u8 mrdmode = 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+#ifdef __i386__
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+#endif
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+			break;
+		case PCI_DEVICE_ID_CMD_646:
+			printk("%s: chipset revision 0x%02X, ", name, class_rev);
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					printk("UltraDMA Capable");
+					break;
+				case 0x03:
+					printk("MultiWord DMA Force Limited");
+					break;
+				case 0x01:
+				default:
+					printk("MultiWord DMA Limited, IRQ workaround enabled");
+					break;
+				}
+			printk("\n");
+                        break;
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			break;
+		default:
+			break;
+	}
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+
+	/* Setup interrupts. */
+	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
+	mrdmode &= ~(0x30);
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
+
+	/* Use MEMORY READ LINE for reads.
+	 * NOTE: Although not mentioned in the PCI0646U specs,
+	 *       these bits are write only and won't be read
+	 *       back as set or not.  The PCI0646U2 specs clarify
+	 *       this point.
+	 */
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+
+	/* Set reasonable active/recovery/address-setup values. */
+	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
+	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
+#ifdef __i386__
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
+	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
+#ifdef CONFIG_PPC
+	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+
+	cmd_devs[n_cmd_devs++] = dev;
+
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		ide_pci_register_host_proc(&cmd64x_procs[0]);
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+		case PCI_DEVICE_ID_CMD_646:
+			return ata66;
+		default:
+			break;
+	}
+	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
+	return (ata66 & mask) ? 1 : 0;
+}
+
+static void __init init_hwif_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int class_rev;
+
+	hwif->autodma = 0;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->tuneproc  = &cmd64x_tuneproc;
+	hwif->speedproc = &cmd64x_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (dev->device == PCI_DEVICE_ID_CMD_643)
+		hwif->ultra_mask = 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_646)
+		if (class_rev > 0x04)
+			hwif->ultra_mask = 0x07;
+		else
+			hwif->ultra_mask = 0x80;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_cmd64x(hwif);
+
+	if (dev->device == PCI_DEVICE_ID_CMD_646) {
+		hwif->chipset = ide_cmd646;
+		if (class_rev == 0x01) {
+			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
+		} else {
+			hwif->ide_dma_end = &cmd64x_ide_dma_end;
+			hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+		}
+	} else {
+		hwif->ide_dma_end = &cmd64x_ide_dma_end;
+		hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+	}
+
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+/**
+ *	FIXME: not required ?
+ */
+ 
+static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	FIXME: not required either ?
+ */
+ 
+static void __init init_setup_cmd64x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init cmd64x_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_CMD)
+		return 0;
+
+	for (d = cmd64x_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/cmd64x.h b/drivers/ide/pci/cmd64x.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cmd64x.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,152 @@
+#ifndef CMD64X_H
+#define CMD64X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...)	printk(x)
+#else
+#define cmdprintk(x...)
+#endif
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+/*
+ * CMD64x specific registers definition.
+ */
+#define CFR		0x50
+#define   CFR_INTR_CH0		0x02
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define   ARTTIM23_INTR_CH1	0x10
+#define ARTTIM2		0x57
+#define ARTTIM3		0x57
+#define DRWTIM23	0x58
+#define DRWTIM2		0x58
+#define BRST		0x59
+#define DRWTIM3		0x5b
+
+#define BMIDECR0	0x70
+#define MRDMODE		0x71
+#define   MRDMODE_INTR_CH0	0x04
+#define   MRDMODE_INTR_CH1	0x08
+#define   MRDMODE_BLK_CH0	0x10
+#define   MRDMODE_BLK_CH1	0x20
+#define BMIDESR0	0x72
+#define UDIDETCR0	0x73
+#define DTPR0		0x74
+#define BMIDECR1	0x78
+#define BMIDECSR	0x79
+#define BMIDESR1	0x7A
+#define UDIDETCR1	0x7B
+#define DTPR1		0x7C
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc;
+
+static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
+static int cmd64x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cmd64x_procs[] __initdata = {
+	{
+		name:		"cmd64x",
+		set:		1,
+		get_info:	cmd64x_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_cmd64x(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_cmd64x(struct pci_dev *, const char *);
+static void init_hwif_cmd64x(ide_hwif_t *);
+static void init_dma_cmd64x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cmd64x_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_643,
+		name:		"CMD643",
+		init_setup:	init_setup_cmd64x,
+		init_chipset:	init_chipset_cmd64x,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cmd64x,
+		init_dma:	init_dma_cmd64x,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_646,
+		name:		"CMD646",
+		init_setup:	init_setup_cmd64x,
+		init_chipset:	init_chipset_cmd64x,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cmd64x,
+		init_dma:	init_dma_cmd64x,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:	PCI_DEVICE_ID_CMD_648,
+		name:		"CMD648",
+		init_setup:	init_setup_cmd64x,
+		init_chipset:	init_chipset_cmd64x,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cmd64x,
+		init_dma:	init_dma_cmd64x,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_649,
+		name:		"CMD649",
+		init_setup:	init_setup_cmd64x,
+		init_chipset:	init_chipset_cmd64x,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cmd64x,
+		init_dma:	init_dma_cmd64x,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	2,
+		bootable:	EOL,
+	}
+};
+
+#endif /* CMD64X_H */
diff -Nru a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cs5530.c	Sun Sep 15 19:19:30 2002
@@ -0,0 +1,462 @@
+/*
+ * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
+ *
+ * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
+ * Ditto of GNU General Public License.
+ *
+ * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "cs5530.h"
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p((u16)bibma + 0x02);
+	c1 = inb_p((u16)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"Cyrix 5530 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	cs5530_xfer_set_mode	-	set a new transfer mode at the drive
+ *	@drive: drive to tune
+ *	@mode: new mode
+ *
+ *	Logging wrapper to the IDE driver speed configuration. This can
+ *	probably go away now.
+ */
+ 
+static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
+{
+	printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
+		drive->name, ide_xfer_verbose(mode));
+	return (ide_config_drive_speed(drive, mode));
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static unsigned int cs5530_pio_timings[2][5] = {
+	{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+	{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+};
+
+/*
+ * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
+ */
+#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+
+/**
+ *	cs5530_tuneproc		-	select/set PIO modes
+ *
+ *	cs5530_tuneproc() handles selection/setting of PIO modes
+ *	for both the chipset and drive.
+ *
+ *	The ide_init_cs5530() routine guarantees that all drives
+ *	will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format, basereg = CS5530_BASEREG(hwif);
+	static u8	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+		format = (hwif->INL(basereg+4) >> 31) & 1;
+		hwif->OUTL(cs5530_pio_timings[format][pio],
+			basereg+(drive->select.b.unit<<3));
+	}
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+/**
+ *	cs5530_config_dma	-	select/set DMA and UDMA modes
+ *	@drive: drive to tune
+ *
+ *	cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ *	for both the chipset and drive. The CS5530 has limitations about
+ *	mixing DMA/UDMA on the same cable.
+ */
+ 
+static int cs5530_config_dma (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+	unsigned int		basereg, reg, timings;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);
+	/* turn off DMA while we fiddle */
+	hwif->ide_dma_host_off(drive);
+	/* clear DMA_capable bit */
+
+	/*
+	 * The CS5530 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 *
+	 * Note: This relies on the fact we never fail from UDMA to MWDMA_2
+	 * but instead drop to PIO
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if (mateid && (mateid->capability & 1) &&
+		    !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) &&
+			    (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) &&
+				 (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if (id && (id->capability & 1) && drive->autodma &&
+	    !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || cs5530_set_xfer_mode(drive, mode))
+		return 1;	/* failure */
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 */
+	switch (mode) {
+		case XFER_UDMA_0:	timings = 0x00921250; break;
+		case XFER_UDMA_1:	timings = 0x00911140; break;
+		case XFER_UDMA_2:	timings = 0x00911030; break;
+		case XFER_MW_DMA_0:	timings = 0x00077771; break;
+		case XFER_MW_DMA_1:	timings = 0x00012121; break;
+		case XFER_MW_DMA_2:	timings = 0x00002020; break;
+		default:
+			printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
+				drive->name, mode);
+			return 1;	/* failure */
+	}
+	basereg = CS5530_BASEREG(hwif);
+	reg = hwif->INL(basereg+4);		/* get drive0 config register */
+	timings |= reg & 0x80000000;		/* preserve PIO format bit */
+	if (unit == 0) {			/* are we configuring drive0? */
+		hwif->OUTL(timings, basereg+4);	/* write drive0 config register */
+	} else {
+		if (timings & 0x00100000)
+			reg |=  0x00100000;	/* enable UDMA timings for both drives */
+		else
+			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
+		hwif->OUTL(reg,     basereg+4);	/* write drive0 config register */
+		hwif->OUTL(timings, basereg+12);	/* write drive1 config register */
+	}
+	(void) hwif->ide_dma_host_on(drive);
+	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/**
+ *	init_chipset_5530	-	set up 5530 bridge
+ *	@dev: PCI device
+ *	@name: device name
+ *
+ *	Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+	unsigned long flags;
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cs5530_proc) {
+		cs5530_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&cs5530_procs[0]);
+	}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+	pci_for_each_dev (dev) {
+		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
+			switch (dev->device) {
+				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+					master_0 = dev;
+					break;
+				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+					cs5530_0 = dev;
+					break;
+			}
+		}
+	}
+	if (!master_0) {
+		printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+		return 0;
+	}
+	if (!cs5530_0) {
+		printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&ide_lock, flags);
+		/* all CPUs (there should only be one CPU with this chipset) */
+
+	/*
+	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
+	 */
+
+	pci_set_master(cs5530_0);
+	pci_set_mwi(cs5530_0);
+
+	/*
+	 * Set PCI CacheLineSize to 16-bytes:
+	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+	 */
+
+	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+	/*
+	 * Disable trapping of UDMA register accesses (Win98 hack):
+	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+	 */
+
+	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+	/*
+	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+	 * The other settings are what is necessary to get the register
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x40, 0x1e);
+
+	/* 
+	 * Set max PCI burst size (16-bytes seems to work best):
+	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
+	 *	all others: clear bit-1 at 0x41, and do:
+	 *	  128bytes: OR 0x00 at 0x41
+	 *	  256bytes: OR 0x04 at 0x41
+	 *	  512bytes: OR 0x08 at 0x41
+	 *	 1024bytes: OR 0x0c at 0x41
+	 */
+
+	pci_write_config_byte(master_0, 0x41, 0x14);
+
+	/*
+	 * These settings are necessary to get the chip
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x42, 0x00);
+	pci_write_config_byte(master_0, 0x43, 0xc1);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return 0;
+}
+
+/**
+ *	init_hwif_cs5530	-	initialise an IDE channel
+ *	@hwif: IDE to initialize
+ *
+ *	This gets invoked by the IDE driver once for each channel. It
+ *	performs channel-specific pre-initialization before drive probing.
+ */
+
+static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+	unsigned int basereg, d0_timings;
+	hwif->autodma = 0;
+
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+
+	hwif->tuneproc = &cs5530_tuneproc;
+	basereg = CS5530_BASEREG(hwif);
+	d0_timings = hwif->INL(basereg+0);
+	if (CS5530_BAD_PIO(d0_timings)) {
+		/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+		if (!hwif->drives[0].autotune)
+			hwif->drives[0].autotune = 1;
+			/* needs autotuning later */
+	}
+	if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
+	/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+		if (!hwif->drives[1].autotune)
+			hwif->drives[1].autotune = 1;
+			/* needs autotuning later */
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &cs5530_config_dma;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+/**
+ *	init_dma_cs5530		-	set up for DMA
+ *	@hwif: interface
+ *	@dmabase: DMA base address
+ *
+ *	FIXME: this can go away
+ */
+ 
+static void __init init_dma_cs5530 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	init_setup_cs5530	-	set up a CS5530 IDE
+ *	@dev: PCI device
+ *	@d: PCI ide device info
+ *
+ *	FIXME: this function can go away too
+ */
+ 
+static void __init init_setup_cs5530 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	cs5530_scan_pcidev	-	set up any CS5530 device
+ *	@dev:	pci device to check
+ *
+ *	Check if the device is a 5530 IDE controller. If it is then 
+ *	claim and set up the interface.  Return 1 if we claimed the
+ *	interface or zero if it is not ours
+ */
+ 
+int __init cs5530_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_CYRIX)
+		return 0;
+
+	for (d = cs5530_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/cs5530.h b/drivers/ide/pci/cs5530.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cs5530.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,56 @@
+#ifndef CS5530_H
+#define CS5530_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc;
+
+static int cs5530_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cs5530_procs[] __initdata = {
+	{
+		name:		"cs5530",
+		set:		1,
+		get_info:	cs5530_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_cs5530(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_cs5530(struct pci_dev *, const char *);
+static void init_hwif_cs5530(ide_hwif_t *);
+static void init_dma_cs5530(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cs5530_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_CYRIX,
+		device:		PCI_DEVICE_ID_CYRIX_5530_IDE,
+		name:		"CS5530",
+		init_setup:	init_setup_cs5530,
+		init_chipset:	init_chipset_cs5530,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cs5530,
+		init_dma:	init_dma_cs5530,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* CS5530_H */
diff -Nru a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cy82c693.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,446 @@
+/*
+ * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
+ *
+ *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrater
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writting the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support. 
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ *   a large and fast disk - the results look great, so I'd say the
+ *   driver is working fine :-)
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
+ *   for optimizations and bug fixing, so feel free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ *   (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ *   problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ *
+ * History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ *                       removed DMA clock speed setting by default
+ *                       added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ *                       added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
+ *                       on some drives.
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cy82c693.h"
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk (int time, int bus_speed)
+{
+	int clocks;
+
+	clocks = (time*bus_speed+999)/1000 -1;
+
+	if (clocks < 0)
+		clocks = 0;
+
+	if (clocks > 0x0F)
+		clocks = 0x0F;
+
+	return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ *       for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */ 
+static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+{
+	int clk1, clk2;
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
+
+	/* we don't check against CY82C693's min and max speed,
+	 * so you can play with the idebus=xx parameter
+	 */
+
+	if (pio > CY82C693_MAX_PIO)
+		pio = CY82C693_MAX_PIO;
+
+	/* let's calc the address setup time clocks */
+	p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+	/* let's calc the active and recovery time clocks */
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+	/* calc recovery timing */
+	clk2 =	ide_pio_timings[pio].cycle_time -
+		ide_pio_timings[pio].active_time -
+		ide_pio_timings[pio].setup_time;
+
+	clk2 = calc_clk(clk2, bus_speed);
+
+	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
+
+	/* note: we use the same values for 16bit IOR and IOW
+         *	those are all the same, since I don't have other
+	 *	timings than those from ide_modes.h
+	 */
+
+	p_pclk->time_16r = (u8)clk1;
+	p_pclk->time_16w = (u8)clk1;
+
+	/* what are good values for 8bit ?? */
+	p_pclk->time_8 = (u8)clk1;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+	u8 index = 0, data = 0;
+
+	if (mode>2)	/* make sure we set a valid mode */
+		mode = 2;
+			   
+	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+		mode = drive->id->tDMA;
+	
+	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the previous values */
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	data = HWIF(drive)->INB(CY82_DATA_PORT);
+
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		(data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+	data = (u8)mode|(u8)(single<<2);
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		mode, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* 
+	 * note: below we set the value for Bus Master IDE TimeOut Register
+	 * I'm not absolutly sure what this does, but it solved my problem
+	 * with IDE DMA and sound, so I now can play sound and work with
+	 * my IDE driver at the same time :-)
+	 *
+	 * If you know the correct (best) value for this register please
+	 * let me know - ASK
+	 */
+
+	data = BUSMASTER_TIMEOUT;
+	HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO	
+	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+		drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/* 
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+int cy82c693_ide_dma_on (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+	if (id != NULL) {		
+		/* Enable DMA on any drive that has DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2) {	/* regular DMA */
+			int mmode, smode;
+
+			mmode = id->dma_mword & (id->dma_mword >> 8);
+			smode = id->dma_1word & (id->dma_1word >> 8);
+			       		      
+			if (mmode != 0) {
+				/* enable multi */
+				cy82c693_dma_enable(drive, (mmode >> 1), 0);
+			} else if (smode != 0) {
+				/* enable single */
+				cy82c693_dma_enable(drive, (smode >> 1), 1);
+			}
+		}
+	}
+        return __ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	pio_clocks_t pclk;
+	unsigned int addrCtrl;
+
+	/* select primary or secondary channel */
+	if (hwif->index > 0) {  /* drive is on the secondary channel */
+		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
+		if (!dev) {
+			printk(KERN_ERR "%s: tune_drive: "
+				"Cannot find secondary interface!\n",
+				drive->name);
+			return;
+		}
+	}
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the register values */
+	
+       	if (drive->select.b.unit == 0) {
+		/*
+		 * get master drive registers               	
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+		addrCtrl &= 0x0F;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+	} else {
+		/*
+		 * set slave drive registers
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= 0xF0;
+		addrCtrl >>= 4;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+	}
+
+	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+	/* first let's calc the pio modes */
+	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* let's calc the values for this PIO mode */
+	compute_clocks(pio, &pclk);
+
+	/* now let's write  the clocks registers */
+	if (drive->select.b.unit == 0) {
+		/*
+		 * set master drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		
+		addrCtrl &= (~0xF);
+		addrCtrl |= (unsigned int)pclk.address_time;
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+		
+		addrCtrl &= 0xF;
+	} else {
+		/*
+		 * set slave drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= (~0xF0);
+		addrCtrl |= ((unsigned int)pclk.address_time<<4);
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+		addrCtrl >>= 4;
+		addrCtrl &= 0xF;
+	}	
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+{
+#ifdef CY82C693_SETDMA_CLOCK
+	u8 data = 0;
+#endif /* CY82C693_SETDMA_CLOCK */ 
+
+	/* write info about this verion of the driver */
+	printk(KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+       /* okay let's set the DMA clock speed */
+        
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        data = inb(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+        /*
+	 * for some reason sometimes the DMA controller
+	 * speed is set to ATCLK/2 ???? - we fix this here
+	 * 
+	 * note: i don't know what causes this strange behaviour,
+	 *       but even changing the dma speed doesn't solve it :-(
+	 *       the ide performance is still only half the normal speed 
+	 * 
+	 *       if anybody knows what goes wrong with my machine, please
+	 *       let me know - ASK
+         */
+
+	data |= 0x03;
+
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */
+	return 0;
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->chipset = ide_cy82c693;
+	hwif->tuneproc = &cy82c693_tune_drive;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x04;
+	hwif->swdma_mask = 0x04;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+void __init init_dma_cy82c693 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+void __init init_setup_cy82c693 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+	    (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+		return;	/* CY82C693 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+}
+
+int __init cy82c693_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_CONTAQ)
+		return 0;
+
+	for (d = cy82c693_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/cy82c693.h b/drivers/ide/pci/cy82c693.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/cy82c693.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,95 @@
+#ifndef CY82C693_H
+#define CY82C693_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+/* the current version */
+#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ *	The following are used to debug the driver.
+ */
+#define	CY82C693_DEBUG_LOGS	0
+#define	CY82C693_DEBUG_INFO	0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ *	NOTE: the value for busmaster timeout is tricky and I got it by
+ *	 trial and error!  By using a to low value will cause DMA timeouts
+ *	 and drop IDE performance, and by using a to high value will cause
+ *	 audio playback to scatter.
+ *	 If you know a better value or how to calc it, please let me know.
+ */
+
+/* twice the value written in cy82c693ub datasheet */
+#define BUSMASTER_TIMEOUT	0x50
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG		0x04
+#define CY82_IDE_ADDRSETUP	0x48
+#define CY82_IDE_MASTER_IOR	0x4C	
+#define CY82_IDE_MASTER_IOW	0x4D	
+#define CY82_IDE_SLAVE_IOR	0x4E	
+#define CY82_IDE_SLAVE_IOW	0x4F
+#define CY82_IDE_MASTER_8BIT	0x50	
+#define CY82_IDE_SLAVE_8BIT	0x51	
+
+#define CY82_INDEX_PORT		0x22
+#define CY82_DATA_PORT		0x23
+
+#define CY82_INDEX_CTRLREG1	0x01
+#define CY82_INDEX_CHANNEL0	0x30
+#define CY82_INDEX_CHANNEL1	0x31
+#define CY82_INDEX_TIMEOUT	0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO	4
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED	25
+#define CY82C963_MAX_BUS_SPEED	33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+        u8	address_time;	/* Address setup (clocks) */
+	u8	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+extern void init_setup_cy82c693(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int init_chipset_cy82c693(struct pci_dev *, const char *);
+extern void init_hwif_cy82c693(ide_hwif_t *);
+extern void init_dma_cy82c693(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cy82c693_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_CONTAQ,
+		device:		PCI_DEVICE_ID_CONTAQ_82C693,
+		name:		"CY82C693",
+		init_setup:	init_setup_cy82c693,
+		init_chipset:	init_chipset_cy82c693,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_cy82c693,
+		init_dma:	init_dma_cy82c693,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* CY82C693_H */
diff -Nru a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/generic.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,109 @@
+/*
+ *  linux/drivers/ide/pci-orphan.c	Version 0.01	December 8, 1997
+ *
+ *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "generic.h"
+
+static unsigned int __init init_chipset_generic (struct pci_dev *dev, const char *name)
+{
+	return 0;
+}
+
+static void __init init_hwif_generic (ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_UMC_UM8673F:
+		case PCI_DEVICE_ID_UMC_UM8886A:
+		case PCI_DEVICE_ID_UMC_UM8886BF:
+			hwif->irq = hwif->channel ? 15 : 14;
+			break;
+		default:
+			break;
+	}
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_generic (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((d->vendor == PCI_VENDOR_ID_UMC) &&
+	    (d->device == PCI_DEVICE_ID_UMC_UM8886A) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return; /* UM8886A/BF pair */
+
+	if ((d->vendor == PCI_VENDOR_ID_OPTI) &&
+	    (d->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return;
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_unknown (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init generic_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	for (d = generic_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		ide_pci_device_t *unknown = unknown_chipset;
+//		unknown->vendor = dev->vendor;
+//		unknown->device = dev->device;
+		init_setup_unknown(dev, unknown);
+		return 1;
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/generic.h b/drivers/ide/pci/generic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/generic.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,172 @@
+#ifndef IDE_GENERIC_H
+#define IDE_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_generic(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_generic(struct pci_dev *, const char *);
+static void init_hwif_generic(ide_hwif_t *);
+static void init_dma_generic(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t generic_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_87410,
+		name:		"NS87410",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		bootable:	ON_BOARD,
+		extra:		0,
+        },{
+		vendor:		PCI_VENDOR_ID_PCTECH,
+		device:		PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		name:		"SAMURAI",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_HOLTEK,
+		device:		PCI_DEVICE_ID_HOLTEK_6565,
+		name:		"HT6565",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8673F,
+		name:		"UM8673F",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8886A,
+		name:		"UM8886A",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8886BF,
+		name:		"UM8886BF",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_HINT,
+		device:		PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		name:		"HINT_IDE",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C561,
+		name:		"VIA_IDE",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_OPTI,
+		device:		PCI_DEVICE_ID_OPTI_82C558,
+		name:		"OPTI621V",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+static ide_pci_device_t unknown_chipset[] __initdata = {
+	{
+		vendor:		0,
+		device:		0,
+		name:		"PCI_IDE",
+		init_setup:	init_setup_generic,
+		init_chipset:	init_chipset_generic,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_generic,
+		init_dma:	init_dma_generic,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+
+};
+
+#endif /* IDE_GENERIC_H */
diff -Nru a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/hpt34x.c	Sun Sep 15 19:19:34 2002
@@ -0,0 +1,354 @@
+/*
+ * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
+ *
+ * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt34x.h"
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc = 0;
+
+#define HPT34X_MAX_DEVS		8
+static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
+static int n_hpt34x_devs;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"HPT34X Chipset.\n");
+	for (i = 0; i < n_hpt34x_devs; i++) {
+		struct pci_dev *dev = hpt34x_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+		u8  c0 = 0, c1 = 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((u16)bibma + 0x02);
+		c1 = inb_p((u16)bibma + 0x0a);
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 hpt34x_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = (reg2 & ~(0x11 << drive->dn));
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+	u8			hi_speed, lo_speed;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = ((hi_speed << drive->dn) | reg2);
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x)\n",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, reg1, tmp1, reg2, tmp2,
+		hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt34x_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+#ifndef CONFIG_HPT34X_AUTODMA
+	return hwif->ide_dma_off_quietly(drive);
+#endif /* CONFIG_HPT34X_AUTODMA */
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define	HPT34X_PCI_INIT_REG		0x80
+
+static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char *name)
+{
+	int i = 0;
+	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+	unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
+	u16 cmd;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & PCI_COMMAND_MEMORY) {
+		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+			pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+				dev->resource[PCI_ROM_RESOURCE].start);
+		}
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+	} else {
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+	}
+
+	/*
+	 * Since 20-23 can be assigned and are R/W, we correct them.
+	 */
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for(i=0; i<4; i++) {
+		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+		dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
+		dev->resource[i].flags = IORESOURCE_IO;
+		pci_write_config_dword(dev,
+				(PCI_BASE_ADDRESS_0 + (i * 4)),
+				dev->resource[i].start);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	local_irq_restore(flags);
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt34x_devs[n_hpt34x_devs++] = dev;
+
+	if (!hpt34x_proc) {
+		hpt34x_proc = 1;
+		ide_pci_register_host_proc(&hpt34x_procs[0]);
+	}
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt34x (ide_hwif_t *hwif)
+{
+	u16 pcicmd = 0;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->no_dsc = 1;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_hpt34x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	char *chipset_names[] = {"HPT343", "HPT345"};
+	u16 pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
+	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+
+	ide_setup_pci_device(dev, d);
+}
+
+int  __init hpt34x_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_TTI)
+		return 0;
+
+	for (d = hpt34x_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/hpt34x.h b/drivers/ide/pci/hpt34x.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/hpt34x.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,62 @@
+#ifndef HPT34X_H
+#define HPT34X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define HPT343_DEBUG_DRIVE_INFO		0
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#undef DISPLAY_HPT34X_TIMINGS
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc;
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt34x_procs[] __initdata = {
+	{
+		name:		"hpt34x",
+		set:		1,
+		get_info:	hpt34x_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_hpt34x(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *);
+static void init_hwif_hpt34x(ide_hwif_t *);
+static void init_dma_hpt34x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt34x_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT343,
+		name:		"HPT34X",
+		init_setup:	init_setup_hpt34x,
+		init_chipset:	init_chipset_hpt34x,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt34x,
+		init_dma:	init_dma_hpt34x,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	NEVER_BOARD,
+		extra:		16
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* HPT34X_H */
diff -Nru a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/hpt366.c	Sun Sep 15 19:19:50 2002
@@ -0,0 +1,1189 @@
+/*
+ * linux/drivers/ide/hpt366.c		Version 0.33	April 17, 2002
+ *
+ * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
+ *
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
+ *
+ * Note that final HPT370 support was done by force extraction of GPL.
+ *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt366.h"
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+
+static u8 hpt366_proc = 0;
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"302", "371",  "374" };
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370/372/374\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev = hpt_revision(dev);
+		u8 c0, c1;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb(iobase + 0x2);
+		c1 = inb(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (hpt_minimum_revision(dev, 3)) {
+			u8 cbl;
+			cbl = inb(iobase + 0x7b);
+			outb(cbl | 1, iobase + 0x7b);
+			outb(cbl & ~1, iobase + 0x7b);
+			cbl = inb(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
+
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u32 hpt_revision (struct pci_dev *dev)
+{
+	u32 class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_TTI_HPT374:
+			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+		case PCI_DEVICE_ID_TTI_HPT372:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		default:
+			break;
+	}
+	return class_rev;
+}
+
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= 0;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+	} else {				/* HPT366 and HPT368 */
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+	}
+	if (!eighty_ninty_three(drive) && (mode))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= hpt3xx_ratemask(drive);
+
+	if (drive->media != ide_disk)
+		return min(speed, (u8)XFER_PIO_4);
+
+	switch(mode) {
+		case 0x04:
+			speed = min(speed, (u8)XFER_UDMA_6);
+			break;
+		case 0x03:
+			speed = min(speed, (u8)XFER_UDMA_5);
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				speed = min(speed, (u8)XFER_UDMA_4);
+			break;
+		case 0x02:
+			speed = min(speed, (u8)XFER_UDMA_4);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				speed = min(speed, (u8)XFER_UDMA_3);
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				speed = min(speed, (u8)XFER_UDMA_2);
+			break;
+		case 0x01:
+			speed = min(speed, (u8)XFER_UDMA_2);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+		case 0x00:
+		default:
+			speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+	}
+	return speed;
+#else
+	return min(speed, (u8)XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (quirk_drives == list) {
+		while (*list)
+			if (strstr(id->model, *list++))
+				return 1;
+	} else {
+		while (*list)
+			if (!strcmp(*list++,id->model))
+				return 1;
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed)
+			return chipset_table->chipset_settings;
+	return chipset_table->chipset_settings;
+}
+
+static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+	u8 regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast		= 0;
+	u32 reg1 = 0, reg2	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+	if (drive_fast & 0x02)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
+
+	reg2 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) dev->driver_data);
+	/*
+	 * Disable on-chip PIO FIFO/buffer
+	 *  (to avoid problems handling I/O errors later)
+	 */
+	pci_read_config_dword(dev, regtime, &reg1);
+	if (speed >= XFER_MW_DMA_0) {
+		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+	} else {
+		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+	}	
+	reg2 &= ~0x80000000;
+
+	pci_write_config_dword(dev, regtime, reg2);
+}
+
+static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_pci	= 0x40 + (drive->dn * 4);
+	u8 new_fast	= 0, drive_fast = 0;
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(dev, regfast, new_fast);
+
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       dev->driver_data);
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
+
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					dev->driver_data);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
+static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
+		hpt372_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 3))
+		hpt370_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
+                hpt366_tune_chipset(drive, speed);
+
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) hpt3xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt3xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, quirk_drives));
+}
+
+static void hpt3xx_intrproc (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (drive->quirk_list)
+		return;
+	/* drives in the quirk_list may not like intr setups/cleanups */
+	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+	if (drive->quirk_list) {
+		if (hpt_minimum_revision(dev,3)) {
+			u8 reg5a = 0;
+			pci_read_config_byte(dev, 0x5a, &reg5a);
+			if (((reg5a & 0x10) >> 4) != mask)
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		} else {
+			if (mask) {
+				disable_irq(HWIF(drive)->irq);
+			} else {
+				enable_irq(HWIF(drive)->irq);
+			}
+		}
+	} else {
+		if (IDE_CONTROL_REG)
+			HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+						 (drive->ctl & ~2),
+						 IDE_CONTROL_REG);
+	}
+}
+
+static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if (id->dma_mword & hwif->mwdma_mask) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt3xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+
+	pci_read_config_byte(dev, 0x50, &reg50h);
+	pci_read_config_byte(dev, 0x52, &reg52h);
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
+	if (reg5ah & 0x10)
+		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+	/* how about we flush and reset, mmmkay? */
+	pci_write_config_byte(dev, 0x51, 0x1F);
+	/* fall through to a reset */
+	case ide_dma_begin:
+	case ide_dma_end:
+	/* reset the chips state over and over.. */
+	pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+	return __ide_dma_lostirq(drive);
+}
+
+static void hpt370_clear_engine (ide_drive_t *drive)
+{
+	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
+	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	udelay(10);
+}
+
+static int hpt370_ide_dma_begin (ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+	hpt370_clear_engine(drive);
+#endif
+	return __ide_dma_begin(drive);
+}
+
+static int hpt370_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if (dma_stat & 0x01) {
+		/* wait a little */
+		udelay(20);
+		dma_stat = hwif->INB(hwif->dma_status);
+	}
+	if ((dma_stat & 0x01) != 0) 
+		/* fallthrough */
+		(void) HWIF(drive)->ide_dma_timeout(drive);
+
+	return __ide_dma_end(drive);
+}
+
+static void hpt370_lostirq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
+	printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+	hpt370_clear_engine(drive);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop dma */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear errors */
+	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
+}
+
+static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int hpt374_ide_dma_end (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
+	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+	pci_read_config_byte(dev, mscreg, &msc_stat);
+	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	return __ide_dma_end(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+
+static void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	u32 high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	u8 reset	= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	u8 reg59h	= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 reg59h = 0, reset	= (hwif->channel) ? 0x80 : 0x40;
+	u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 tristate = 0, resetmask = 0, bus_reg = 0;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(dev, tristate, &tri_reg);
+	pci_read_config_byte(dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(dev, 0x59, bus_reg);
+	pci_write_config_word(dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static int __init init_hpt37x(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	u8 reg5bh;
+
+#if 1
+	u8 reg5ah = 0;
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		if (hpt_minimum_revision(dev,8))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+		printk("HPT37X: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		if (hpt_minimum_revision(dev,8))
+			return -EOPNOTSUPP;
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		printk("HPT37X: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		if (hpt_minimum_revision(dev,8))
+			return -EOPNOTSUPP;
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+		printk("HPT37X: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (dev->driver_data) 
+		goto init_hpt37X_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				if (hpt_minimum_revision(dev,8))
+					return -EOPNOTSUPP;
+				else if (hpt_minimum_revision(dev,5))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+				else if (hpt_minimum_revision(dev,4))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				else
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt37X_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+	return 0;
+}
+
+static int __init init_hpt366 (struct pci_dev *dev)
+{
+	u32 reg1	= 0;
+	u8 drive_fast	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+									
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			pci_set_drvdata(dev, (void *) forty_base_hpt366);
+			break;
+		case 9:
+			pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+			break;
+		case 7:
+		default:
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+			break;
+	}
+
+	if (!dev->driver_data)
+	{
+		printk(KERN_ERR "hpt366: unknown bus timing.\n");
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_hpt366 (struct pci_dev *dev, const char *name)
+{
+	int ret = 0;
+	u8 test = 0;
+
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+	if (test != (L1_CACHE_BYTES / 4))
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+			(L1_CACHE_BYTES / 4));
+
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+	if (test != 0x78)
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+	if (hpt_minimum_revision(dev, 3)) {
+		ret = init_hpt37x(dev);
+	} else {
+		ret =init_hpt366(dev);
+	}
+	if (ret)
+		return ret;
+	
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt_devs[n_hpt_devs++] = dev;
+
+	if (!hpt366_proc) {
+		hpt366_proc = 1;
+		ide_pci_register_host_proc(&hpt366_procs[0]);
+	}
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt366 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev		= hwif->pci_dev;
+	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+
+	hwif->tuneproc			= &hpt3xx_tune_drive;
+	hwif->speedproc			= &hpt3xx_tune_chipset;
+	hwif->quirkproc			= &hpt3xx_quirkproc;
+	hwif->intrproc			= &hpt3xx_intrproc;
+	hwif->maskproc			= &hpt3xx_maskproc;
+
+	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+
+#ifdef DEBUG
+	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+		ata66, (ata66 & regmask) ? "33" : "66",
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	if (hpt_minimum_revision(dev,3)) {
+		u8 reg5ah = 0;
+			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+//		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+	} else if (hpt_minimum_revision(dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
+		hwif->resetproc = &hpt3xx_reset;
+		hwif->busproc   = &hpt3xx_tristate;
+	}
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
+	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+	if (hpt_minimum_revision(dev,8))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,5))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,3)) {
+		hwif->ide_dma_begin = &hpt370_ide_dma_begin;
+		hwif->ide_dma_end = &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
+	} else if (hpt_minimum_revision(dev,2))
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+	else
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 masterdma	= 0, slavedma = 0;
+	u8 dma_new	= 0, dma_old = 0;
+	u8 primary	= hwif->channel ? 0x4b : 0x43;
+	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	unsigned long flags;
+
+	if (!dmabase)
+		return;
+
+	dma_old = hwif->INB(dmabase+2);
+
+	local_irq_save(flags);
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old)
+		hwif->OUTB(dma_new, dmabase+2);
+
+	local_irq_restore(flags);
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			u8 irq = 0, irq2 = 0;
+			pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+			pci_read_config_byte(findev, PCI_INTERRUPT_LINE, &irq2);
+			if (irq != irq2) {
+				pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				findev->irq = dev->irq;
+				printk("%s: pci-config space interrupt "
+					"fixed.\n", d->name);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt37x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+	u8 pin1 = 0, pin2 = 0;
+	unsigned int class_rev;
+	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
+				 "HPT370", "HPT370A", "HPT372"};
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	strcpy(d->name, chipset_names[class_rev]);
+
+	switch(class_rev) {
+		case 5:
+		case 4:
+		case 3: ide_setup_pci_device(dev, d);
+			return;
+		default:	break;
+	}
+
+	d->channels = 1;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
+			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, "
+					"pin1=%d pin2=%d\n", d->name,
+					pin1, pin2);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+int __init hpt366_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_TTI)
+		return 0;
+	if (dev->device == PCI_DEVICE_ID_TTI_HPT343)
+		return 0;
+
+	for (d = hpt366_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/hpt366.h b/drivers/ide/pci/hpt366.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/hpt366.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,523 @@
+#ifndef HPT366_H
+#define HPT366_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_HPT366_TIMINGS
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+const char *quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP LM20.5",
+        NULL
+};
+
+const char *bad_ata100_5[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_4[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_3[] = {
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata33[] = {
+	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+	"Maxtor 90510D4",
+	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+	NULL
+};
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	unsigned int	chipset_settings;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
+struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
+};
+
+struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
+
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
+};
+
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
+};
+
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x0a81f443	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x06814e93	}
+};
+
+#if 0
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO		0
+#define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
+#define HPT372_ALLOW_ATA133_6		1
+#define HPT370_ALLOW_ATA100_5		1
+#define HPT366_ALLOW_ATA66_4		1
+#define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt366_proc;
+
+static int hpt366_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt366_procs[] __initdata = {
+	{
+		name:		"hpt366",
+		set:		1,
+		get_info:	hpt366_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_hpt366(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt37x(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt374(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_hpt366(struct pci_dev *, const char *);
+static void init_hwif_hpt366(ide_hwif_t *);
+static void init_dma_hpt366(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt366_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT366,
+		name:		"HPT366",
+		init_setup:	init_setup_hpt366,
+		init_chipset:	init_chipset_hpt366,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt366,
+		init_dma:	init_dma_hpt366,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		240
+	},{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT372,
+		name:		"HPT372A",
+		init_setup:	init_setup_hpt37x,
+		init_chipset:	init_chipset_hpt366,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt366,
+		init_dma:	init_dma_hpt366,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT302,
+		name:		"HPT302",
+		init_setup:	init_setup_hpt37x,
+		init_chipset:	init_chipset_hpt366,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt366,
+		init_dma:	init_dma_hpt366,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT371,
+		name:		"HPT371",
+		init_setup:	init_setup_hpt37x,
+		init_chipset:	init_chipset_hpt366,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt366,
+		init_dma:	init_dma_hpt366,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0
+	},{
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT374,
+		name:		"HPT374",
+		init_setup:	init_setup_hpt374,
+		init_chipset:	init_chipset_hpt366,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_hpt366,
+		init_dma:	init_dma_hpt366,
+		channels:	2,	/* 4 */
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* HPT366_H */
diff -Nru a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/it8172.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,325 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *      IT8172 IDE controller support
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *              stevel@mvista.com or source@mvista.com
+ *
+ *  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.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/it8172/it8172_int.h>
+
+#include "ide_modes.h"
+#include "it8172.h"
+
+/*
+ * Prototypes
+ */
+static u8 it8172_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (hwif->drives[1] == drive);
+	unsigned long flags;
+	u16 drive_enables;
+	u32 drive_timing;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, 0x40, &drive_enables);
+	pci_read_config_dword(dev, 0x44, &drive_timing);
+
+	/*
+	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+	 * are being left at the default values of 8 PCI clocks (242 nsec
+	 * for a 33 MHz clock). These can be safely shortened at higher
+	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
+	 * apply to PIO modes, not to the DMA modes.
+	 */
+
+	/*
+	 * Enable port 0x44. The IT8172G spec is confused; it calls
+	 * this register the "Slave IDE Timing Register", but in fact,
+	 * it controls timing for both master and slave drives.
+	 */
+	drive_enables |= 0x4000;
+
+	if (is_slave) {
+		drive_enables &= 0xc006;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0060;
+	} else {
+		drive_enables &= 0xc060;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0006;
+	}
+
+	pci_write_config_word(dev, 0x40, drive_enables);
+	spin_unlock_irqrestore(&ide_lock, flags)
+}
+
+static u8 it8172_dma_2_pio (u8 xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(it8172_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	u8 reg48, reg4a;
+
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x4a, &reg4a);
+
+    /*
+     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+     * transfers on some drives, even though both numbers meet the minimum
+     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+     * So the faster times are just commented out here. The good news is
+     * that the slower cycle time has very little affect on transfer
+     * performance.
+     */
+    
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		reg4a &= ~a_speed;
+		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+	} else {
+		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) it8172_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = it8172_config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!it8172_config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!it8172_config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		it8172_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+{
+	unsigned char progif;
+    
+	/*
+	 * Place both IDE interfaces into PCI "native" mode
+	 */
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+
+	return IT8172_IDE_IRQ;
+}
+
+
+static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+{
+	struct pci_dev* dev = hwif->pci_dev;
+	unsigned long cmdBase, ctrlBase;
+    
+	hwif->autodma = 0;
+	hwif->tuneproc = &it8172_tune_drive;
+	hwif->speedproc = &it8172_tune_chipset;
+
+	cmdBase = dev->resource[0].start;
+	ctrlBase = dev->resource[1].start;
+    
+	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->noprobe = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_it8172 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return; /* IT8172 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+}
+
+static int __init it8172_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_ITE)
+		return 0;
+
+	for (d = it8172_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/it8172.h b/drivers/ide/pci/it8172.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/it8172.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,45 @@
+#ifndef ITE8172G_H
+#define ITE8172G_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static u8 it8172_ratemask(ide_drive_t *drive);
+static u8 it8172_ratefilter(ide_drive_t *drive, u8 speed);
+static void it8172_tune_drive(ide_drive_t *drive, u8 pio);
+static u8 it8172_dma_2_pio(u8 xfer_rate);
+static int it8172_tune_chipset(ide_drive_t *drive, u8 xferspeed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma(ide_drive_t *drive);
+#endif
+
+static void init_setup_it8172(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_it8172(struct pci_dev *, const char *);
+static void init_hwif_it8172(ide_hwif_t *);
+static void init_dma_it8172(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t it8172_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_ITE,
+		device:		PCI_DEVICE_ID_ITE_IT8172G,
+		name:		"IT8172G",
+		init_setup:	init_setup_it8172,
+		init_chipset:	init_chipset_it8172,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_it8172,
+                init_dma:	init_dma_it8172,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* ITE8172G_H */
diff -Nru a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/ns87415.c	Sun Sep 15 19:19:37 2002
@@ -0,0 +1,254 @@
+/*
+ * linux/drivers/ide/ns87415.c		Version 1.01  Mar. 18, 2000
+ *
+ * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ *
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ns87415.h"
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	new = *old;
+
+	/* Adjust IRQ enable bit */
+	bit = 1 << (8 + hwif->channel);
+	new = drive->present ? (new & ~bit) : (new | bit);
+
+	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
+
+	if (new != *old) {
+		unsigned char stat;
+
+		/*
+		 * Don't change DMA engine settings while Write Buffers
+		 * are busy.
+		 */
+		(void) pci_read_config_byte(dev, 0x43, &stat);
+		while (stat & 0x03) {
+			udelay(1);
+			(void) pci_read_config_byte(dev, 0x43, &stat);
+		}
+
+		*old = new;
+		(void) pci_write_config_dword(dev, 0x40, new);
+
+		/*
+		 * And let things settle...
+		 */
+		udelay(10);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+	ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int ns87415_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t      *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+	/* from ERRATA: clear the INTR & ERROR bits */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	hwif->OUTB(dma_cmd|6, hwif->dma_command);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int ns87415_ide_dma_read (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_read(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_write (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_write(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_check (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	return __ide_dma_check(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int ctrl, using_inta;
+	u8 progif;
+#ifdef __sparc_v9__
+	int timeout;
+	u8 stat;
+#endif
+
+	hwif->autodma = 0;
+	hwif->selectproc = &ns87415_selectproc;
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+	/*
+	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
+	 * Also, leave IRQ masked during drive probing, to prevent infinite
+	 * interrupts from a potentially floating INTA..
+	 *
+	 * IRQs get unmasked in selectproc when drive is first used.
+	 */
+	(void) pci_read_config_dword(dev, 0x40, &ctrl);
+	(void) pci_read_config_byte(dev, 0x09, &progif);
+	/* is irq in "native" mode? */
+	using_inta = progif & (1 << (hwif->channel << 1));
+	if (!using_inta)
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
+	} else {
+		hwif->select_data = (unsigned long)
+					&ns87415_control[ns87415_count++];
+		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
+		if (using_inta)
+			ctrl &= ~(1 << 6);	/* unmask INTA */
+		*((unsigned int *)hwif->select_data) = ctrl;
+		(void) pci_write_config_dword(dev, 0x40, ctrl);
+
+		/*
+		 * Set prefetch size to 512 bytes for both ports,
+		 * but don't turn on/off prefetching here.
+		 */
+		pci_write_config_byte(dev, 0x55, 0xee);
+
+#ifdef __sparc_v9__
+		/*
+		 * XXX: Reset the device, if we don't it will not respond
+		 *      to SELECT_DRIVE() properly during first probe_hwif().
+		 */
+		timeout = 10000;
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			udelay(50);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+                	if (stat == 0xff)
+                        	break;
+        	} while ((stat & BUSY_STAT) && --timeout);
+#endif
+	}
+
+	if (!using_inta)
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
+
+	if (!hwif->dma_base)
+		return;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->OUTB(0x60, hwif->dma_status);
+	hwif->ide_dma_read = &ns87415_ide_dma_read;
+	hwif->ide_dma_write = &ns87415_ide_dma_write;
+	hwif->ide_dma_check = &ns87415_ide_dma_check;
+	hwif->ide_dma_end = &ns87415_ide_dma_end;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_ns87415 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init ns87415_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_NS)
+		return 0;
+
+	for (d = ns87415_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/ns87415.h b/drivers/ide/pci/ns87415.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/ns87415.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,35 @@
+#ifndef NS87415_H
+#define NS87415_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_ns87415(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_ns87415(ide_hwif_t *);
+static void init_dma_ns87415(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ns87415_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_87415,
+		name:		"NS87415",
+		init_setup:	init_setup_ns87415,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_ns87415,
+                init_dma:	init_dma_ns87415,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* NS87415_H */
diff -Nru a/drivers/ide/pci/nvidia.c b/drivers/ide/pci/nvidia.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/nvidia.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,362 @@
+/*
+ * linux/drivers/ide/nvidia.c		Version 0.01
+ *
+ * Copyright (C) 2002-2002		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "nvidia.h"
+
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 nforce_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int nforce_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+	u8 c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"nVidia %04X Chipset.\n", bmide_dev->device);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 nforce_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+        switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Here is where all the hard work goes to program the chipset.
+ */
+static int nforce_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 drive_pci[]		= { 0x63, 0x62, 0x61, 0x60 };
+	u8 drive_pci2[]		= { 0x5b, 0x5a, 0x59, 0x58 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(nforce_ratemask(drive), xferspeed);
+	u8 ultra_timing	= 0, dma_pio_timing = 0, pio_timing = 0;
+
+	pci_read_config_byte(dev, drive_pci[drive->dn], &ultra_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_pio_timing);
+	pci_read_config_byte(dev, 0x5c, &pio_timing);
+
+	ultra_timing	&= ~0xC7;
+	dma_pio_timing	&= ~0xFF;
+	pio_timing	&= ~(0x03 << drive->dn);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+		case XFER_UDMA_6:
+			speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+			ultra_timing |= 0x46;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_4:
+			ultra_timing |= 0x45;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_3:
+			ultra_timing |= 0x44;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_2:
+			ultra_timing |= 0x40;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_1:
+			ultra_timing |= 0x41;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_UDMA_0:
+			ultra_timing |= 0x42;
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_2:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_MW_DMA_1:
+			dma_pio_timing |= 0x21;
+			break;
+		case XFER_MW_DMA_0:
+			dma_pio_timing |= 0x77;
+			break;
+		case XFER_SW_DMA_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_SW_DMA_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_SW_DMA_0:
+			dma_pio_timing |= 0xA8;
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+			dma_pio_timing |= 0x20;
+			break;
+		case XFER_PIO_3:
+			dma_pio_timing |= 0x22;
+			break;
+		case XFER_PIO_2:
+			dma_pio_timing |= 0x42;
+			break;
+		case XFER_PIO_1:
+			dma_pio_timing |= 0x65;
+			break;
+		case XFER_PIO_0:
+		default:
+			dma_pio_timing |= 0xA8;
+			break;
+        }
+
+	pio_timing |= (0x03 << drive->dn);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing);
+	pci_write_config_byte(dev, 0x5c, pio_timing);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void nforce_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) nforce_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, nforce_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) nforce_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int nforce_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		nforce_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+unsigned int __init init_chipset_nforce (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!nforce_proc) {
+		nforce_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&nforce_procs[0]);
+	}
+#endif /* DISPLAY_NFORCE_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static unsigned int __init ata66_nforce (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 cable_80_pin[2]	= { 0, 0 };
+	u8 ata66		= 0;
+	u8 tmpbyte;
+
+	/*
+	 * Ultra66 cable detection (from Host View)
+	 * 7411, 7441, 0x52, bit0: primary, bit2: secondary 80 pin
+	 */
+	pci_read_config_byte(dev, 0x52, &tmpbyte);
+
+	/*
+	 * 0x52, bit0 is 1 => primary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
+
+	/*
+	 * 0x52, bit2 is 1 => secondary channel
+	 * has 80-pin (from host view)
+	 */
+	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_NVIDIA_NFORCE_IDE:
+			ata66 = (hwif->channel) ?
+				cable_80_pin[1] :
+				cable_80_pin[0];
+		default:
+			break;
+	}
+	return (unsigned int) ata66;
+}
+
+static void __init init_hwif_nforce (ide_hwif_t *hwif)
+{
+	hwif->tuneproc = &nforce_tune_drive;
+	hwif->speedproc = &nforce_tune_chipset;
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_nforce(hwif);
+	hwif->ide_dma_check = &nforce_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+/* FIXME - not needed */
+static void __init init_dma_nforce (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/* FIXME - not needed */
+static void __init init_setup_nforce (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init nforce_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_NVIDIA)
+		return 0;
+
+	for (d = nvidia_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/nvidia.h b/drivers/ide/pci/nvidia.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/nvidia.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,56 @@
+#ifndef NFORCE_H
+#define NFORCE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_NFORCE_TIMINGS
+
+#if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 nforce_proc;
+
+static int nforce_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t nforce_procs[] __initdata = {
+	{
+		name:		"nforce",
+		set:		1,
+		get_info:	nforce_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_nforce(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_nforce(struct pci_dev *, const char *);
+static void init_hwif_nforce(ide_hwif_t *);
+static void init_dma_nforce(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t nvidia_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_NVIDIA,
+		device:		PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		name:		"NFORCE",
+		init_setup:	init_setup_nforce,
+		init_chipset:	init_chipset_nforce,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_nforce,
+		init_dma:	init_dma_nforce,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* NFORCE_H */
diff -Nru a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/opti621.c	Sun Sep 15 19:19:34 2002
@@ -0,0 +1,383 @@
+/*
+ *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
+ *
+ *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
+ * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
+ * and disassembled/traced setupvic.exe (DOS program).
+ * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
+ * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
+ * It has a place for a secondary connector in circuit, but nothing
+ * is there. Also BIOS says no address for
+ * secondary controller (see bellow in ide_init_opti621).
+ * I've only tested this on my system, which only has one disk.
+ * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
+ * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
+ * lockups). I tried the OCTEK double speed CD-ROM and
+ * it does not work! But I can't boot DOS also, so it's probably
+ * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
+ * problems) and Seagate 1GB (as slave, WD as master). My experiences
+ * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
+ * it slows to about 100kB/s! I don't know why and I have
+ * not this drive now, so I can't try it again.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
+ * The main problem with OPTi is that some timings for master
+ * and slave must be the same. For example, if you have master
+ * PIO 3 and slave PIO 0, driver have to set some timings of
+ * master for PIO 0. Second problem is that opti621_tune_drive
+ * got only one drive to set, but have to set both drives.
+ * This is solved in compute_pios. If you don't set
+ * the second drive, compute_pios use ide_get_best_pio_mode
+ * for autoselect mode (you can change it to PIO 0, if you want).
+ * If you then set the second drive to another PIO, the old value
+ * (automatically selected) will be overrided by yours.
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency which get
+ * (use idebus=xx to select PCI bus speed).
+ * Use ide0=autotune for automatical tune of the PIO modes.
+ * If you get strange results, do not use this and set PIO manually
+ * by hdparm.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8. 
+ * Initial version of driver.
+ * 
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ * 
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
+ */
+
+#undef REALLY_SLOW_IO	/* most systems can safely undef this */
+#define OPTI621_DEBUG		/* define for debug messages */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "opti621.h"
+
+#define OPTI621_MAX_PIO 3
+/* In fact, I do not have any PIO 4 drive
+ * (address: 25 ns, data: 70 ns, recovery: 35 ns),
+ * but OPTi 82C621 is programmable and it can do (minimal values):
+ * on 40MHz PCI bus (pulse 25 ns):
+ *  address: 25 ns, data: 25 ns, recovery: 50 ns;
+ * on 20MHz PCI bus (pulse 50 ns):
+ *  address: 50 ns, data: 50 ns, recovery: 100 ns.
+ */
+
+/* #define READ_PREFETCH 0 */
+/* Uncommnent for disable read prefetch.
+ * There is some readprefetch capatibility in hdparm,
+ * but when I type hdparm -P 1 /dev/hda, I got errors
+ * and till reset drive is inaccessible.
+ * This (hw) read prefetch is safe on my drive.
+ */
+
+#ifndef READ_PREFETCH
+#define READ_PREFETCH 0x40 /* read prefetch is enabled */
+#endif /* else read prefetch is disabled */
+
+#define READ_REG 0	/* index of Read cycle timing register */
+#define WRITE_REG 1	/* index of Write cycle timing register */
+#define CNTRL_REG 3	/* index of Control register */
+#define STRAP_REG 5	/* index of Strap register */
+#define MISC_REG 6	/* index of Miscellaneous register */
+
+static int reg_base;
+
+#define PIO_NOT_EXIST 254
+#define PIO_DONT_KNOW 255
+
+/* there are stored pio numbers from other calls of opti621_tune_drive */
+static void compute_pios(ide_drive_t *drive, u8 pio)
+/* Store values into drive->drive_data
+ *	second_contr - 0 for primary controller, 1 for secondary
+ *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
+ *	pio - PIO mode for selected drive (for other we don't know)
+ */
+{
+	int d;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	for (d = 0; d < 2; ++d) {
+		drive = &hwif->drives[d];
+		if (drive->present) {
+			if (drive->drive_data == PIO_DONT_KNOW)
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+#ifdef OPTI621_DEBUG
+			printk("%s: Selected PIO mode %d\n",
+				drive->name, drive->drive_data);
+#endif
+		} else {
+			drive->drive_data = PIO_NOT_EXIST;
+		}
+	}
+}
+
+static int cmpt_clk(int time, int bus_speed)
+/* Returns (rounded up) time in clocks for time in ns,
+ * with bus_speed in MHz.
+ * Example: bus_speed = 40 MHz, time = 80 ns
+ * 1000/40 = 25 ns (clk value),
+ * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
+ * Use idebus=xx to select right frequency.
+ */
+{
+	return ((time*bus_speed+999)/1000);
+}
+
+static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
+/* Write value to register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	hwif->OUTB(value, reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+}
+
+static u8 read_reg(ide_hwif_t *hwif, int reg)
+/* Read value from register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	u8 ret = 0;
+
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	ret = hwif->INB(reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+	return ret;
+}
+
+typedef struct pio_clocks_s {
+	int	address_time;	/* Address setup (clocks) */
+	int	data_time;	/* Active/data pulse (clocks) */
+	int	recovery_time;	/* Recovery time (clocks) */
+} pio_clocks_t;
+
+static void compute_clocks(int pio, pio_clocks_t *clks)
+{
+        if (pio != PIO_NOT_EXIST) {
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
+ 	       	adr_setup = ide_pio_timings[pio].setup_time;
+  	      	data_pls = ide_pio_timings[pio].active_time;
+	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+     			- adr_setup-data_pls, bus_speed);
+     		if (clks->address_time<1) clks->address_time = 1;
+     		if (clks->address_time>4) clks->address_time = 4;
+     		if (clks->data_time<1) clks->data_time = 1;
+     		if (clks->data_time>16) clks->data_time = 16;
+     		if (clks->recovery_time<2) clks->recovery_time = 2;
+     		if (clks->recovery_time>17) clks->recovery_time = 17;
+	} else {
+		clks->address_time = 1;
+		clks->data_time = 1;
+		clks->recovery_time = 2;
+		/* minimal values */
+	}
+ 
+}
+
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	/* primary and secondary drives share some registers,
+	 * so we have to program both drives
+	 */
+	unsigned long flags;
+	u8 pio1 = 0, pio2 = 0;
+	pio_clocks_t first, second;
+	int ax, drdy;
+	u8 cycle1, cycle2, misc;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	/* sets drive->drive_data for both drives */
+	compute_pios(drive, pio);
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
+
+	compute_clocks(pio1, &first);
+	compute_clocks(pio2, &second);
+
+	/* ax = max(a1,a2) */
+	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
+
+	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
+
+	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
+	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
+	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
+
+#ifdef OPTI621_DEBUG
+	printk("%s: master: address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, first.data_time,
+		first.recovery_time, drdy);
+	printk("%s: slave:  address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, second.data_time,
+		second.recovery_time, drdy);
+#endif
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+
+	/* allow Register-B */
+	hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+	/* hmm, setupvic.exe does this ;-) */
+	hwif->OUTB(0xff, reg_base+5);
+	/* if reads 0xff, adapter not exist? */
+	(void) hwif->INB(reg_base+CNTRL_REG);
+	/* if reads 0xc0, no interface exist? */
+	read_reg(hwif, CNTRL_REG);
+	/* read version, probably 0 */
+	read_reg(hwif, STRAP_REG);
+
+	/* program primary drive */
+		/* select Index-0 for Register-A */
+	write_reg(hwif, 0,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle1, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle1, WRITE_REG);
+
+	/* program secondary drive */
+		/* select Index-1 for Register-B */
+	write_reg(hwif, 1,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle2, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle2, WRITE_REG);
+
+	/* use Register-A for drive 0 */
+	/* use Register-B for drive 1 */
+	write_reg(hwif, 0x85, CNTRL_REG);
+
+	/* set address setup, DRDY timings,   */
+	/*  and read prefetch for both drives */
+ 	write_reg(hwif, misc, MISC_REG);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * init_hwif_opti621() is called once for each hwif found at boot.
+ */
+static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->drives[0].drive_data = PIO_DONT_KNOW;
+	hwif->drives[1].drive_data = PIO_DONT_KNOW;
+	hwif->tuneproc = &opti621_tune_drive;
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+}
+
+static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init opti621_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_OPTI)
+		return 0;
+
+	for (d = opti621_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/opti621.h b/drivers/ide/pci/opti621.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/opti621.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,49 @@
+#ifndef OPTI621_H
+#define OPTI621_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_opti621(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_opti621(ide_hwif_t *);
+static void init_dma_opti621(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t opti621_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_OPTI,
+		device:		PCI_DEVICE_ID_OPTI_82C621,
+		name:		"OPTI621",
+		init_setup:	init_setup_opti621,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_opti621,
+		init_dma:	init_dma_opti621,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_OPTI,
+		device:		PCI_DEVICE_ID_OPTI_82C825,
+		name:		"OPTI621X",
+		init_setup:	init_setup_opti621,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_opti621,
+                init_dma:	init_dma_opti621,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* OPTI621_H */
diff -Nru a/drivers/ide/pci/pdc202xx.c b/drivers/ide/pci/pdc202xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,1181 @@
+/*
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  Promise Ultra100 cards.
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	u32 bibma  = pci_resource_start(dev, 4);
+	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+	u8 hi = 0, lo = 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((u16)bibma + 0x02);
+	u8 c1	= inb_p((u16)bibma + 0x0a);
+
+	u8 sc11	= inb_p((u16)bibma + 0x11);
+	u8 sc1a	= inb_p((u16)bibma + 0x1a);
+	u8 sc1b	= inb_p((u16)bibma + 0x1b);
+	u8 sc1c	= inb_p((u16)bibma + 0x1c); 
+	u8 sc1d	= inb_p((u16)bibma + 0x1d);
+	u8 sc1e	= inb_p((u16)bibma + 0x1e);
+	u8 sc1f	= inb_p((u16)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "Ultra100"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "Ultra100 on M/B"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "FastTrak 66"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "Ultra66"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "Ultra33");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "Ultra Series"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+		(c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
+		(c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
+	p += sprintf(p, "DMA Mode:       %s           %s "
+			"         %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s "
+			"          %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
+#if 0
+	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+#endif
+	return (char *)p;
+}
+
+static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+//	u32 bibma = pci_resource_start(dev, 4);
+
+//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+//	u16 reg50h = 0, word88 = 0;
+//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "SBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "MBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "MBUltra133"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "FastTrak TX2000"); break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+			p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "Ultra133 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "Ultra100 TX2"); break;
+		default:
+			p += sprintf(p, "Ultra series"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_PROMISE_20277:
+			case PCI_DEVICE_ID_PROMISE_20276:
+			case PCI_DEVICE_ID_PROMISE_20275:
+			case PCI_DEVICE_ID_PROMISE_20271:
+			case PCI_DEVICE_ID_PROMISE_20269:
+			case PCI_DEVICE_ID_PROMISE_20268:
+			case PCI_DEVICE_ID_PROMISE_20270:
+				p = pdc202xx_info_new(buffer, dev);
+				break;
+			default:
+				p = pdc202xx_info(buffer, dev);
+				break;
+		}
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			mode = 4;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			return 1;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int pdc202xx_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	u32 indexreg		= hwif->dma_vendor1;
+	u32 datareg		= hwif->dma_vendor3;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 high_16		= pci_resource_start(dev, 4);
+	u32 indexreg		= high_16 + (hwif->channel ? 0x09 : 0x01);
+	u32 datareg		= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 thold		= 0x10;
+	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed == XFER_UDMA_2) {
+		hwif->OUTB((thold + adj), indexreg);
+		hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	switch (speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:	set_ultra(0x1a, 0x01, 0xcb); break;
+		case XFER_UDMA_5:	set_ultra(0x1a, 0x02, 0xcb); break;
+		case XFER_UDMA_4:	set_ultra(0x1a, 0x03, 0xcd); break;
+		case XFER_UDMA_3:	set_ultra(0x1a, 0x05, 0xcd); break;
+		case XFER_UDMA_2:	set_ultra(0x2a, 0x07, 0xcd); break;
+		case XFER_UDMA_1:	set_ultra(0x3a, 0x0a, 0xd0); break;
+		case XFER_UDMA_0:	set_ultra(0x4a, 0x0f, 0xd5); break;
+		case XFER_MW_DMA_2:	set_ata2(0x69, 0x25); break;
+		case XFER_MW_DMA_1:	set_ata2(0x6b, 0x27); break;
+		case XFER_MW_DMA_0:	set_ata2(0xdf, 0x5f); break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	set_pio(0x23, 0x09, 0x25); break;
+		case XFER_PIO_3:	set_pio(0x27, 0x0d, 0x35); break;
+		case XFER_PIO_2:	set_pio(0x23, 0x26, 0x64); break;
+		case XFER_PIO_1:	set_pio(0x46, 0x29, 0xa4); break;
+		case XFER_PIO_0:	set_pio(0xfb, 0x2b, 0xac); break;
+		default:
+			;
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	pio = (pio == 5) ? 4 : pio;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdc202xx_tune_chipset(drive, speed));
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+static u8 pdc202xx_new_cable_detect (ide_hwif_t *hwif)
+{
+	hwif->OUTB(0x0b, hwif->dma_vendor1);
+	return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+	return ((u8)(CIS & mask));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 drive_conf		= 0;
+	u8 mask			= hwif->channel ? 0x08 : 0x02;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 test1 = 0, test2 = 0, speed = -1;
+	u8 AP = 0, CLKSPD = 0, jumpbit = 0, cable = 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			cable = pdc202xx_new_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			jumpbit = 1;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			cable = pdc202xx_old_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			jumpbit = 0;
+			break;
+		default:
+			cable = 1; jumpbit = 0;
+			break;
+	}
+
+	if (!jumpbit)
+		CLKSPD = hwif->INB(hwif->dma_master + 0x11);
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		if (!jumpbit)
+			hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive->dn%2)].id) {
+				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
+					if (!jumpbit)
+						hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+				} else {
+					if (!jumpbit)
+						hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				if (!jumpbit)
+					hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+			}
+		}
+	}
+
+	if (jumpbit) {
+		if (drive->media != ide_disk)
+			return 0;
+		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+			hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+			hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+		}
+		goto jumpbit_is_set;
+	}
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	if (!(test1 & SYNC_ERRDY_EN)) {
+		if (drive->select.b.unit & 0x01) {
+			pci_read_config_byte(dev, drive_pci - 4, &test2);
+			if ((test2 & SYNC_ERRDY_EN) &&
+			    !(test1 & SYNC_ERRDY_EN)) {
+				pci_write_config_byte(dev, drive_pci,
+					test1|SYNC_ERRDY_EN);
+			}
+		} else {
+			pci_write_config_byte(dev, drive_pci,
+				test1|SYNC_ERRDY_EN);
+		}
+	}
+
+chipset_is_set:
+
+	if (drive->media == ide_disk) {
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (id->capability & 4)	/* IORDY_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (drive->media == ide_disk)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+	}
+
+jumpbit_is_set:
+
+	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+	if (!(speed)) {
+		/* restore original pci-config space */
+		if (!jumpbit)
+			pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		struct request *rq	= HWGROUP(drive)->rq;
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u32 high_16	= pci_resource_start(dev, 4);
+		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u32 word_count	= 0;
+		u8 clock = hwif->INB(high_16 + 0x11);
+
+		hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11);
+		word_count = (rq->nr_sectors << 8);
+		word_count = (rq->cmd == READ) ? word_count | 0x05000000 :
+						 word_count | 0x06000000;
+		hwif->OUTL(word_count, atapi_reg);
+	}
+	return __ide_dma_begin(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u32 high_16	= pci_resource_start(hwif->pci_dev, 4);
+		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock	= 0;
+
+		hwif->OUTL(0, atapi_reg); /* zero out extra */
+		clock = hwif->INB(high_16 + 0x11);
+		hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+	}
+	return __ide_dma_end(drive);
+}
+
+static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8 sc1d			= hwif->INB((high_16 + 0x001d));
+
+	if (hwif->channel) {
+		if ((sc1d & 0x50) == 0x50)
+			goto somebody_else;
+		else if ((sc1d & 0x40) == 0x40)
+			return (dma_stat & 4) == 4;
+	} else {
+		if ((sc1d & 0x05) == 0x05)
+			goto somebody_else;
+		else if ((sc1d & 0x04) == 0x04)
+			return (dma_stat & 4) == 4;
+	}
+somebody_else:
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void pdc202xx_new_reset (ide_drive_t *drive)
+{
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdc202xx_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdc202xx_reset_host(hwif);
+	pdc202xx_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 sc1f			= hwif->INB(high_16|0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+	} else {
+		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		ide_pci_register_host_proc(&pdc202xx_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	/*
+	 * software reset -  this is required because the bios
+	 * will set UDMA timing on if the hdd supports it. The
+	 * user may want to turn udma off. A bug in the pdc20262
+	 * is that it cannot handle a downgrade in timing from
+	 * UDMA to DMA. Disk accesses after issuing a set
+	 * feature command will result in errors. A software
+	 * reset leaves the timing registers intact,
+	 * but resets the drives.
+	 */
+#if 0
+	if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+		unsigned long high_16	= pci_resource_start(dev, 4);
+		byte udma_speed_flag	= inb(high_16 + 0x001f);
+		outb(udma_speed_flag | 0x10, high_16 + 0x001f);
+		mdelay(100);
+		outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		mdelay(2000);	/* 2 seconds ?! */
+	}
+
+#endif
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		hwif->busproc   = &pdc202xx_tristate;
+		hwif->resetproc = &pdc202xx_reset;
+	}
+
+	hwif->speedproc = &pdc202xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		if (!(hwif->udma_four))
+			hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+		hwif->ide_dma_begin = &pdc202xx_old_ide_dma_begin;
+		hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+	} 
+	hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */	
+}
+
+static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+	hwif->speedproc = &pdc202xx_new_tune_chipset;
+	hwif->resetproc = &pdc202xx_new_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+	if (!(hwif->udma_four))
+		hwif->udma_four = (pdc202xx_new_cable_detect(hwif)) ? 0 : 1;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+	if (hwif->channel) {
+		ide_setup_dma(hwif, dmabase, 8);
+		return;
+	}
+
+	udma_speed_flag	= hwif->INB((dmabase|0x1f));
+	primary_mode	= hwif->INB((dmabase|0x1a));
+	secondary_mode	= hwif->INB((dmabase|0x1b));
+	printk("%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n", hwif->cds->name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+	if (!(udma_speed_flag & 1)) {
+		printk("%s: FORCING BURST BIT 0x%02x->0x%02x ",
+			hwif->cds->name, udma_speed_flag,
+			(udma_speed_flag|1));
+		hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+		printk("%sACTIVE\n",
+			(hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+	}
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk("%s: FORCING PRIMARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			primary_mode, (primary_mode|1));
+		hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+	}
+
+	if (!(secondary_mode & 1)) {
+		printk("%s: FORCING SECONDARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			secondary_mode, (secondary_mode|1));
+		hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+		u8 irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		/* 0xbc */
+		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev,
+				(PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+			printk("%s: pci-config space interrupt "
+				"mirror fixed.\n", d->name);
+		}
+	}
+
+#if 0
+        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+
+#if 0
+        {
+                u8 pri = 0, sec = 0;
+
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				u8 irq = 0, irq2 = 0;
+				pci_read_config_byte(dev,
+					PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(findev,
+					PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					findev->irq = dev->irq;
+					pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				}
+				ide_setup_pci_devices(dev, findev, d);
+				return;
+			}
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+int __init pdc202xx_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_PROMISE)
+		return 0;
+
+	for (d = pdc202xx_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/pdc202xx.h b/drivers/ide/pci/pdc202xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,436 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc;
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
+	{
+		name:		"pdc202xx",
+		set:		1,
+		get_info:	pdc202xx_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d);
+static void init_setup_pdc20265(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc202xx(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+static unsigned int init_chipset_pdc202xx(struct pci_dev *, const char *);
+static void init_hwif_pdc202xx(ide_hwif_t *);
+static void init_hwif_pdc202new(ide_hwif_t *);
+static void init_dma_pdc202xx(ide_hwif_t *, unsigned long);
+static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdc202xx_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20246,
+		name:		"PDC20246",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		16,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20262,
+		name:		"PDC20262",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20263,
+		name:		"PDC20263",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20265,
+		name:		"PDC20265",
+		init_setup:	init_setup_pdc20265,
+		init_chipset:	init_chipset_pdc202xx,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20267,
+		name:		"PDC20267",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20268,
+		name:		"PDC20268",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20269,
+		name:		"PDC20269",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20270,
+		name:		"PDC20270",
+		init_setup:	init_setup_pdc20270,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20271,
+		name:		"PDC20271",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20275,
+		name:		"PDC20275",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20276,
+		name:		"PDC20276",
+		init_setup:	init_setup_pdc20276,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20277,
+		name:		"PDC20277",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx_new.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,666 @@
+/*
+ *  Promise TX2/TX4/TX2000/133 IDE driver
+ *
+ *  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.
+ *
+ *  Split from:
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_new.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdcnew_info(char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "SBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "MBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "MBUltra133"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "FastTrak TX2000"); break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+			p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "Ultra133 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "Ultra100 TX2"); break;
+		default:
+			p += sprintf(p, "Ultra series"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdcnew_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdcnew_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdcnew_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			mode = 4;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdcnew_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	u32 indexreg		= hwif->dma_vendor1;
+	u32 datareg		= hwif->dma_vendor3;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 high_16		= pci_resource_start(dev, 4);
+	u32 indexreg		= high_16 + (hwif->channel ? 0x09 : 0x01);
+	u32 datareg		= (indexreg + 2);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 thold		= 0x10;
+	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
+	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed == XFER_UDMA_2) {
+		hwif->OUTB((thold + adj), indexreg);
+		hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	switch (speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:	set_ultra(0x1a, 0x01, 0xcb); break;
+		case XFER_UDMA_5:	set_ultra(0x1a, 0x02, 0xcb); break;
+		case XFER_UDMA_4:	set_ultra(0x1a, 0x03, 0xcd); break;
+		case XFER_UDMA_3:	set_ultra(0x1a, 0x05, 0xcd); break;
+		case XFER_UDMA_2:	set_ultra(0x2a, 0x07, 0xcd); break;
+		case XFER_UDMA_1:	set_ultra(0x3a, 0x0a, 0xd0); break;
+		case XFER_UDMA_0:	set_ultra(0x4a, 0x0f, 0xd5); break;
+		case XFER_MW_DMA_2:	set_ata2(0x69, 0x25); break;
+		case XFER_MW_DMA_1:	set_ata2(0x6b, 0x27); break;
+		case XFER_MW_DMA_0:	set_ata2(0xdf, 0x5f); break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	set_pio(0x23, 0x09, 0x25); break;
+		case XFER_PIO_3:	set_pio(0x27, 0x0d, 0x35); break;
+		case XFER_PIO_2:	set_pio(0x23, 0x26, 0x64); break;
+		case XFER_PIO_1:	set_pio(0x46, 0x29, 0xa4); break;
+		case XFER_PIO_0:	set_pio(0xfb, 0x2b, 0xac); break;
+		default:
+			;
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	pio = (pio == 5) ? 4 : pio;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdcnew_tune_chipset(drive, speed));
+}
+
+static void pdcnew_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+{
+	hwif->OUTB(0x0b, hwif->dma_vendor1);
+	return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= -1;
+	u8 cable		= 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			cable = pdcnew_new_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		default:
+			/* If its not one we know we should never
+			   arrive here.. */
+			BUG();
+	}
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+	}
+
+	if (drive->media != ide_disk)
+		return 0;
+	if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+		hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+		hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+	}
+
+	speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+
+	if (!(speed)) {
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdcnew_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void pdcnew_new_reset (ide_drive_t *drive)
+{
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk("PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+static void pdcnew_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdcnew_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdcnew_reset_host(hwif);
+	pdcnew_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdcnew_proc) {
+		pdcnew_proc = 1;
+		ide_pci_register_host_proc(&pdcnew_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->tuneproc  = &pdcnew_tune_drive;
+	hwif->quirkproc = &pdcnew_quirkproc;
+	hwif->speedproc = &pdcnew_new_tune_chipset;
+	hwif->resetproc = &pdcnew_new_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
+	if (!(hwif->udma_four))
+		hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				u8 irq = 0, irq2 = 0;
+				pci_read_config_byte(dev,
+					PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(findev,
+					PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					findev->irq = dev->irq;
+					pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				}
+				ide_setup_pci_devices(dev, findev, d);
+				return;
+			}
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+int __init pdcnew_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_PROMISE)
+		return 0;
+
+	for (d = pdcnew_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/pdc202xx_new.h b/drivers/ide/pci/pdc202xx_new.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx_new.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,343 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdcnew_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdcnew_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdcnew_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdcnew_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc;
+
+static int pdcnew_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcnew_procs[] __initdata = {
+	{
+		name:		"pdcnew",
+		set:		1,
+		get_info:	pdcnew_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdcnew(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+static unsigned int init_chipset_pdcnew(struct pci_dev *, const char *);
+static void init_hwif_pdc202new(ide_hwif_t *);
+static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcnew_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20268,
+		name:		"PDC20268",
+		init_setup:	init_setup_pdcnew,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20269,
+		name:		"PDC20269",
+		init_setup:	init_setup_pdcnew,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20270,
+		name:		"PDC20270",
+		init_setup:	init_setup_pdc20270,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20271,
+		name:		"PDC20271",
+		init_setup:	init_setup_pdcnew,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20275,
+		name:		"PDC20275",
+		init_setup:	init_setup_pdcnew,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20276,
+		name:		"PDC20276",
+		init_setup:	init_setup_pdc20276,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20277,
+		name:		"PDC20277",
+		init_setup:	init_setup_pdcnew,
+		init_chipset:	init_chipset_pdcnew,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202new,
+		init_dma:	init_dma_pdc202new,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Nru a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx_old.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,938 @@
+/*
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  Promise Ultra100 cards.
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_old.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	u32 bibma  = pci_resource_start(dev, 4);
+	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+	u8 hi = 0, lo = 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((u16)bibma + 0x02);
+	u8 c1	= inb_p((u16)bibma + 0x0a);
+
+	u8 sc11	= inb_p((u16)bibma + 0x11);
+	u8 sc1a	= inb_p((u16)bibma + 0x1a);
+	u8 sc1b	= inb_p((u16)bibma + 0x1b);
+	u8 sc1c	= inb_p((u16)bibma + 0x1c); 
+	u8 sc1d	= inb_p((u16)bibma + 0x1d);
+	u8 sc1e	= inb_p((u16)bibma + 0x1e);
+	u8 sc1f	= inb_p((u16)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "Ultra100"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "Ultra100 on M/B"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "FastTrak 66"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "Ultra66"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "Ultra33");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "Ultra Series"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+		(c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
+		(c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
+	p += sprintf(p, "DMA Mode:       %s           %s "
+			"         %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s "
+			"          %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
+#if 0
+	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+#endif
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdc202xx_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			return 1;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	pio = (pio == 5) ? 4 : pio;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdc202xx_tune_chipset(drive, speed));
+}
+
+static void pdc202xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+	return ((u8)(CIS & mask));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 drive_conf		= 0;
+	u8 mask			= hwif->channel ? 0x08 : 0x02;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 test1 = 0, test2 = 0, speed = -1;
+	u8 AP = 0, CLKSPD = 0, cable = 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			cable = pdc202xx_old_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk("%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		default:
+			BUG();
+	}
+
+	CLKSPD = hwif->INB(hwif->dma_master + 0x11);
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk("         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("%s reduced to Ultra33 mode.\n", drive->name);
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive->dn%2)].id) {
+				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
+					hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+				} else {
+					hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+			}
+		}
+	}
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	if (!(test1 & SYNC_ERRDY_EN)) {
+		if (drive->select.b.unit & 0x01) {
+			pci_read_config_byte(dev, drive_pci - 4, &test2);
+			if ((test2 & SYNC_ERRDY_EN) &&
+			    !(test1 & SYNC_ERRDY_EN)) {
+				pci_write_config_byte(dev, drive_pci,
+					test1|SYNC_ERRDY_EN);
+			}
+		} else {
+			pci_write_config_byte(dev, drive_pci,
+				test1|SYNC_ERRDY_EN);
+		}
+	}
+
+chipset_is_set:
+
+	if (drive->media == ide_disk) {
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (id->capability & 4)	/* IORDY_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (drive->media == ide_disk)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+	}
+
+	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+	if (!(speed)) {
+		/* restore original pci-config space */
+		pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		struct request *rq	= HWGROUP(drive)->rq;
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u32 high_16	= pci_resource_start(dev, 4);
+		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u32 word_count	= 0;
+		u8 clock = hwif->INB(high_16 + 0x11);
+
+		hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11);
+		word_count = (rq->nr_sectors << 8);
+		word_count = (rq->cmd == READ) ? word_count | 0x05000000 :
+						 word_count | 0x06000000;
+		hwif->OUTL(word_count, atapi_reg);
+	}
+	return __ide_dma_begin(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u32 high_16	= pci_resource_start(hwif->pci_dev, 4);
+		u32 atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock	= 0;
+
+		hwif->OUTL(0, atapi_reg); /* zero out extra */
+		clock = hwif->INB(high_16 + 0x11);
+		hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+	}
+	return __ide_dma_end(drive);
+}
+
+static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long high_16	= pci_resource_start(dev, 4);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8 sc1d			= hwif->INB((high_16 + 0x001d));
+
+	if (hwif->channel) {
+		if ((sc1d & 0x50) == 0x50)
+			goto somebody_else;
+		else if ((sc1d & 0x40) == 0x40)
+			return (dma_stat & 4) == 4;
+	} else {
+		if ((sc1d & 0x05) == 0x05)
+			goto somebody_else;
+		else if ((sc1d & 0x04) == 0x04)
+			return (dma_stat & 4) == 4;
+	}
+somebody_else:
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk("PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdc202xx_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdc202xx_reset_host(hwif);
+	pdc202xx_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 sc1f			= hwif->INB(high_16|0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+	} else {
+		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		ide_pci_register_host_proc(&pdc202xx_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	/*
+	 * software reset -  this is required because the bios
+	 * will set UDMA timing on if the hdd supports it. The
+	 * user may want to turn udma off. A bug in the pdc20262
+	 * is that it cannot handle a downgrade in timing from
+	 * UDMA to DMA. Disk accesses after issuing a set
+	 * feature command will result in errors. A software
+	 * reset leaves the timing registers intact,
+	 * but resets the drives.
+	 */
+#if 0
+	if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+		unsigned long high_16	= pci_resource_start(dev, 4);
+		byte udma_speed_flag	= inb(high_16 + 0x001f);
+		outb(udma_speed_flag | 0x10, high_16 + 0x001f);
+		mdelay(100);
+		outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		mdelay(2000);	/* 2 seconds ?! */
+	}
+
+#endif
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc  = &pdc202xx_tune_drive;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		hwif->busproc   = &pdc202xx_tristate;
+		hwif->resetproc = &pdc202xx_reset;
+	}
+
+	hwif->speedproc = &pdc202xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		if (!(hwif->udma_four))
+			hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+		hwif->ide_dma_begin = &pdc202xx_old_ide_dma_begin;
+		hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+	} 
+	hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+#if PDC202_DEBUG_CABLE
+	printk("%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */	
+}
+
+static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+	if (hwif->channel) {
+		ide_setup_dma(hwif, dmabase, 8);
+		return;
+	}
+
+	udma_speed_flag	= hwif->INB((dmabase|0x1f));
+	primary_mode	= hwif->INB((dmabase|0x1a));
+	secondary_mode	= hwif->INB((dmabase|0x1b));
+	printk("%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n", hwif->cds->name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+	if (!(udma_speed_flag & 1)) {
+		printk("%s: FORCING BURST BIT 0x%02x->0x%02x ",
+			hwif->cds->name, udma_speed_flag,
+			(udma_speed_flag|1));
+		hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+		printk("%sACTIVE\n",
+			(hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+	}
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk("%s: FORCING PRIMARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			primary_mode, (primary_mode|1));
+		hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+	}
+
+	if (!(secondary_mode & 1)) {
+		printk("%s: FORCING SECONDARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			secondary_mode, (secondary_mode|1));
+		hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+		u8 irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		/* 0xbc */
+		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev,
+				(PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+			printk("%s: pci-config space interrupt "
+				"mirror fixed.\n", d->name);
+		}
+	}
+
+#if 0
+        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+
+#if 0
+        {
+                u8 pri = 0, sec = 0;
+
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init pdc202xx_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_PROMISE)
+		return 0;
+
+	for (d = pdc202xx_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/pdc202xx_old.h b/drivers/ide/pci/pdc202xx_old.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdc202xx_old.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,326 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc;
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
+	{
+		name:		"pdc202xx",
+		set:		1,
+		get_info:	pdc202xx_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d);
+static void init_setup_pdc20265(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc202xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdc202xx(struct pci_dev *, const char *);
+static void init_hwif_pdc202xx(ide_hwif_t *);
+static void init_dma_pdc202xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdc202xx_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20246,
+		name:		"PDC20246",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		16,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20262,
+		name:		"PDC20262",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20263,
+		name:		"PDC20263",
+		init_setup:	init_setup_pdc202ata4,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20265,
+		name:		"PDC20265",
+		init_setup:	init_setup_pdc20265,
+		init_chipset:	init_chipset_pdc202xx,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		PCI_VENDOR_ID_PROMISE,
+		device:		PCI_DEVICE_ID_PROMISE_20267,
+		name:		"PDC20267",
+		init_setup:	init_setup_pdc202xx,
+		init_chipset:	init_chipset_pdc202xx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdc202xx,
+		init_dma:	init_dma_pdc202xx,
+		channels:	2,
+		autodma:	AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		enablebits:	{{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		bootable:	OFF_BOARD,
+		extra:		48,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Nru a/drivers/ide/pci/pdcadma.c b/drivers/ide/pci/pdcadma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdcadma.c	Sun Sep 15 19:20:14 2002
@@ -0,0 +1,152 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.01	June 21, 2001
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdcadma.h"
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc = 0;
+#define PDC_MAX_DEVS		5
+static struct pci_dev *pdc_devs[PDC_MAX_DEVS];
+static int n_pdc_devs;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc_devs; i++) {
+		struct pci_dev *dev	= pdc_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+
+		p += sprintf(p, "\n                                "
+			"PDC ADMA %04X Chipset.\n", dev->device);
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "PIO\n");
+
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * pdcadma_dma functions() initiates/aborts (U)DMA read/write
+ * operations on a drive.
+ */
+#if 0
+        int (*ide_dma_read)(ide_drive_t *drive);
+        int (*ide_dma_write)(ide_drive_t *drive);
+        int (*ide_dma_begin)(ide_drive_t *drive);
+        int (*ide_dma_end)(ide_drive_t *drive);
+        int (*ide_dma_check)(ide_drive_t *drive);
+        int (*ide_dma_on)(ide_drive_t *drive);
+        int (*ide_dma_off)(ide_drive_t *drive);
+        int (*ide_dma_off_quietly)(ide_drive_t *drive);
+        int (*ide_dma_test_irq)(ide_drive_t *drive);
+        int (*ide_dma_host_on)(ide_drive_t *drive);
+        int (*ide_dma_host_off)(ide_drive_t *drive);
+        int (*ide_dma_bad_drive)(ide_drive_t *drive);
+        int (*ide_dma_good_drive)(ide_drive_t *drive);
+        int (*ide_dma_count)(ide_drive_t *drive);
+        int (*ide_dma_verbose)(ide_drive_t *drive);
+        int (*ide_dma_retune)(ide_drive_t *drive);
+        int (*ide_dma_lostirq)(ide_drive_t *drive);
+        int (*ide_dma_timeout)(ide_drive_t *drive);
+
+#endif
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc_devs[n_pdc_devs++] = dev;
+
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		ide_pci_register_host_proc(&pdcadma_procs[0]);
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->autodma = 1;
+//	}
+
+	hwif->udma_four = 1;
+
+//	hwif->atapi_dma = 1;
+//	hwif->ultra_mask = 0x7f;
+//	hwif->mwdma_mask = 0x07;
+//	hwif->swdma_mask = 0x07;
+
+}
+
+static void __init init_dma_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+#if 0
+	ide_setup_dma(hwif, dmabase, 8);
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdcadma (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init pdcadma_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_PDC)
+		return 0;
+
+	for (d = pdcadma_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/pdcadma.h b/drivers/ide/pci/pdcadma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/pdcadma.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,56 @@
+#ifndef PDC_ADMA_H
+#define PDC_ADMA_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc;
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcadma_procs[] __initdata = {
+	{
+		name:		"pdcadma",
+		set:		1,
+		get_info:	pdcadma_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+static void init_hwif_pdcadma(ide_hwif_t *);
+static void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_PDC,
+		device:		PCI_DEVICE_ID_PDC_1841,
+		name:		"PDCADMA",
+		init_setup:	init_setup_pdcadma,
+		init_chipset:	init_chipset_pdcadma,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_pdcadma,
+		init_dma:	init_dma_pdcadma,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	OFF_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* PDC_ADMA_H */
diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/piix.c	Sun Sep 15 19:19:28 2002
@@ -0,0 +1,692 @@
+/*
+ *  linux/drivers/ide/piix.c		Version 0.40	August 18, 2002
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ *
+ *    ata-33/82371AB
+ *    ata-33/82371EB
+ *    ata-33/82801AB            ata-66/82801AA
+ *    00|00 udma 0              00|00 reserved
+ *    01|01 udma 1              01|01 udma 3
+ *    10|10 udma 2              10|10 udma 4
+ *    11|11 reserved            11|11 reserved
+ *
+ * 54 8421|8421    ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "piix.h"
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc = 0;
+#define PIIX_MAX_DEVS		5
+static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
+static int n_piix_devs;
+
+/**
+ *	piix_get_info		-	fill in /proc for PIIX ide
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the PIIX devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_piix_devs; i++) {
+		struct pci_dev *dev	= piix_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+	        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+		u8  c0 = 0, c1 = 0, reg54 = 0, reg55 = 0;
+		u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "\n                                Intel ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_INTEL_82801BA_8:
+			case PCI_DEVICE_ID_INTEL_82801BA_9:
+			case PCI_DEVICE_ID_INTEL_82801CA_10:
+			case PCI_DEVICE_ID_INTEL_82801CA_11:
+			case PCI_DEVICE_ID_INTEL_82801DB_11:
+			case PCI_DEVICE_ID_INTEL_82801E_11:
+				p += sprintf(p, "PIIX4 Ultra 100 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82372FB_1:
+			case PCI_DEVICE_ID_INTEL_82801AA_1:
+				p += sprintf(p, "PIIX4 Ultra 66 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82451NX:
+			case PCI_DEVICE_ID_INTEL_82801AB_1:
+			case PCI_DEVICE_ID_INTEL_82443MX_1:
+			case PCI_DEVICE_ID_INTEL_82371AB:
+				p += sprintf(p, "PIIX4 Ultra 33 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371SB_1:
+				p += sprintf(p, "PIIX3 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371MX:
+				p += sprintf(p, "MPIIX ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371FB_1:
+			case PCI_DEVICE_ID_INTEL_82371FB_0:
+			default:
+				p += sprintf(p, "PIIX ");
+				break;
+		}
+		p += sprintf(p, "Chipset.\n");
+
+		if (dev->device == PCI_DEVICE_ID_INTEL_82371MX)
+			continue;
+
+		pci_read_config_word(dev, 0x40, &reg40);
+		pci_read_config_word(dev, 0x42, &reg42);
+		pci_read_config_byte(dev, 0x44, &reg44);
+		pci_read_config_byte(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x4a, &reg4a);
+		pci_read_config_byte(dev, 0x4b, &reg4b);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_byte(dev, 0x55, &reg55);
+
+		psitre = (reg40 & 0x4000) ? 1 : 0;
+		ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb((unsigned short)bibma + 0x02);
+		c1 = inb((unsigned short)bibma + 0x0a);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s "
+				"            %s               %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s              %s "
+				"            %s               %s\n",
+				(reg48&0x01) ? "yes" : "no ",
+				(reg48&0x02) ? "yes" : "no ",
+				(reg48&0x04) ? "yes" : "no ",
+				(reg48&0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s "
+				"              %s                 %s\n",
+				((reg54&0x11) &&
+				 (reg55&0x10) && (reg4a&0x01)) ? "5" :
+				((reg54&0x11) && (reg4a&0x02)) ? "4" :
+				((reg54&0x11) && (reg4a&0x01)) ? "3" :
+				(reg4a&0x02) ? "2" :
+				(reg4a&0x01) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x22) &&
+				 (reg55&0x20) && (reg4a&0x10)) ? "5" :
+				((reg54&0x22) && (reg4a&0x20)) ? "4" :
+				((reg54&0x22) && (reg4a&0x10)) ? "3" :
+				(reg4a&0x20) ? "2" :
+				(reg4a&0x10) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x44) &&
+				 (reg55&0x40) && (reg4b&0x03)) ? "5" :
+				((reg54&0x44) && (reg4b&0x02)) ? "4" :
+				((reg54&0x44) && (reg4b&0x01)) ? "3" :
+				(reg4b&0x02) ? "2" :
+				(reg4b&0x01) ? "1" :
+				(reg4b&0x00) ? "0" : "X",
+				((reg54&0x88) &&
+				 (reg55&0x80) && (reg4b&0x30)) ? "5" :
+				((reg54&0x88) && (reg4b&0x20)) ? "4" :
+				((reg54&0x88) && (reg4b&0x10)) ? "3" :
+				(reg4b&0x20) ? "2" :
+				(reg4b&0x10) ? "1" :
+				(reg4b&0x00) ? "0" : "X");
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+
+		/*
+		 * FIXME.... Add configuration junk data....blah blah......
+		 */
+	}
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	piix_ratemask		-	compute rate mask for PIIX IDE
+ *	@drive: IDE drive to compute for
+ *
+ *	Returns the available modes for the PIIX IDE controller.
+ */
+ 
+static u8 piix_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode;
+
+	switch(dev->device) {
+		/* UDMA 100 capable */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+			mode = 3;
+			break;
+		/* UDMA 66 capable */
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+			mode = 2;
+			break;
+		/* UDMA 33 capable */
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			return 1;
+		/* Non UDMA capable (MWDMA2) */
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		default:
+			return 0;
+	}
+	
+	/*
+	 *	If we are UDMA66 capable fall back to UDMA33 
+	 *	if the drive cannot see an 80pin cable.
+	 */
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	piix_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+ 
+static u8 piix_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/**
+ *	piix_tune_drive		-	tune a drive attached to a PIIX
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode based upon  the settings done by AMI BIOS
+ *	(might be useful if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ *	piix_tune_chipset	-	tune a PIIX interface
+ *	@drive: IDE drive to tune
+ *	@xferspeed: speed to configure
+ *
+ *	Set a PIIX interface channel to the desired speeds. This involves
+ *	requires the right timing data into the PIIX configuration space
+ *	then setting the drive parameters appropriately
+ */
+ 
+static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed	= ide_rate_filter(piix_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg44, reg48, reg4a, reg54;
+	u8			reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if (!(reg4a & u_speed)) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag)) {
+				pci_write_config_word(dev, 0x54, reg54|v_flag);
+			}
+		} else {
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+/**
+ *	piix_config_drive_for_dma	-	configure drive for DMA
+ *	@drive: IDE drive to configure
+ *
+ *	Set up a PIIX interface channel for the best available speed.
+ *	We prefer UDMA if it is available and then MWDMA. If DMA is 
+ *	not available we switch to PIO and return 0. 
+ */
+ 
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) piix_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	piix_config_drive_xfer_rate	-	set up an IDE device
+ *	@drive: IDE drive to configure
+ *
+ *	Set up the PIIX interface for the best available speed on this
+ *	interface, preferring DMA to PIO.
+ */
+ 
+static int piix_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				if ((id->field_valid & 2) &&
+				    (!piix_config_drive_for_dma(drive)))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!piix_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!piix_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/**
+ *	init_chipset_piix	-	set up the PIIX chipset
+ *	@dev: PCI device to set up
+ *	@name: Name of the device
+ *
+ *	Initialize the PCI device as required. For the PIIX this turns
+ *	out to be nice and simple
+ */
+ 
+static unsigned int __init init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+        switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		{
+			unsigned int extra = 0;
+			pci_read_config_dword(dev, 0x54, &extra);
+			pci_write_config_dword(dev, 0x54, extra|0x400);
+		}
+		default:
+			break;
+	}
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	piix_devs[n_piix_devs++] = dev;
+
+	if (!piix_proc) {
+		piix_proc = 1;
+		ide_pci_register_host_proc(&piix_procs[0]);
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/**
+ *	init_hwif_piix		-	fill in the hwif for the PIIX
+ *	@hwif: IDE interface
+ *
+ *	Set up the ide_hwif_t for the PIIX interface according to the
+ *	capabilities of the hardware.
+ */
+ 
+static void __init init_hwif_piix (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	u8 reg54h = 0, reg55h = 0, ata66 = 0;
+	u8 mask = hwif->channel ? 0xc0 : 0x30;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+
+#ifndef CONFIG_IA64
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+		/* This is a painful system best to let it self tune for now */
+		return;
+	}
+
+	hwif->autodma = 0;
+	hwif->tuneproc = &piix_tune_drive;
+	hwif->speedproc = &piix_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82371MX:
+			hwif->mwdma_mask = 0x80;
+			hwif->swdma_mask = 0x80;
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+			hwif->ultra_mask = 0x80;
+			break;
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			hwif->ultra_mask = 0x07;
+			break;
+		default:
+			pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+			pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
+			ata66 = (reg54h & mask) ? 1 : 0;
+			break;
+	}
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+	hwif->ide_dma_check = &piix_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+/**
+ *	init_dma_piix		-	set up the PIIX DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA PCI base
+ *
+ *	Set up the DMA on the PIIX controller, providing a DMA base is
+ *	available. The PIIX follows the normal specs so we do nothing
+ *	magical here.
+ */
+
+static void __init init_dma_piix (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	init_setup_piix		-	callback for IDE initialize
+ *	@dev: PIIX PCI device
+ *	@d: IDE pci info
+ *
+ *	Enable the xp fixup for the PIIX controller and then perform
+ *	a standard ide PCI setup
+ */
+ 
+static void __init init_setup_piix (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	piix_scan_pcidev	-	Check for and initialize PIIX IDE
+ *	@dev: PCI device to check
+ *
+ *	Checks if the passed device is an Intel PIIX device. If so the
+ *	hardware is initialized and we return 1 to claim the device. If not
+ *	we return 0.
+ */
+ 
+int __init piix_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_INTEL)
+		return 0;
+
+	for (d = piix_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/piix.h b/drivers/ide/pci/piix.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/piix.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,269 @@
+#ifndef PIIX_H
+#define PIIX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define PIIX_DEBUG_DRIVE_INFO		0
+
+#define DISPLAY_PIIX_TIMINGS
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc;
+
+static int piix_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t piix_procs[] __initdata = {
+	{
+		name:		"piix",
+		set:		1,
+		get_info:	piix_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_piix(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_piix(struct pci_dev *, const char *);
+static void init_hwif_piix(ide_hwif_t *);
+static void init_dma_piix(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t piix_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82371FB_0,
+		name:		"PIIXa",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82371FB_1,
+		name:		"PIIXb",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82371MX,
+		name:		"MPIIX",
+		init_setup:	init_setup_piix,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82371SB_1,
+		name:		"PIIX3",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82371AB,
+		name:		"PIIX4",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801AB_1,
+		name:		"ICH0",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82443MX_1,
+		name:		"PIIX4",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801AA_1,
+		name:		"ICH",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82372FB_1,
+		name:		"PIIX4",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82451NX,
+		name:		"PIIX4",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801BA_9,
+		name:		"ICH2",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801BA_8,
+		name:		"ICH2M",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801CA_10,
+		name:		"ICH3M",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801CA_11,
+		name:		"ICH3",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801DB_11,
+		name:		"ICH4",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		PCI_DEVICE_ID_INTEL_82801E_11,
+		name:		"C-ICH",
+		init_setup:	init_setup_piix,
+		init_chipset:	init_chipset_piix,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_piix,
+		init_dma:	init_dma_piix,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		init_setup:	NULL,
+		bootable:	EOL,
+	}
+};
+
+#endif /* PIIX_H */
diff -Nru a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/rz1000.c	Sun Sep 15 19:19:30 2002
@@ -0,0 +1,80 @@
+/*
+ *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author:  mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for disabling the buggy read-ahead
+ *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ *  Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "rz1000.h"
+
+static void __init init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+	u16 reg;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->chipset = ide_rz1000;
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+		printk("%s: disabled chipset read-ahead "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	} else {
+		hwif->serialized = 1;
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk("%s: serialized, disabled unmasking "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	}
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_rz1000 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init rz1000_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_PCTECH)
+		return 0;
+
+	for (d = rz1000_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/rz1000.h b/drivers/ide/pci/rz1000.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/rz1000.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,48 @@
+#ifndef RZ100X_H
+#define RZ100X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_rz1000(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_rz1000(ide_hwif_t *);
+
+static ide_pci_device_t rz1000_chipsets[] __initdata = {
+{
+		vendor:		PCI_VENDOR_ID_PCTECH,
+		device:		PCI_DEVICE_ID_PCTECH_RZ1000,
+		name:		"RZ1000",
+		init_setup:	init_setup_rz1000,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_rz1000,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_PCTECH,
+		device:		PCI_DEVICE_ID_PCTECH_RZ1001,
+		name:		"RZ1001",
+		init_setup:	init_setup_rz1000,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_rz1000,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* RZ100X_H */
diff -Nru a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/serverworks.c	Sun Sep 15 19:19:28 2002
@@ -0,0 +1,786 @@
+/*
+ * linux/drivers/ide/serverworks.c		Version 0.6	05 April 2002
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
+ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "serverworks.h"
+
+static u8 svwks_revision = 0;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc = 0;
+#define SVWKS_MAX_DEVS		2
+static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
+static int n_svwks_devs;
+
+static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"ServerWorks OSB4/CSB5/CSB6\n");
+
+	for (i = 0; i < n_svwks_devs; i++) {
+		struct pci_dev *dev = svwks_devs[i];
+		u32 bibma = pci_resource_start(dev, 4);
+		u32 reg40, reg44;
+		u16 reg48, reg56;
+		u8  reg54, c0=0, c1=0;
+
+		pci_read_config_dword(dev, 0x40, &reg40);
+		pci_read_config_dword(dev, 0x44, &reg44);
+		pci_read_config_word(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_word(dev, 0x56, &reg56);
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((unsigned short)bibma + 0x02);
+		c1 = inb_p((unsigned short)bibma + 0x0a);
+
+		p += sprintf(p, "\n                            ServerWorks ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+				p += sprintf(p, "CSB6 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				p += sprintf(p, "CSB5 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+				p += sprintf(p, "OSB4 ");
+				break;
+			default:
+				p += sprintf(p, "%04x ", dev->device);
+				break;
+		}
+		p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);
+
+		p += sprintf(p, "------------------------------- "
+				"General Status "
+				"---------------------------------\n");
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled"
+				"                         %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s              %s"
+				"             %s               %s\n",
+			(reg54 & 0x01) ? "yes" : "no ",
+			(reg54 & 0x02) ? "yes" : "no ",
+			(reg54 & 0x04) ? "yes" : "no ",
+			(reg54 & 0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg56&0x0005)==0x0005)?"5":
+				((reg56&0x0004)==0x0004)?"4":
+				((reg56&0x0003)==0x0003)?"3":
+				((reg56&0x0002)==0x0002)?"2":
+				((reg56&0x0001)==0x0001)?"1":
+				((reg56&0x000F))?"?":"0",
+			((reg56&0x0050)==0x0050)?"5":
+				((reg56&0x0040)==0x0040)?"4":
+				((reg56&0x0030)==0x0030)?"3":
+				((reg56&0x0020)==0x0020)?"2":
+				((reg56&0x0010)==0x0010)?"1":
+				((reg56&0x00F0))?"?":"0",
+			((reg56&0x0500)==0x0500)?"5":
+				((reg56&0x0400)==0x0400)?"4":
+				((reg56&0x0300)==0x0300)?"3":
+				((reg56&0x0200)==0x0200)?"2":
+				((reg56&0x0100)==0x0100)?"1":
+				((reg56&0x0F00))?"?":"0",
+			((reg56&0x5000)==0x5000)?"5":
+				((reg56&0x4000)==0x4000)?"4":
+				((reg56&0x3000)==0x3000)?"3":
+				((reg56&0x2000)==0x2000)?"2":
+				((reg56&0x1000)==0x1000)?"1":
+				((reg56&0xF000))?"?":"0");
+		p += sprintf(p, "DMA enabled:    %s                %s"
+				"               %s                 %s\n",
+			((reg44&0x00002000)==0x00002000)?"2":
+				((reg44&0x00002100)==0x00002100)?"1":
+				((reg44&0x00007700)==0x00007700)?"0":
+				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
+			((reg44&0x00000020)==0x00000020)?"2":
+				((reg44&0x00000021)==0x00000021)?"1":
+				((reg44&0x00000077)==0x00000077)?"0":
+				((reg44&0x000000FF)==0x000000FF)?"X":"?",
+			((reg44&0x20000000)==0x20000000)?"2":
+				((reg44&0x21000000)==0x21000000)?"1":
+				((reg44&0x77000000)==0x77000000)?"0":
+				((reg44&0xFF000000)==0xFF000000)?"X":"?",
+			((reg44&0x00200000)==0x00200000)?"2":
+				((reg44&0x00210000)==0x00210000)?"1":
+				((reg44&0x00770000)==0x00770000)?"0":
+				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+
+		p += sprintf(p, "PIO  enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg40&0x00002000)==0x00002000)?"4":
+				((reg40&0x00002200)==0x00002200)?"3":
+				((reg40&0x00003400)==0x00003400)?"2":
+				((reg40&0x00004700)==0x00004700)?"1":
+				((reg40&0x00005D00)==0x00005D00)?"0":"?",
+			((reg40&0x00000020)==0x00000020)?"4":
+				((reg40&0x00000022)==0x00000022)?"3":
+				((reg40&0x00000034)==0x00000034)?"2":
+				((reg40&0x00000047)==0x00000047)?"1":
+				((reg40&0x0000005D)==0x0000005D)?"0":"?",
+			((reg40&0x20000000)==0x20000000)?"4":
+				((reg40&0x22000000)==0x22000000)?"3":
+				((reg40&0x34000000)==0x34000000)?"2":
+				((reg40&0x47000000)==0x47000000)?"1":
+				((reg40&0x5D000000)==0x5D000000)?"0":"?",
+			((reg40&0x00200000)==0x00200000)?"4":
+				((reg40&0x00220000)==0x00220000)?"3":
+				((reg40&0x00340000)==0x00340000)?"2":
+				((reg40&0x00470000)==0x00470000)?"1":
+				((reg40&0x005D0000)==0x005D0000)?"0":"?");
+
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 svwks_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev     = HWIF(drive)->pci_dev;
+	u8 mode;
+
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		u32 reg = 0;
+		if (isa_dev)
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			
+		/*
+		 *	Don't enable UDMA on disk devices for the moment
+		 */
+		if(drive->media == ide_disk)
+			return 0;
+		/* Check the OSB4 DMA33 enable bit */
+		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+		return 1;
+	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+		u8 btr = 0;
+		pci_read_config_byte(dev, 0x5A, &btr);
+		mode = btr;
+		if (!eighty_ninty_three(drive))
+			mode = min(mode, (u8)1);
+	}
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		mode = 2;
+	return mode;
+}
+
+static u8 svwks_csb_check (struct pci_dev *dev)
+{
+	switch (dev->device) {
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+	u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
+	u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
+	u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(svwks_ratemask(drive), xferspeed);
+	u8 pio			= ide_get_best_pio_mode(drive, 255, 5, NULL);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 csb5			= svwks_csb_check(dev);
+	u8 ultra_enable		= 0, ultra_timing = 0;
+	u8 dma_timing		= 0, pio_timing = 0;
+	u16 csb5_pio		= 0;
+
+	pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+	pci_read_config_word(dev, 0x4A, &csb5_pio);
+	pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+		if (!drive->init_speed) {
+			u8 dma_stat = hwif->INB(hwif->dma_status);
+
+dma_pio:
+			if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
+			    ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
+				drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
+				return 0;
+			} else if ((dma_timing) &&
+				   ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
+				u8 dmaspeed = dma_timing;
+
+				dma_timing &= ~0xFF;
+				if ((dmaspeed & 0x20) == 0x20)
+					dmaspeed = XFER_MW_DMA_2;
+				else if ((dmaspeed & 0x21) == 0x21)
+					dmaspeed = XFER_MW_DMA_1;
+				else if ((dmaspeed & 0x77) == 0x77)
+					dmaspeed = XFER_MW_DMA_0;
+				else
+					goto dma_pio;
+				drive->current_speed = drive->init_speed = dmaspeed;
+				return 0;
+			} else if (pio_timing) {
+				u8 piospeed = pio_timing;
+
+				pio_timing &= ~0xFF;
+				if ((piospeed & 0x20) == 0x20)
+					piospeed = XFER_PIO_4;
+				else if ((piospeed & 0x22) == 0x22)
+					piospeed = XFER_PIO_3;
+				else if ((piospeed & 0x34) == 0x34)
+					piospeed = XFER_PIO_2;
+				else if ((piospeed & 0x47) == 0x47)
+					piospeed = XFER_PIO_1;
+				else if ((piospeed & 0x5d) == 0x5d)
+					piospeed = XFER_PIO_0;
+				else
+					goto oem_setup_failed;
+				drive->current_speed = drive->init_speed = piospeed;
+				return 0;
+			}
+		}
+	}
+
+oem_setup_failed:
+
+	pio_timing	&= ~0xFF;
+	dma_timing	&= ~0xFF;
+	ultra_timing	&= ~(0x0F << (4*unit));
+	ultra_enable	&= ~(0x01 << drive->dn);
+	csb5_pio	&= ~(0x0F << (4*drive->dn));
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pio_timing |= pio_modes[speed - XFER_PIO_0];
+			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
+			break;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			pio_timing |= pio_modes[pio];
+			csb5_pio   |= (pio << (4*drive->dn));
+			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+			break;
+
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
+			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+			ultra_enable |= (0x01 << drive->dn);
+#endif
+		default:
+			break;
+	}
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
+	if (csb5)
+		pci_write_config_word(dev, 0x4A, csb5_pio);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+	pci_write_config_byte(dev, 0x54, ultra_enable);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+	u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+	u8 timing, speed, pio;
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio > 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0)
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	else
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 :
+			   (drive->id->tPIO & 2) ? 0x02 :
+			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+	drive->current_speed = speed;
+}
+
+static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+
+	if (!(speed))
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	(void) svwks_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto no_dma_set;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive);
+		//	hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int svwks_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if ((dma_stat & 1) && drive->media == ide_disk)
+	{
+		printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+		printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+		printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+		/* Panic might sys_sync -> death by corrupt disk */
+		printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+		while(1)
+			cpu_relax();
+	}
+	return __ide_dma_end(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
+{
+	unsigned int reg;
+	u8 btr;
+
+	/* save revision id to determine DMA capability */
+	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			if(!(reg & 0x00004000))
+				printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name);
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
+
+	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+//		u32 pioreg = 0, dmareg = 0;
+
+		/* Third Channel Test */
+		if (!(PCI_FUNC(dev->devfn) & 1)) {
+#if 1
+			struct pci_dev * findev = NULL;
+			u32 reg4c = 0;
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+			if (findev) {
+				pci_read_config_dword(findev, 0x4C, &reg4c);
+				reg4c &= ~0x000007FF;
+				reg4c |=  0x00000040;
+				reg4c |=  0x00000020;
+				pci_write_config_dword(findev, 0x4C, reg4c);
+			}
+#endif
+			outb_p(0x06, 0x0c00);
+			dev->irq = inb_p(0x0c01);
+#if 0
+			/* WE need to figure out how to get the correct one */
+			printk("%s: interrupt %d\n", name, dev->irq);
+			if (dev->irq != 0x0B)
+				dev->irq = 0x0B;
+#endif
+#if 0
+			printk("%s: device class (0x%04x)\n",
+				name, dev->class);
+#else
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				dev->class &= ~0x000F0F00;
+		//		dev->class |= ~0x00000400;
+				dev->class |= ~0x00010100;
+				/**/
+			}
+#endif
+		} else {
+			struct pci_dev * findev = NULL;
+			u8 reg41 = 0;
+
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+					PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+			if (findev) {
+				pci_read_config_byte(findev, 0x41, &reg41);
+				reg41 &= ~0x40;
+				pci_write_config_byte(findev, 0x41, reg41);
+			}
+			/*
+			 * This is a device pin issue on CSB6.
+			 * Since there will be a future raid mode,
+			 * early versions of the chipset require the
+			 * interrupt pin to be set, and it is a compatablity
+			 * mode issue.
+			 */
+			dev->irq = 0;
+		}
+//		pci_read_config_dword(dev, 0x40, &pioreg)
+//		pci_write_config_dword(dev, 0x40, 0x99999999);
+//		pci_read_config_dword(dev, 0x44, &dmareg);
+//		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 * 	00 : legacy
+		 * 	01 : udma2
+		 * 	10 : udma2/udma4
+		 * 	11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		if (!(PCI_FUNC(dev->devfn) & 1))
+			btr |= 0x2;
+		else
+			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
+	}
+
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+	svwks_devs[n_svwks_devs++] = dev;
+
+	if (!svwks_proc) {
+		svwks_proc = 1;
+		ide_pci_register_host_proc(&svwks_procs[0]);
+	}
+#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+
+	return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+//	struct pci_dev *dev = hwif->pci_dev;
+//	return 0;
+	return 1;
+}
+
+/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
+ * of the subsystem device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set   = secondary IDE channel has 80-pin cable.
+ * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+ * Bit 14 set   = primary IDE channel has 80-pin cable.
+ */
+static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
+	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+		return 1;
+
+	/* Server Works */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+		return ata66_svwks_svwks (hwif);
+	
+	/* Dell PowerEdge */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+		return ata66_svwks_dell (hwif);
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
+	return 0;
+}
+
+#undef CAN_SW_DMA
+static void __init init_hwif_svwks (ide_hwif_t *hwif)
+{
+	u8 dma_stat = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &svwks_tune_drive;
+	hwif->speedproc = &svwks_tune_chipset;
+
+	hwif->atapi_dma = 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ultra_mask = 0x3f;
+
+	hwif->mwdma_mask = 0x07;
+#ifdef CAN_SW_DMA
+	hwif->swdma_mask = 0x07;
+#endif /* CAN_SW_DMA */
+
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ide_dma_end = &svwks_ide_dma_end;
+	else if (!(hwif->udma_four))
+		hwif->udma_four = ata66_svwks(hwif);
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	dma_stat = hwif->INB(hwif->dma_status);
+	hwif->drives[0].autodma = (dma_stat & 0x20);
+	hwif->drives[1].autodma = (dma_stat & 0x40);
+	hwif->drives[0].autotune = (!(dma_stat & 0x20));
+	hwif->drives[1].autotune = (!(dma_stat & 0x40));
+//	hwif->drives[0].autodma = hwif->autodma;
+//	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+		return;
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if (!(PCI_FUNC(dev->devfn) & 1)) {
+		d->bootable = NEVER_BOARD;
+		if (dev->resource[0].start == 0x01f1)
+			d->bootable = ON_BOARD;
+	} else {
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+			return;
+	}
+#if 0
+	if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+             (!(PCI_FUNC(dev->devfn) & 1)))
+		d->autodma = AUTODMA;
+#endif
+
+	d->channels = (((d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+			(d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+		       (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+
+	ide_setup_pci_device(dev, d);
+}
+
+int __init serverworks_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_SERVERWORKS)
+		return 0;
+
+	for (d = serverworks_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+ 
diff -Nru a/drivers/ide/pci/serverworks.h b/drivers/ide/pci/serverworks.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/serverworks.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,105 @@
+
+#ifndef SERVERWORKS_H
+#define SERVERWORKS_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef SVWKS_DEBUG_DRIVE_INFO
+
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+#define DISPLAY_SVWKS_TIMINGS	1
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc;
+
+static int svwks_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t svwks_procs[] __initdata = {
+{
+		name:		"svwks",
+		set:		1,
+		get_info:	svwks_get_info,
+		parent:		NULL,
+	},
+};
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_svwks(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_csb6(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_svwks(struct pci_dev *, const char *);
+static void init_hwif_svwks(ide_hwif_t *);
+static void init_dma_svwks(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t serverworks_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_SERVERWORKS,
+		device:		PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		name:		"SvrWks OSB4",
+		init_setup:	init_setup_svwks,
+		init_chipset:	init_chipset_svwks,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_svwks,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_SERVERWORKS,
+		device:		PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		name:		"SvrWks CSB5",
+		init_setup:	init_setup_svwks,
+		init_chipset:	init_chipset_svwks,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_svwks,
+		init_dma:	init_dma_svwks,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_SERVERWORKS,
+		device:		PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
+		name:		"SvrWks CSB6",
+		init_setup:	init_setup_csb6,
+		init_chipset:	init_chipset_svwks,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_svwks,
+		init_dma:	init_dma_svwks,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_SERVERWORKS,
+		device:		PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
+		name:		"SvrWks CSB6",
+		init_setup:	init_setup_csb6,
+		init_chipset:	init_chipset_svwks,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_svwks,
+		init_dma:	init_dma_svwks,
+		channels:	1,	/* 2 */
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SERVERWORKS_H */
diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/siimage.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,861 @@
+/*
+ * linux/drivers/ide/siimage.c		Version 1.00	May 9, 2002
+ *
+ * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "siimage.h"
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 siimage_proc = 0;
+#define SIIMAGE_MAX_DEVS		5
+static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];
+static int n_siimage_devs;
+
+static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p		= buf;
+	u8 mmio		= (dev->driver_data != NULL) ? 1 : 0;
+	u32 bmdma	= (mmio) ? ((u32) dev->driver_data) :
+				    (pci_resource_start(dev, 4));
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
+	if (mmio)
+		p += sprintf(p, "MMIO Base 0x%08x\n", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%08x\n", (mmio)?"MMIO":"BM", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%08x\n", (mmio)?"MMIO":"BM", bmdma+8);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	return (char *)p;
+}
+
+static int siimage_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u16 i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_siimage_devs; i++) {
+		struct pci_dev *dev	= siimage_devs[i];
+		p = print_siimage_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte siimage_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode	= 0, scsc = 0;
+
+	if (hwif->mmio)
+		scsc = hwif->INB(HWIFADDR(0x4A));
+	else
+		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_SII_3112:
+			return 4;
+		case PCI_DEVICE_ID_SII_680:
+			if ((scsc & 0x10) == 0x10)	/* 133 */
+				mode = 4;
+			else if ((scsc & 0x30) == 0x00)	/* 100 */
+				mode = 3;
+			else if ((scsc & 0x20) == 0x20)	/* 66 eek */
+				BUG();	// mode = 2;
+			break;
+		default:	return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static byte siimage_taskfile_timing (ide_hwif_t *hwif)
+{
+	u16 timing	= 0x328a;
+
+	if (hwif->mmio)
+		timing = hwif->INW(SELADDR(2));
+	else
+		pci_read_config_word(hwif->pci_dev, SELREG(2), &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 speedt		= 0;
+	u8 unit			= drive->select.b.unit;
+
+	if (hwif->mmio)
+		speedt = hwif->INW(SELADDR(0x04|(unit<<unit)));
+	else
+		pci_read_config_word(dev, SELADDR(0x04|(unit<<unit)), &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(siimage_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	if (hwif->mmio)
+		hwif->OUTW(speedt, SELADDR(0x04|(unit<<unit)));
+	else
+		pci_write_config_word(dev, SELADDR(0x04|(unit<<unit)), speedt);
+}
+
+static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
+	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	siimage_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	config_siimage_chipset_for_pio(drive, set_speed);
+}
+
+static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 ultra = 0, multi	= 0;
+	u8 mode = 0, unit	= drive->select.b.unit;
+	u8 speed	= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
+				    ((hwif->mmio) ? 0xF4 : 0x84) :
+				    ((hwif->mmio) ? 0xB4 : 0x80));
+
+	if (hwif->mmio) {
+		scsc = hwif->INB(HWIFADDR(0x4A));
+		mode = hwif->INB(HWIFADDR(addr_mask));
+		multi = hwif->INW(SELADDR(0x08|(unit<<unit)));
+		ultra = hwif->INW(SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, HWIFADDR(0x8A), &scsc);
+		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), &multi);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), &ultra);
+	}
+
+	mode &= ~((unit) ? 0x30 : 0x03);
+	ultra &= ~0x3F;
+	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+	scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc;
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			siimage_tuneproc(drive, (speed - XFER_PIO_0));
+			mode |= ((unit) ? 0x10 : 0x01);
+			break;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			multi = dma[speed - XFER_MW_DMA_0];
+			mode |= ((unit) ? 0x20 : 0x02);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			multi = dma[2];
+			ultra |= ((scsc) ? (ultra5[speed - XFER_UDMA_0]) :
+					   (ultra6[speed - XFER_UDMA_0]));
+			mode |= ((unit) ? 0x30 : 0x03);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		default:
+			return 1;
+	}
+
+	if (hwif->mmio) {
+		hwif->OUTB(mode, HWIFADDR(addr_mask));
+		hwif->OUTW(multi, SELADDR(0x08|(unit<<unit)));
+		hwif->OUTW(ultra, SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), multi);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), ultra);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
+
+	config_chipset_for_pio(drive, (!(speed)));
+
+	if ((!(speed)))
+		return 0;
+
+	if (HWIF(drive)->speedproc(drive, speed))
+		return 0;
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int siimage_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		if (!(hwif->atapi_dma))
+			goto fast_ata_pio;
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if ((id->field_valid & 4) && siimage_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_altstat		= 0;
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 4) == 4)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat)),
+	    ((dma_altstat & 8) == 8))
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
+{
+#ifdef SIIMAGE_VIRTUAL_DMAPIO
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 count		= (rq->nr_sectors * SECTOR_SIZE);
+	u32 rcount		= 0;
+
+	hwif->OUTL(count, SELADDR(0x1C));
+	rcount = hwif->INL(SELADDR(0x1C));
+
+	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
+		drive->name, count, rcount, rq->nr_sectors);
+
+#endif /* SIIMAGE_VIRTUAL_DMAPIO */
+	return __ide_dma_count(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (SATA_ERROR_REG) {
+		u32 ext_stat = hwif->INL(HWIFADDR(0x10));
+		u8 watchdog = 0;
+		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+			u32 sata_error = hwif->INL(SATA_ERROR_REG);
+			hwif->OUTL(sata_error, SATA_ERROR_REG);
+			watchdog = (sata_error & 0x00680000) ? 1 : 0;
+#if 1
+			printk("%s: sata_error = 0x%08x, "
+				"watchdog = %d, %s\n",
+				drive->name, sata_error, watchdog,
+				__FUNCTION__);
+#endif
+
+		} else {
+			watchdog = (ext_stat & 0x8000) ? 1 : 0;
+		}
+		ext_stat >>= 16;
+
+		if (!(ext_stat & 0x0404) && !watchdog)
+			return 0;
+	}
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((hwif->INB(SELADDR(1)) & 8) == 8)
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive)
+{
+	int temp = __ide_dma_verbose(drive);
+#if 0
+	drive->using_dma = 0;
+#endif
+	return temp;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static int siimage_busproc (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 stat_config		= 0;
+
+	if (hwif->mmio) {
+		stat_config = hwif->INL(SELADDR(0));
+	} else
+		pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config);
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+	return 0;
+}
+
+static int siimage_reset_poll (ide_drive_t *drive)
+{
+	if (SATA_STATUS_REG) {
+		ide_hwif_t *hwif	= HWIF(drive);
+
+		if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+			printk("%s: reset phy dead, status=0x%08x\n",
+				hwif->name, hwif->INL(SATA_STATUS_REG));
+			HWGROUP(drive)->poll_timeout = 0;
+#if 0
+			drive->failures++;
+			return ide_stopped;
+#else
+			return ide_started;
+#endif
+			return 1;
+		}
+		return 0;
+	} else {
+		return 0;
+	}
+}
+
+static void siimage_pre_reset (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		drive->special.b.set_geometry = 0;
+		drive->special.b.recalibrate = 0;
+	}
+}
+
+static void siimage_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 reset		= 0;
+
+	if (hwif->mmio) {
+		reset = hwif->INB(SELADDR(0));
+		hwif->OUTB((reset|0x03), SELADDR(0));
+		udelay(25);
+		hwif->OUTB(reset, SELADDR(0));
+		(void) hwif->INB(SELADDR(0));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03);
+		udelay(25);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset);
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+	}
+
+	if (SATA_STATUS_REG) {
+		u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+		printk("%s: reset phy, status=0x%08x, %s\n",
+			hwif->name, sata_stat, __FUNCTION__);
+		if (!(sata_stat)) {
+			printk("%s: reset phy dead, status=0x%08x\n",
+				hwif->name, sata_stat);
+			drive->failures++;
+		}
+	}
+
+}
+
+static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_SII_3112)
+		goto sata_skip;
+
+	printk("%s: BASE CLOCK ", name);
+	clocking &= ~0x0C;
+	switch(clocking) {
+		case 0x03: printk("DISABLED !\n"); break;
+		case 0x02: printk("== 2X PCI \n"); break;
+		case 0x01: printk("== 133 \n"); break;
+		case 0x00: printk("== 100 \n"); break;
+		default:
+			BUG();
+	}
+
+sata_skip:
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+	siimage_devs[n_siimage_devs++] = dev;
+
+	if (!siimage_proc) {
+		siimage_proc = 1;
+		ide_pci_register_host_proc(&siimage_procs[0]);
+	}
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */
+}
+
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+{
+	u32 bar5	= pci_resource_start(dev, 5);
+	u32 end5	= pci_resource_end(dev, 5);
+	u8 tmpbyte	= 0;
+	u32 addr;
+	void *ioaddr;
+
+	ioaddr = ioremap_nocache(bar5, (end5 - bar5));
+
+	if (ioaddr == NULL)
+		return 0;
+
+	pci_set_master(dev);
+	addr = (u32) ioaddr;
+	pci_set_drvdata(dev, (void *) addr);
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		sii_outl(0, DEVADDR(0x148));
+		sii_outl(0, DEVADDR(0x1C8));
+	}
+
+	sii_outb(0, DEVADDR(0xB4));
+	sii_outb(0, DEVADDR(0xF4));
+	tmpbyte = sii_inb(DEVADDR(0x4A));
+
+	switch(tmpbyte) {
+		case 0x01:
+			sii_outb(tmpbyte|0x10, DEVADDR(0x4A));
+			tmpbyte = sii_inb(DEVADDR(0x4A));
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			sii_outb(tmpbyte & ~0x20, DEVADDR(0x4A));
+			tmpbyte = sii_inb(DEVADDR(0x4A));
+		case 0x11:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			sii_outb(tmpbyte, DEVADDR(0x4A));
+			break;
+	}
+	
+	sii_outb(0x72, DEVADDR(0xA1));
+	sii_outw(0x328A, DEVADDR(0xA2));
+	sii_outl(0x62DD62DD, DEVADDR(0xA4));
+	sii_outl(0x43924392, DEVADDR(0xA8));
+	sii_outl(0x40094009, DEVADDR(0xAC));
+	sii_outb(0x72, DEVADDR(0xE1));
+	sii_outw(0x328A, DEVADDR(0xE2));
+	sii_outl(0x62DD62DD, DEVADDR(0xE4));
+	sii_outl(0x43924392, DEVADDR(0xE8));
+	sii_outl(0x40094009, DEVADDR(0xEC));
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		sii_outl(0xFFFF0000, DEVADDR(0x108));
+		sii_outl(0xFFFF0000, DEVADDR(0x188));
+		sii_outl(0x00680000, DEVADDR(0x148));
+		sii_outl(0x00680000, DEVADDR(0x1C8));
+	}
+
+	tmpbyte = sii_inb(DEVADDR(0x4A));
+
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 1;
+}
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev	= 0;
+	u8 tmpbyte	= 0;
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+	u8 BA5_EN	= 0;
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+        class_rev &= 0xff;
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);	
+
+#ifdef CONFIG_TRY_MMIO_SIIMAGE
+	pci_read_config_byte(dev, 0x8A, &BA5_EN);
+	if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
+		if (setup_mmio_siimage(dev, name)) {
+			return 0;
+		}
+	}
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	switch(tmpbyte) {
+		case 0x00:
+		case 0x01:
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x30:
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x10:
+		case 0x11:
+		case 0x20:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			pci_write_config_byte(dev, 0x8A, tmpbyte);
+			break;
+	}
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0xA1, 0x72);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xA8, 0x43924392);
+	pci_write_config_dword(dev, 0xAC, 0x40094009);
+	pci_write_config_byte(dev, 0xB1, 0x72);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xB8, 0x43924392);
+	pci_write_config_dword(dev, 0xBC, 0x40094009);
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 0;
+}
+
+static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 addr		= (u32) pci_get_drvdata(hwif->pci_dev);
+	u8 ch			= hwif->channel;
+//	u16 i			= 0;
+	hw_regs_t hw;
+
+	hwif->OUTB  = sii_outb;
+	hwif->OUTW  = sii_outw;
+	hwif->OUTL  = sii_outl;
+	hwif->OUTSW = sii_outsw;
+	hwif->OUTSL = sii_outsl;
+	hwif->INB   = sii_inb;
+	hwif->INW   = sii_inw;
+	hwif->INL   = sii_inl;
+	hwif->INSW  = sii_insw;
+	hwif->INSL  = sii_insl;
+
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+#if 1
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xD0 : 0x90);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xD1 : 0x91);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xD2 : 0x92);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xD3 : 0x93);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xD4 : 0x94);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xD5 : 0x95);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xD6 : 0x96);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xD7 : 0x97);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xC0 : 0x80);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xC1 : 0x81);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xC2 : 0x82);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xC3 : 0x83);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xC4 : 0x84);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xC5 : 0x85);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xC6 : 0x86);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xC7 : 0x87);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#else
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#endif
+
+#if 0
+	printk("%s: ", hwif->name);
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i));
+	printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i));
+#endif
+
+	hw.io_ports[IDE_IRQ_OFFSET]	= 0;
+
+        if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		hw.sata_scr[SATA_STATUS_OFFSET]	= DEVADDR((ch) ? 0x184 : 0x104);
+		hw.sata_scr[SATA_ERROR_OFFSET]	= DEVADDR((ch) ? 0x188 : 0x108);
+		hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100);
+		hw.sata_misc[SATA_MISC_OFFSET]	= DEVADDR((ch) ? 0x1C0 : 0x140);
+		hw.sata_misc[SATA_PHY_OFFSET]	= DEVADDR((ch) ? 0x1C4 : 0x144);
+		hw.sata_misc[SATA_IEN_OFFSET]	= DEVADDR((ch) ? 0x1C8 : 0x148);
+	}
+
+	hw.priv				= (void *) addr;
+//	hw.priv				= pci_get_drvdata(hwif->pci_dev);
+	hw.irq				= hwif->pci_dev->irq;
+//	hw.iops				= siimage_iops;
+
+	memcpy(&hwif->hw, &hw, sizeof(hw));
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr));
+		memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc));
+	}
+
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+        hwif->addressing = 1;
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+	hwif->irq			= hw.irq;
+	hwif->hwif_data			= pci_get_drvdata(hwif->pci_dev);
+
+#ifdef SIIMAGE_LARGE_DMA
+	hwif->dma_base			= DEVADDR((ch) ? 0x18 : 0x10);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_prdtable		= (hwif->dma_base2 + 4);
+#else /* ! SIIMAGE_LARGE_DMA */
+	hwif->dma_base			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x18 : 0x10);
+#endif /* SIIMAGE_LARGE_DMA */
+	hwif->mmio			= 1;
+}
+
+static void __init init_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 class_rev		= 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->rqsize = 128;
+	if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev)))
+		hwif->rqsize = 16;
+
+	if (dev->driver_data == NULL)
+		return;
+	init_mmio_iops_siimage(hwif);
+}
+
+static unsigned int __init ata66_siimage (ide_hwif_t *hwif)
+{
+	if (hwif->pci_dev->driver_data == NULL) {
+		u8 ata66 = 0;
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66);
+		return (ata66 & 0x01) ? 1 : 0;
+	}
+#ifndef CONFIG_TRY_MMIO_SIIMAGE
+	if (hwif->mmio) BUG();
+#endif /* CONFIG_TRY_MMIO_SIIMAGE */
+
+	return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0;
+}
+
+static void __init init_hwif_siimage (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->busproc   = &siimage_busproc;
+	hwif->resetproc = &siimage_reset;
+	hwif->speedproc = &siimage_tune_chipset;
+	hwif->tuneproc	= &siimage_tuneproc;
+	hwif->reset_poll = &siimage_reset_poll;
+	hwif->pre_reset = &siimage_pre_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112)
+		hwif->atapi_dma = 1;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &siimage_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_siimage(hwif);
+
+	if (hwif->mmio) {
+		hwif->ide_dma_count = &siimage_mmio_ide_dma_count;
+		hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
+		hwif->ide_dma_verbose = &siimage_mmio_ide_dma_verbose;
+	} else {
+		hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
+	}
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_siimage (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init siimage_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_CMD)
+		return 0;
+
+	for (d = siimage_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/siimage.h b/drivers/ide/pci/siimage.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/siimage.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,153 @@
+#ifndef SIIMAGE_H
+#define SIIMAGE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_SIIMAGE_TIMINGS
+
+#define CONFIG_TRY_MMIO_SIIMAGE
+//#undef CONFIG_TRY_MMIO_SIIMAGE
+#undef SIIMAGE_VIRTUAL_DMAPIO
+#undef SIIMAGE_BUFFERED_TASKFILE
+#undef SIIMAGE_LARGE_DMA
+
+#if 0
+typedef struct ide_io_ops_s siimage_iops {
+
+}
+#endif
+
+#define SII_DEBUG 0
+
+#if SII_DEBUG
+#define siiprintk(x...)	printk(x)
+#else
+#define siiprintk(x...)
+#endif
+
+#define ADJREG(B,R)	((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio)))))
+#define SELREG(R)	ADJREG((0xA0),(R))
+#define SELADDR(R)	((((u32)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
+#define HWIFADDR(R)	((((u32)hwif->hwif_data)*(hwif->mmio))|(R))
+#define DEVADDR(R)	(((u32) pci_get_drvdata(dev))|(R))
+
+
+inline u8 sii_inb (u32 port)
+{
+	return (u8) readb(port);
+}
+
+inline u16 sii_inw (u32 port)
+{
+	return (u16) readw(port);
+}
+
+inline void sii_insw (u32 port, void *addr, u32 count)
+{
+	while (count--) { *(u16 *)addr = readw(port); addr += 2; }
+}
+
+inline u32 sii_inl (u32 port)
+{
+	return (u32) readl(port);
+}
+
+inline void sii_insl (u32 port, void *addr, u32 count)
+{
+	sii_insw(port, addr, (count)<<1);
+//	while (count--) { *(u32 *)addr = readl(port); addr += 4; }
+}
+
+inline void sii_outb (u8 addr, u32 port)
+{
+	writeb(addr, port);
+}
+
+inline void sii_outw (u16 addr, u32 port)
+{
+	writew(addr, port);
+}
+
+inline void sii_outsw (u32 port, void *addr, u32 count)
+{
+	while (count--) { writew(*(u16 *)addr, port); addr += 2; }
+}
+
+inline void sii_outl (u32 addr, u32 port)
+{
+	writel(addr, port);
+}
+
+inline void sii_outsl (u32 port, void *addr, u32 count)
+{
+	sii_outsw(port, addr, (count)<<1);
+//	while (count--) { writel(*(u32 *)addr, port); addr += 4; }
+}
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char * print_siimage_get_info(char *, struct pci_dev *, int);
+static int siimage_get_info(char *, char **, off_t, int);
+
+static u8 siimage_proc;
+
+static ide_pci_host_proc_t siimage_procs[] __initdata = {
+	{
+		name:		"siimage",
+		set:		1,
+		get_info:	siimage_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */	
+
+static void init_setup_siimage(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_siimage(struct pci_dev *, const char *);
+static void init_iops_siimage(ide_hwif_t *);
+static void init_hwif_siimage(ide_hwif_t *);
+static void init_dma_siimage(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t siimage_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_SII_680,
+		name:		"SiI680",
+		init_setup:	init_setup_siimage,
+		init_chipset:	init_chipset_siimage,
+		init_iops:	init_iops_siimage,
+		init_hwif:	init_hwif_siimage,
+		init_dma:	init_dma_siimage,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_SII_3112,
+		name:		"SiI3112 Serial ATA",
+		init_setup:	init_setup_siimage,
+		init_chipset:	init_chipset_siimage,
+		init_iops:	init_iops_siimage,
+		init_hwif:	init_hwif_siimage,
+		init_dma:	init_dma_siimage,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SIIMAGE_H */
diff -Nru a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sis5513.c	Sun Sep 15 19:19:46 2002
@@ -0,0 +1,1047 @@
+/*
+ * linux/drivers/ide/sis5513.c		Version 0.14	July 24, 2002
+ *
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul :
+ *			  for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ */
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sis5513.h"
+
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */
+// #define DEBUG
+/* When BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
+
+/* Miscellaneaous flags */
+#define SIS5513_LATENCY		0x01
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
+#define ATA_100		0x05
+#define ATA_133a	0x06 // SiS961b with 133 support
+#define ATA_133		0x07 // SiS962
+/* 2/ variable holding the controller chipset family value */
+static u8 chipset_family;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers fewer will be used
+ * Some odd chipsets hang if unused registers are accessed
+ * -> We only access them in #DEBUG code (then we'll see if SiS did
+ * it right from day one) */
+static u8 ide_regs_copy[0xff];
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	u8 reg_val;
+	u8 changed=0;
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%02x: %02x -> %02x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
+
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print config space registers a la "lspci -vxxx" */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i,j;
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+
+	for(i=0; i<=0xf; i++) {
+		printk("SIS5513 dump: %d" "0:", i);
+		for(j=0; j<=0xf; j++) {
+			printk(" %02x", ide_regs_copy[(i<<16)+j]);
+		}
+		printk("\n");
+	}
+}
+#endif
+
+
+/*
+ * Devices supported
+ */
+static const struct {
+	const char *name;
+	u16 host_id;
+	u8 chipset_family;
+	u8 flags;
+} SiSHostChipInfo[] = {
+	{ "SiS752",	PCI_DEVICE_ID_SI_752,	ATA_133,	0 },
+	{ "SiS751",	PCI_DEVICE_ID_SI_751,	ATA_133,	0 },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_133,	0 },
+	{ "SiS748",	PCI_DEVICE_ID_SI_748,	ATA_133,	0 },
+	{ "SiS746",	PCI_DEVICE_ID_SI_746,	ATA_133,	0 },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_133,	0 },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	0 },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
+	{ "SiS652",	PCI_DEVICE_ID_SI_652,	ATA_133,	0 },
+	{ "SiS651",	PCI_DEVICE_ID_SI_651,	ATA_133,	0 },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_133,	0 },
+	{ "SiS648",	PCI_DEVICE_ID_SI_648,	ATA_133,	0 },
+	{ "SiS646",	PCI_DEVICE_ID_SI_646,	ATA_133,	0 },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_133,	0 },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS550",	PCI_DEVICE_ID_SI_550,	ATA_100a,	0},
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
+};
+
+/* Cycle time bits and values vary accross chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+
+/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
+static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
+static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
+static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0,0}, /* ATA_33 */
+	{7,5,3,2,1,0,0}, /* ATA_66 */
+	{7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
+	{11,7,5,4,2,1,0}, /* ATA_100 */
+	{15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
+	{15,10,7,5,3,2,1}, /* ATA_133 */
+};
+/* CRC Valid Setup Time vary accross IDE clock setting 33/66/100/133
+   See SiS962 data sheet for more detail */
+static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{2,1,1,0,0,0,0},
+	{4,3,2,1,0,0,0},
+	{4,3,2,1,0,0,0},
+	{6,4,3,1,1,1,0},
+	{9,6,4,2,2,2,2},
+	{9,6,4,2,2,2,2},
+};
+/* Initialize time, Active time, Recovery time vary accross
+   IDE clock settings. These 3 arrays hold the register value
+   for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
+static u8 ini_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{2,1,0,0,0,1,0,0},
+	{4,3,1,1,1,3,1,1},
+	{4,3,1,1,1,3,1,1},
+	{6,4,2,2,2,4,2,2},
+	{9,6,3,3,3,6,3,3},
+	{9,6,3,3,3,6,3,3},
+};
+static u8 act_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,9,9,2,2,7,2,2},
+	{19,19,19,5,4,14,5,4},
+	{19,19,19,5,4,14,5,4},
+	{28,28,28,7,6,21,7,6},
+	{38,38,38,10,9,28,10,9},
+	{38,38,38,10,9,28,10,9},
+};
+static u8 rco_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,2,0,2,0,7,1,1},
+	{19,5,1,5,2,16,3,2},
+	{19,5,1,5,2,16,3,2},
+	{30,9,3,9,4,25,6,4},
+	{40,12,4,12,5,34,12,5},
+	{40,12,4,12,5,34,12,5},
+};
+
+static struct pci_dev *host_dev = NULL;
+
+/*
+ * Printing configuration
+ */
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char* recovery_time[] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"13 CLK", "14 CLK",
+	"15 CLK", "16 CLK"
+};
+
+static char* chipset_capability[] = {
+	"ATA", "ATA 16",
+	"ATA 33", "ATA 66",
+	"ATA 100", "ATA 100",
+	"ATA 133", "ATA 133"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, u8 pos)
+{
+	u8 reg00, reg01, reg10, reg11; /* timing registers */
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	if (chipset_family < ATA_133) {
+		pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+		p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+			     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+			     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+		pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+		pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+		pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+		pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+	}
+
+
+/* UDMA */
+	if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:  p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	if (chipset_family < ATA_133) {
+		p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+			     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+	}
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u8 reg;
+	u16 reg2, reg3;
+
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133a:
+		case ATA_133: p += sprintf(p, "Ultra 133"); break;
+		default: p+= sprintf(p, "Unknown???"); break;
+	}
+	p += sprintf(p, " chipset\n");
+	p += sprintf(p, "--------------- Primary Channel "
+		     "---------------- Secondary Channel "
+		     "-------------\n");
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	if (chipset_family == ATA_133) {
+		pci_read_config_word(bmide_dev, 0x50, &reg2);
+		pci_read_config_word(bmide_dev, 0x52, &reg3);
+	}
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else if (chipset_family < ATA_133) {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	} else { /* ATA_133 */
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg2 & 0x02) ? "On" : "Off",
+			     (reg3 & 0x02) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg2 & 0x01) ? cable_type[1] : cable_type[0],
+			     (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
+	} else if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
+
+/* Prefetch Count */
+	if (chipset_family < ATA_133) {
+		pci_read_config_word(bmide_dev, 0x4c, &reg2);
+		pci_read_config_word(bmide_dev, 0x4e, &reg3);
+		p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+			     reg2, reg3);
+	}
+
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
+
+	return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 sis5513_ratemask (ide_drive_t *drive)
+{
+#if 0
+	u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
+	u8 mode = rates[chipset_family];
+#else
+	u8 mode;
+
+	switch(chipset_family) {
+		case ATA_133:
+		case ATA_133a:
+			mode = 4;
+			break;
+		case ATA_100:
+		case ATA_100a:
+			mode = 3;
+			break;
+		case ATA_66:
+			mode = 2;
+			break;
+		case ATA_33:
+			return 1;
+		case ATA_16:
+                case ATA_00:	
+		default:
+			return 0;
+	}
+#endif
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 reg4bh		= 0;
+	u8 rw_prefetch		= (0x11 << drive->dn);
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
+	if (drive->media != ide_disk)
+		return;
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+	if ((reg4bh & rw_prefetch) != rw_prefetch)
+		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
+}
+
+
+/* Set per-drive active and recovery time */
+static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8			timing, drive_pci, test1, test2;
+
+	u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
+	config_drive_art_rwp(drive);
+	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, "
+		"drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
+
+	/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
+	drive_pci = 0x40;
+	/* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+	}
+
+	/* register layout changed with newer ATA100 chips */
+	if (chipset_family < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else if (chipset_family < ATA_133) {
+		switch(timing) { /*		active  recovery
+						  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+	} else { /* ATA_133 */
+		u32 test3;
+		pci_read_config_dword(dev, drive_pci, &test3);
+		test3 &= 0xc0c00fff;
+		if (test3 & 0x08) {
+			test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24;
+		} else {
+			test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24;
+		}
+		pci_write_config_dword(dev, drive_pci, test3);
+	}
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+#if 0
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, (XFER_PIO_0 + pio));
+#else
+	u8 speed;
+
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, speed);
+#endif
+}
+
+static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 drive_pci, reg;
+	u32 regdw;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, speed);
+#endif
+
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL);
+#endif
+	if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
+#endif
+
+	u8 speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+	/* See config_art_rwp_pio for drive pci config registers */
+	drive_pci = 0x40;
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+		pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if (speed < XFER_UDMA_0) {
+			regdw &= 0xfffffffb;
+			pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+		}
+	
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+		pci_read_config_byte(dev, drive_pci+1, &reg);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+			reg &= 0x7F;
+			pci_write_config_byte(dev, drive_pci+1, reg);
+		}
+	}
+
+	/* Config chip for mode */
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (chipset_family >= ATA_133) {
+				regdw |= 0x04;
+				regdw &= 0xfffff00f;
+				/* check if ATA133 enable */
+				if (regdw & 0x08) {
+					regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8;
+				} else {
+				/* if ATA133 disable, we should not set speed above UDMA5 */
+					if (speed > XFER_UDMA_5)
+						speed = XFER_UDMA_5;
+					regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8;
+				}
+				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+			} else {
+				/* Force the UDMA bit on if we want to use UDMA */
+				reg |= 0x80;
+				/* clean reg cycle time bits */
+				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+					 << cycle_time_offset[chipset_family]);
+				/* set reg cycle time bits */
+				reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+					<< cycle_time_offset[chipset_family];
+				pci_write_config_byte(dev, drive_pci+1, reg);
+			}
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+		case XFER_PIO_0:
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
+
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x, udma_66 %x\n",
+	       drive->dn, drive->id->dma_ultra);
+#endif
+
+	if (!(speed))
+		return 0;
+
+	sis5513_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		sis5513_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+	config_drive_art_rwp(drive);
+	config_art_rwp_pio(drive, 5);
+	return sis5513_config_drive_xfer_rate(drive);
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/* Chip detection and general config */
+static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *host;
+	int i = 0;
+
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_SI,
+					SiSHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
+	
+		/* check 100/133 chipset family */
+		if (chipset_family == ATA_133) {
+			u32 reg54h;
+			u16 reg02h;
+			pci_read_config_dword(dev, 0x54, &reg54h);
+			pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff));
+			pci_read_config_word(dev, 0x02, &reg02h);
+			pci_write_config_dword(dev, 0x54, reg54h);
+			/* devid 5518 here means SiS962 or later
+			   which supports ATA133 */
+			if (reg02h != 0x5518) {
+				u8 reg49h;
+				unsigned long sbrev;
+				/* SiS961 family */
+
+		/*
+		 * FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING 
+		 */
+				outl(0x80001008, 0x0cf8);
+				sbrev = inl(0x0cfc);
+
+				pci_read_config_byte(dev, 0x49, &reg49h);
+				if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80))
+					chipset_family = ATA_133a;
+				else
+					chipset_family = ATA_100;
+			}
+		}
+		printk(SiSHostChipInfo[i].name);
+		printk("    %s controller", chipset_capability[chipset_family]);
+		printk("\n");
+
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+		}
+	}
+
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compabitility mode only
+	   2/ tell old chips to allow per drive IDE timings */
+	if (host_dev) {
+		u8 reg;
+		u16 regw;
+		switch(chipset_family) {
+			case ATA_133:
+				/* SiS962 operation mode */
+				pci_read_config_word(dev, 0x50, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x50, regw&0xfff7);
+				pci_read_config_word(dev, 0x52, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x52, regw&0xfff7);
+				break;
+			case ATA_133a:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_100a:
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
+		}
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		if (!sis_proc) {
+			sis_proc = 1;
+			bmide_dev = dev;
+			ide_pci_register_host_proc(&sis_procs[0]);
+		}
+#endif
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
+	return 0;
+}
+
+static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0;
+
+	if (chipset_family >= ATA_133) {
+		u16 regw = 0;
+		u16 reg_addr = hwif->channel ? 0x52: 0x50;
+		pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
+		ata66 = (regw & 0x8000) ? 0 : 1;
+	} else if (chipset_family >= ATA_66) {
+		u8 reg48h = 0;
+		u8 mask = hwif->channel ? 0x20 : 0x10;
+		pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+		ata66 = (reg48h & mask) ? 0 : 1;
+	}
+        return ata66;
+}
+
+static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &sis5513_tune_drive;
+	hwif->speedproc = &sis5513_tune_chipset;
+
+	if (!(hwif->dma_base)) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!host_dev)
+		return;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_sis5513(hwif);
+
+	if (chipset_family > ATA_16) {
+		hwif->ide_dma_check = &sis5513_config_xfer_rate;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif
+	return;
+}
+
+static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init sis5513_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_SI)
+		return 0;
+
+	for (d = sis5513_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/sis5513.h b/drivers/ide/pci/sis5513.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sis5513.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,56 @@
+#ifndef SIS5513_H
+#define SIS5513_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SIS_TIMINGS
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc;
+
+static int sis_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sis_procs[] __initdata = {
+{
+		name:		"sis",
+		set:		1,
+		get_info:	sis_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_sis5513(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
+static void init_hwif_sis5513(ide_hwif_t *);
+static void init_dma_sis5513(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sis5513_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_SI,
+		device:		PCI_DEVICE_ID_SI_5513,
+		name:		"SIS5513",
+		init_setup:	init_setup_sis5513,
+		init_chipset:	init_chipset_sis5513,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_sis5513,
+		init_dma:	init_dma_sis5513,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		bootable:	ON_BOARD,
+		extra:		0
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SIS5513_H */
diff -Nru a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sl82c105.c	Sun Sep 15 19:19:30 2002
@@ -0,0 +1,306 @@
+/*
+ * linux/drivers/ide/sl82c105.c
+ *
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Rebel.com's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "ide_modes.h"
+#include "sl82c105.h"
+
+/*
+ * Convert a PIO mode and cycle time to the required on/off
+ * times for the interface.  This has protection against run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+	unsigned int cmd_on;
+	unsigned int cmd_off;
+
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+	if (cmd_on > 32)
+		cmd_on = 32;
+	if (cmd_on == 0)
+		cmd_on = 1;
+
+	if (cmd_off > 32)
+		cmd_off = 32;
+	if (cmd_off == 0)
+		cmd_off = 1;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+}
+
+/*
+ * Configure the drive and chipset for PIO
+ */
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	ide_pio_data_t p;
+	u16 drv_ctrl = 0x909;
+	unsigned int xfer_mode, reg;
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+	xfer_mode = XFER_PIO_0 + pio;
+
+	if (ide_config_drive_speed(drive, xfer_mode) == 0)
+		drv_ctrl = get_timing_sl82c105(&p);
+
+	if (drive->using_dma == 0) {
+		/*
+		 * If we are actually using MW DMA, then we can not
+		 * reprogram the interface drive control register.
+		 */
+		pci_write_config_word(dev, reg, drv_ctrl);
+		pci_read_config_word(dev, reg, &drv_ctrl);
+
+		if (report) {
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+		}
+	}
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u16 drv_ctrl = 0x909;
+	unsigned int reg;
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
+		drv_ctrl = 0x0240;
+
+	pci_write_config_word(dev, reg, drv_ctrl);
+
+	return 0;
+}
+
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+
+static int sl82c105_check_drive (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	do {
+		struct hd_driveid *id = drive->id;
+
+		if (!drive->autodma)
+			break;
+
+		if (!id || !(id->capability & 1))
+			break;
+
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			break;
+
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask))
+				return hwif->ide_dma_on(drive);
+		}
+
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
+	} while (0);
+
+	return hwif->ide_dma_off_quietly(drive);
+}
+
+static int sl82c105_ide_dma_on (ide_drive_t *drive)
+{
+	if (config_for_dma(drive)) {
+		config_for_pio(drive, 4, 0);
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	}
+	return __ide_dma_on(drive);
+}
+
+static int sl82c105_ide_dma_off (ide_drive_t *drive)
+{
+	config_for_pio(drive, 4, 0);
+	return __ide_dma_off(drive);
+}
+
+static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+{
+	config_for_pio(drive, 4, 0);
+	return __ide_dma_off_quietly(drive);
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+{
+	config_for_pio(drive, pio, 1);
+
+	/*
+	 * We support 32-bit I/O on this interface, and it
+	 * doesn't have problems with interrupts.
+	 */
+	drive->io_32bit = 1;
+	drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+	struct pci_dev *bridge;
+	u8 rev;
+
+	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
+
+	/*
+	 * If we are part of a Winbond 553
+	 */
+	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+		return -1;
+
+	if (bridge->bus != dev->bus ||
+	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
+		return -1;
+
+	/*
+	 * We need to find function 0's revision, not function 1
+	 */
+	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+	return rev;
+}
+
+/*
+ * Enable the PCI device
+ */
+static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	u8 ctrl_stat;
+
+	/*
+	 * Enable the ports
+	 */
+	pci_read_config_byte(dev, 0x40, &ctrl_stat);
+	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+
+	return dev->irq;
+}
+
+static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	unsigned int rev;
+	u8 dma_state;
+
+	hwif->autodma = 0;
+
+	if (!dma_base)
+		return;
+
+	dma_state = hwif->INB(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+		       hwif->name, rev);
+		dma_state &= ~0x60;
+	} else {
+		dma_state |= 0x60;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->OUTB(dma_state, dma_base + 2);
+
+	ide_setup_dma(hwif, dma_base, 8);
+}
+
+/*
+ * Initialise the chip
+ */
+
+static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+{
+	hwif->tuneproc = tune_sl82c105;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &sl82c105_check_drive;
+	hwif->ide_dma_on = &sl82c105_ide_dma_on;
+	hwif->ide_dma_off = &sl82c105_ide_dma_off;
+	hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_sl82c105 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init sl82c105_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_WINBOND)
+		return 0;
+
+	for (d = sl82c105_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/sl82c105.h b/drivers/ide/pci/sl82c105.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/sl82c105.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,36 @@
+#ifndef W82C105_H
+#define W82C105_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_sl82c105(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_sl82c105(struct pci_dev *, const char *);
+static void init_hwif_sl82c105(ide_hwif_t *);
+static void init_dma_sl82c105(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sl82c105_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_WINBOND,
+		device:		PCI_DEVICE_ID_WINBOND_82C105,
+		name:		"W82C105",
+		init_setup:	init_setup_sl82c105,
+		init_chipset:	init_chipset_sl82c105,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_sl82c105,
+		init_dma:	init_dma_sl82c105,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* W82C105_H */
diff -Nru a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/slc90e66.c	Sun Sep 15 19:20:14 2002
@@ -0,0 +1,389 @@
+/*
+ *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
+ *
+ *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "slc90e66.h"
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u32 bibma = pci_resource_start(bmide_dev, 4);
+        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x47, &reg47);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "                                SLC90E66 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg4a&0x04)==0x04) ? "4" :
+			((reg4a&0x03)==0x03) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4a&0x40)==0x40) ? "4" :
+			((reg4a&0x30)==0x30) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4b&0x04)==0x04) ? "4" :
+			((reg4b&0x03)==0x03) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg4b&0x40)==0x40) ? "4" :
+			((reg4b&0x30)==0x30) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 slc90e66_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 2;
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed	= ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
+	int u_speed = 0, u_flag = 1 << drive->dn;
+	u16			reg4042, reg44, reg48, reg4a;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:        break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if ((reg4a & u_speed) != u_speed) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_read_config_word(dev, 0x4a, &reg4a);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) slc90e66_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = slc90e66_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!slc90e66_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!slc90e66_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_slc90e66 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!slc90e66_proc) {
+		slc90e66_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&slc90e66_procs[0]);
+	}
+#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+{
+	u8 reg47 = 0;
+	u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->speedproc = &slc90e66_tune_chipset;
+	hwif->tuneproc = &slc90e66_tune_drive;
+
+	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	if (!(hwif->udma_four))
+		/* bit[0(1)]: 0:80, 1:40 */
+		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+
+	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_slc90e66 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_slc90e66 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init slc90e66_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_EFAR)
+		return 0;
+
+	for (d = slc90e66_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/slc90e66.h b/drivers/ide/pci/slc90e66.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/slc90e66.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,58 @@
+#ifndef SLC90E66_H
+#define SLC90E66_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SLC90E66_TIMINGS
+
+#define SLC90E66_DEBUG_DRIVE_INFO	0
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc;
+
+static int slc90e66_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t slc90e66_procs[] __initdata = {
+	{
+		name:		"slc90e66",
+		set:		1,
+		get_info:	slc90e66_get_info,
+		parent:		NULL,
+	},
+};
+#endif	/* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_slc90e66(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_slc90e66(struct pci_dev *, const char *);
+static void init_hwif_slc90e66(ide_hwif_t *);
+static void init_dma_slc90e66(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t slc90e66_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_EFAR,
+		device:		PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		name:		"SLC90E66",
+		init_setup:	init_setup_slc90e66,
+		init_chipset:	init_chipset_slc90e66,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_slc90e66,
+		init_dma:	init_dma_slc90e66,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SLC90E66_H */
diff -Nru a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/trm290.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,421 @@
+/*
+ *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
+ *
+ *  Copyright (c) 1997-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA function
+ * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
+ * including a "Precision Instruments" board.  The TRM290 pre-dates
+ * the sff-8038 standard (ide-dma.c) by a few months, and differs
+ * significantly enough to warrant separate routines for some functions,
+ * while re-using others from ide-dma.c.
+ *
+ * EXPERIMENTAL!  It works for me (a sample of one).
+ *
+ * Works reliably for me in DMA mode (READs only),
+ * DMA WRITEs are disabled by default (see #define below);
+ *
+ * DMA is not enabled automatically for this chipset,
+ * but can be turned on manually (with "hdparm -d1") at run time.
+ *
+ * I need volunteers with "spare" drives for further testing
+ * and development, and maybe to help figure out the peculiarities.
+ * Even knowing the registers (below), some things behave strangely.
+ */
+
+#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
+
+/*
+ * TRM-290 PCI-IDE2 Bus Master Chip
+ * ================================
+ * The configuration registers are addressed in normal I/O port space
+ * and are used as follows:
+ *
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
+ *	bit7 must always be written as "1"
+ *	bits6-2 undefined
+ *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
+ *	bit0 1=test_mode, 0=normal(default)
+ *
+ * trm290_base+2 when READ: status register (byte, read-only)
+ *	bits7-2 undefined
+ *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
+ *	bit0 channel0 interrupt status 0=none, 1=asserted
+ *
+ * trm290_base+3 Interrupt mask register
+ *	bits7-5 undefined
+ *	bit4 legacy_header: 1=present, 0=absent
+ *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
+ *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
+ *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
+ *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
+ *
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
+ *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
+ *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
+ *	bit5 0=enabled master burst access (default), 1=disable  (write only)
+ *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
+ *	bit3 0=primary IDE channel, 1=secondary IDE channel
+ *	bits2-0 register index for accesses through CDR port
+ *
+ * trm290_base+0 "CDR" Config Data Register (word)
+ *	two sets of seven config registers,
+ *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
+ *	each index defined below:
+ *
+ * Index-0 Base address register for command block (word)
+ *	defaults: 0x1f0 for primary, 0x170 for secondary
+ *
+ * Index-1 general config register (byte)
+ *	bit7 1=DMA enable, 0=DMA disable
+ *	bit6 1=activate IDE_RESET, 0=no action (default)
+ *	bit5 1=enable IORDY, 0=disable IORDY (default)
+ *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
+ *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
+ *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
+ *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
+ *	bit0 enable_io_ports: 1=enable(default), 0=disable
+ *
+ * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
+ *	bits7-0 bits7-0 of readahead count
+ *
+ * Index-3 read-ahead config register (byte, write only)
+ *	bit7 1=enable_readahead, 0=disable_readahead(default)
+ *	bit6 1=clear_FIFO, 0=no_action
+ *	bit5 undefined
+ *	bit4 mode4 timing control: 1=enable, 0=disable(default)
+ *	bit3 undefined
+ *	bit2 undefined
+ *	bits1-0 bits9-8 of read-ahead count
+ *
+ * Index-4 base address register for control block (word)
+ *	defaults: 0x3f6 for primary, 0x376 for secondary
+ *
+ * Index-5 data port timings (shared by both drives) (byte)
+ *	standard PCI "clk" (clock) counts, default value = 0xf5
+ *
+ *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
+ *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
+ *				011=4clk, 100=5clk, 101=6clk,
+ *				110=8clk, 111=12clk
+ *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
+ *				011=5clk, 100=6clk, 101=8clk,
+ *				110=12clk, 111=16clk
+ *
+ * Index-6 command/control port timings (shared by both drives) (byte)
+ *	same layout as Index-5, default value = 0xde
+ *
+ * Suggested CDR programming for PIO mode0 (600ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode3 (180ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode4 (120ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "trm290.h"
+
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 reg = 0;
+	unsigned long flags;
+
+	/* select PIO or DMA */
+	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+	local_irq_save(flags);
+
+	if (reg != hwif->select_data) {
+		hwif->select_data = reg;
+		/* set PIO/DMA */
+		hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+		hwif->OUTW(reg & 0xff, hwif->config_data);
+	}
+
+	/* enable IRQ if not probing */
+	if (drive->present) {
+		reg = hwif->INW(hwif->config_data + 3);
+		reg &= 0x13;
+		reg &= ~(1 << hwif->channel);
+		hwif->OUTW(reg, hwif->config_data+3);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+	trm290_prepare_drive(drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	reading = 0;
+	writing = 1;
+#ifdef TRM290_NO_DMA_WRITES
+	/* always use PIO for writes */
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
+	return 1;
+#endif
+	if (!(count = ide_build_dmatable(drive, rq))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_READDMA_EXT : */ WIN_READDMA;
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_read (ide_drive_t *drive  /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	if (!(count = ide_build_dmatable(drive, rq))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_WRITEDMA_EXT : */ WIN_WRITEDMA;
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_begin (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int trm290_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;;
+
+	drive->waiting_for_dma = 0;
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	status = hwif->INW(hwif->dma_status);
+	return (status != 0x00ff);
+}
+
+static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;
+
+	status = hwif->INW(hwif->dma_status);
+	return (status == 0x00ff);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Invoked from ide-dma.c at boot time.
+ */
+void __init init_hwif_trm290 (ide_hwif_t *hwif)
+{
+	unsigned int cfgbase = 0;
+	unsigned long flags;
+	u8 reg = 0;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->addressing = 1;
+	hwif->chipset = ide_trm290;
+	cfgbase = pci_resource_start(dev, 4);
+	if ((dev->class & 5) && cfgbase) {
+		hwif->config_data = cfgbase;
+		printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+			hwif->config_data);
+	} else {
+		hwif->config_data = 0x3df0;
+		printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+			hwif->config_data);
+	}
+
+	local_irq_save(flags);
+	/* put config reg into first byte of hwif->select_data */
+	hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+	/* select PIO as default */
+	hwif->select_data = 0x21;
+	hwif->OUTB(hwif->select_data, hwif->config_data);
+	/* get IRQ info */
+	reg = hwif->INB(hwif->config_data+3);
+	/* mask IRQs for both ports */
+	reg = (reg & 0x10) | 0x03;
+	hwif->OUTB(reg, hwif->config_data+3);
+	local_irq_restore(flags);
+
+	if ((reg & 0x10))
+		/* legacy mode */
+		hwif->irq = hwif->channel ? 15 : 14;
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		/* sharing IRQ with mate */
+		hwif->irq = hwif->mate->irq;
+
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_write = &trm290_ide_dma_write;
+	hwif->ide_dma_read = &trm290_ide_dma_read;
+	hwif->ide_dma_begin = &trm290_ide_dma_begin;
+	hwif->ide_dma_end = &trm290_ide_dma_end;
+	hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	hwif->selectproc = &trm290_selectproc;
+	hwif->autodma = 0;		/* play it safe for now */
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#if 1
+	{
+	/*
+	 * My trm290-based card doesn't seem to work with all possible values
+	 * for the control basereg, so this kludge ensures that we use only
+	 * values that are known to work.  Ugh.		-ml
+	 */
+		u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
+		static u16 next_offset = 0;
+		u8 old_mask;
+
+		hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = hwif->INW(hwif->config_data);
+		old &= ~1;
+		old_mask = hwif->INB(old+2);
+		if (old != compat && old_mask == 0xff) {
+			/* leave lower 10 bits untouched */
+			compat += (next_offset += 0x400);
+#  if 1
+			if (check_region(compat + 2, 1))
+				printk(KERN_ERR "%s: check_region failure at 0x%04x\n",
+					hwif->name, (compat + 2));
+			/*
+			 * The region check is not needed; however.........
+			 * Since this is the checked in ide-probe.c,
+			 * this is only an assignment.
+			 */
+#  endif
+			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+			hwif->OUTW(compat|1, hwif->config_data);
+			new = hwif->INW(hwif->config_data);
+			printk(KERN_INFO "%s: control basereg workaround: "
+				"old=0x%04x, new=0x%04x\n",
+				hwif->name, old, new & ~1);
+		}
+	}
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+void __init init_setup_trm290 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+int __init trm290_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_TEKRAM)
+		return 0;
+
+	for (d = trm290_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/trm290.h b/drivers/ide/pci/trm290.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/trm290.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,34 @@
+#ifndef TRM290_H
+#define TRM290_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_setup_trm290(struct pci_dev *, ide_pci_device_t *);
+extern void init_hwif_trm290(ide_hwif_t *);
+
+static ide_pci_device_t trm290_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_TEKRAM,
+		device:		PCI_DEVICE_ID_TEKRAM_DC290,
+		name:		"TRM290",
+		init_setup:	init_setup_trm290,
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_trm290,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* TRM290_H */
diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/via82cxxx.c	Sun Sep 15 19:19:28 2002
@@ -0,0 +1,671 @@
+/*
+ * $Id: via82cxxx.c,v 3.35-ac1 2002/08/19 Alan Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ */
+
+/*
+ * Version 3.35
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ *   vt8235
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "via82cxxx.h"
+
+#define VIA_IDE_ENABLE		0x40
+#define VIA_IDE_CONFIG		0x41
+#define VIA_FIFO_CONFIG		0x43
+#define VIA_MISC_1		0x44
+#define VIA_MISC_2		0x45
+#define VIA_MISC_3		0x46
+#define VIA_DRIVE_TIMING	0x48
+#define VIA_8BIT_TIMING		0x4e
+#define VIA_ADDRESS_SETUP	0x4c
+#define VIA_UDMA_TIMING		0x50
+
+#define VIA_UDMA		0x007
+#define VIA_UDMA_NONE		0x000
+#define VIA_UDMA_33		0x001
+#define VIA_UDMA_66		0x002
+#define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
+#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
+#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+	char *name;
+	u16 id;
+	u8 rev_min;
+	u8 rev_max;
+	u16 flags;
+} via_isa_bridges[] = {
+#ifdef FUTURE_BRIDGES
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+#endif
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
+	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+	{ NULL }
+};
+
+static struct via_isa_bridge *via_config;
+static unsigned char via_enabled;
+static unsigned int via_80w;
+static unsigned int via_clock;
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+
+/*
+ * VIA /proc entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc = 0;
+static unsigned long via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+
+/**
+ *	via_get_info		-	generate via /proc file 
+ *	@buffer: buffer for data
+ *	@addr: set to start of data to use
+ *	@offset: current file offset
+ *	@count: size of read
+ *
+ *	Fills in buffer with the debugging/configuration information for
+ *	the VIA chipset tuning and attached drives
+ */
+ 
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	u16 c, w;
+	u8 t, x;
+	char *p = buffer;
+
+	via_print("----------VIA BusMastering IDE Configuration"
+		"----------------");
+
+	via_print("Driver Version:                     3.35-ac");
+	via_print("South Bridge:                       VIA %s",
+		via_config->name);
+
+	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+	via_print("Revision:                           ISA %#x IDE %#x", t, x);
+	via_print("Highest DMA rate:                   %s",
+		via_dma[via_config->flags & VIA_UDMA]);
+
+	via_print("BM-DMA base:                        %#x", via_base);
+	via_print("PCI clock:                          %d.%dMHz",
+		via_clock / 1000, via_clock / 100 % 10);
+
+	pci_read_config_byte(dev, VIA_MISC_1, &t);
+	via_print("Master Read  Cycle IRDY:            %dws",
+		(t & 64) >> 6);
+	via_print("Master Write Cycle IRDY:            %dws",
+		(t & 32) >> 5);
+	via_print("BM IDE Status Register Read Retry:  %s",
+		(t & 8) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_MISC_3, &t);
+	via_print("Max DRDY Pulse Width:               %s%s",
+		via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+	via_print("-----------------------Primary IDE"
+		"-------Secondary IDE------");
+	via_print("Read DMA FIFO flush:   %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+	via_print("End Sector FIFO flush: %10s%20s",
+		(t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+	via_print("Prefetch Buffer:       %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	via_print("Post Write Buffer:     %10s%20s",
+		(t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+	via_print("Enabled:               %10s%20s",
+		(t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
+	via_print("Simplex only:          %10s%20s",
+		(c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	via_print("Cable Type:            %10s%20s",
+		(via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+	via_print("-------------------drive0----drive1"
+		"----drive2----drive3-----");
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+	if (via_config->flags & VIA_UDMA)
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+	else u = 0;
+
+	for (i = 0; i < 4; i++) {
+
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+		if (!uen[i] || !den[i])
+			continue;
+
+		switch (via_config->flags & VIA_UDMA) {
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_66:
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+				break;
+
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
+				break;
+		}
+	}
+
+	via_print_drive("Transfer Mode: ", "%10s",
+		den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	via_print_drive("Address Setup: ", "%8dns",
+		1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns",
+		1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns",
+		1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns",
+		1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns",
+		1000000 * recover[i] / via_clock);
+	via_print_drive("Cycle Time:    ", "%8dns",
+		cycle[i]);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s",
+		speed[i] / 1000, speed[i] / 100 % 10);
+
+	/* hoping it is less than 4K... */
+	return p - buffer;
+}
+
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	via_set_speed			-	write timing registers
+ *	@dev: PCI device
+ *	@dn: device
+ *	@timing: IDE timing data to use
+ *
+ *	via_set_speed writes timing values to the chipset registers
+ */
+
+static void via_set_speed(struct pci_dev *dev, u8 dn, struct ide_timing *timing)
+{
+	u8 t;
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
+
+	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+}
+
+/**
+ *	via_set_drive		-	configure transfer mode
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	via_set_drive() computes timing values configures the drive and
+ *	the chipset to a desired transfer mode. It also can be called
+ *	by upper layers.
+ */
+
+static int via_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	unsigned int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't "
+				"accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / via_clock;
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:   UT = T;   break;
+		case VIA_UDMA_66:   UT = T/2; break;
+		case VIA_UDMA_100:  UT = T/3; break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
+	}
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/**
+ *	via82cxxx_tune_drive	-	PIO setup
+ *	@drive: drive to set up
+ *	@pio: mode to use (255 for 'best possible')
+ *
+ *	A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((via_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		via_set_drive(drive,
+			ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+
+/**
+ *	via82cxxx_ide_dma_check		-	set up for DMA if possible
+ *	@drive: IDE drive to set up
+ *
+ *	Set up the drive for the highest supported speed considering the
+ *	driver, controller and cable
+ */
+ 
+static int via82cxxx_ide_dma_check (ide_drive_t *drive)
+{
+	u16 w80 = HWIF(drive)->udma_four;
+
+	u16 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+		(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+	via_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/**
+ *	init_chipset_via82cxxx	-	initialization handler
+ *	@dev: PCI device
+ *	@name: Name of interface
+ *
+ *	The initialization callback. Here we determine the IDE chip type
+ *	and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *isa = NULL;
+	u8 t, v;
+	unsigned int u;
+	int i;
+
+	/*
+	 * Find the ISA bridge to see how good the IDE is.
+	 */
+
+	for (via_config = via_isa_bridges; via_config->id; via_config++)
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID),
+			via_config->id, NULL))) {
+
+			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+			if (t >= via_config->rev_min &&
+			    t <= via_config->rev_max)
+				break;
+		}
+
+	if (!via_config->id) {
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Check 80-wire cable presence and setup Clk66.
+	 */
+
+	switch (via_config->flags & VIA_UDMA) {
+
+		case VIA_UDMA_66:
+			/* Enable Clk66 */
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> (i & 16)) & 8) &&
+				    ((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 2)) {
+					/*
+					 * 2x PCI clock and
+					 * UDMA w/ < 3T/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 4))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 8))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+	}
+
+	/* Disable Clk66 */
+	if (via_config->flags & VIA_BAD_CLK66) {
+		/* Would cause trouble on 596a and 686 */
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
+	}
+
+	/*
+	 * Check whether interfaces are enabled.
+	 */
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
+
+	/*
+	 * Set up FIFO sizes and thresholds.
+	 */
+
+	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
+
+	/* Disable PREQ# till DDACK# */
+	if (via_config->flags & VIA_BAD_PREQ) {
+		/* Would crash on 586b rev 41 */
+		t &= 0x7f;
+	}
+
+	/* Fix FIFO split between channels */
+	if (via_config->flags & VIA_SET_FIFO) {
+		t &= (t & 0x9f);
+		switch (via_enabled) {
+			case 1: t |= 0x00; break;	/* 16 on primary */
+			case 2: t |= 0x60; break;	/* 16 on secondary */
+			case 3: t |= 0x20; break;	/* 8 pri 8 sec */
+		}
+	}
+
+	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
+
+	/*
+	 * Determine system bus clock.
+	 */
+
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
+		printk(KERN_WARNING "VP_IDE: User given PCI clock speed "
+			"impossible (%d), using 33 MHz instead.\n", via_clock);
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want "
+			"to assume 80-wire cable.\n");
+		via_clock = 33333;
+	}
+
+	/*
+	 * Print the boot message.
+	 */
+
+	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+		"controller on pci%s\n",
+		via_config->name, t,
+		via_dma[via_config->flags & VIA_UDMA],
+		dev->slot_name);
+
+	/*
+	 * Setup /proc/ide/via entry.
+	 */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!via_proc) {
+		via_base = pci_resource_start(dev, 4);
+		bmide_dev = dev;
+		isa_dev = isa;
+		ide_pci_register_host_proc(&via_procs[0]);
+		via_proc = 1;
+	}
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &via82cxxx_tune_drive;
+	hwif->speedproc = &via_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1;
+	hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+/**
+ *	init_dma_via82cxxx	-	set up for IDE DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA base address
+ *
+ *	We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+
+static void __init init_dma_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((via_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/*
+ *	FIXME: should not be needed
+ */
+ 
+static void __init init_setup_via82cxxx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	via82cxxx_scan_pcidev	-	set up any via devices
+ *	@dev: PCI device we are offered
+ *
+ *	Any controller we are offered that we can configure we set up 
+ *	and return 1. Anything we cannot drive we return 0
+ */
+ 
+int __init via82cxxx_scan_pcidev (struct pci_dev *dev)
+{
+	ide_pci_device_t *d;
+
+	if (dev->vendor != PCI_VENDOR_ID_VIA)
+		return 0;
+
+	for (d = via82cxxx_chipsets; d && d->vendor && d->device; ++d) {
+		if (((d->vendor == dev->vendor) &&
+		     (d->device == dev->device)) &&
+		    (d->init_setup)) {
+			d->init_setup(dev, d);
+			return 1;
+		}
+	}
+	return 0;
+}
+
diff -Nru a/drivers/ide/pci/via82cxxx.h b/drivers/ide/pci/via82cxxx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/via82cxxx.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,70 @@
+#ifndef VIA82CXXX_H
+#define VIA82CXXX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc;
+
+static int via_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t via_procs[] __initdata = {
+	{
+		name:		"via",
+		set:		1,
+		get_info:	via_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_via82cxxx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_via82cxxx(struct pci_dev *, const char *);
+static void init_hwif_via82cxxx(ide_hwif_t *);
+static void init_dma_via82cxxx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t via82cxxx_chipsets[] __initdata = {
+	{
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C576_1,
+		name:		"VP_IDE",
+		init_setup:	init_setup_via82cxxx,
+		init_chipset:	init_chipset_via82cxxx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_via82cxxx,
+		init_dma:	init_dma_via82cxxx,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C586_1,
+		name:		"VP_IDE",
+		init_setup:	init_setup_via82cxxx,
+		init_chipset:	init_chipset_via82cxxx,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_via82cxxx,
+		init_dma:	init_dma_via82cxxx,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* VIA82CXXX_H */
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1430 +0,0 @@
-/*
- *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
- *
- *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
- *
- *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
- *  compiled into the kernel if you have more than one card installed.
- *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
- *  safe chipset tuning, including this support is harmless
- *
- *  Promise Ultra66 cards with BIOS v1.11 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100 cards.
- *
- *  The latest chipset code will support the following ::
- *  Three Ultra33 controllers and 12 drives.
- *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
- *  The 8/4 ratio is a BIOS code limit by promise.
- *
- *  UNLESS you enable "CONFIG_PDC202XX_BURST"
- *
- */
-
-/*
- *  Portions Copyright (C) 1999 Promise Technology, Inc.
- *  Author: Frank Tiernan (frankt@promise.com)
- *  Released under terms of General Public License
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define PDC202XX_DEBUG_DRIVE_INFO		0
-#define PDC202XX_DECODE_REGISTER_INFO		0
-
-#define DISPLAY_PDC202XX_TIMINGS
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdc202xx_get_info(char *, char **, off_t, int);
-extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-byte pdc202xx_proc = 0;
-
-#define PDC202_MAX_DEVS		5
-
-static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
-static int n_pdc202_devs;
-
-const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
-char *pdc202xx_pio_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
-	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
-	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
-	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
-	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
-	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
-	return("PIO ?");
-}
-
-char *pdc202xx_dma_verbose (u32 drive_pci)
-{
-	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
-	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
-	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
-	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
-	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
-	return("PIO---");
-}
-
-char *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
-{
-	if ((drive_pci & 0x000ff000) == 0x000ff000)
-		return("NOTSET");
-	if ((drive_pci & 0x00012000) == 0x00012000)
-		return((slow_cable) ? "UDMA 2" : "UDMA 4");
-	if ((drive_pci & 0x00024000) == 0x00024000)
-		return((slow_cable) ? "UDMA 1" : "UDMA 3");
-	if ((drive_pci & 0x00036000) == 0x00036000)
-		return("UDMA 0");
-	return(pdc202xx_dma_verbose(drive_pci));
-}
-
-static char * pdc202xx_info (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-
-	u32 bibma  = pci_resource_start(dev, 4);
-	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
-	u8 hi = 0, lo = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	u8 c0	= inb_p((unsigned short)bibma + 0x02);
-	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
-
-	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
-	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
-	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
-	u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
-	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
-	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
-	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f);
-
-	pci_read_config_word(dev, 0x50, &reg50h);
-	pci_read_config_dword(dev, 0x60, &reg60h);
-	pci_read_config_dword(dev, 0x64, &reg64h);
-	pci_read_config_dword(dev, 0x68, &reg68h);
-	pci_read_config_dword(dev, 0x6c, &reg6ch);
-
-	p += sprintf(p, "\n                                ");
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "PDC20267"); break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "PDC20265"); break;
-		case PCI_DEVICE_ID_PROMISE_20263:
-			p += sprintf(p, "PDC20263"); break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "PDC20262"); break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "PDC20246");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "PDC202XX"); break;
-	}
-	p += sprintf(p, " Chipset.\n");
-
-	p += sprintf(p, "------------------------------- General Status "
-			"---------------------------------\n");
-	p += sprintf(p, "Burst Mode                           : %sabled\n",
-		(sc1f & 0x01) ? "en" : "dis");
-	p += sprintf(p, "Host Mode                            : %s\n",
-		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
-	p += sprintf(p, "Bus Clocking                         : %s\n",
-		((sc1f & 0xC0) == 0xC0) ? "100 External" :
-		((sc1f & 0x80) == 0x80) ? "66 External" :
-		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
-	p += sprintf(p, "IO pad select                        : %s mA\n",
-		((sc1c & 0x03) == 0x03) ? "10" :
-		((sc1c & 0x02) == 0x02) ? "8" :
-		((sc1c & 0x01) == 0x01) ? "6" :
-		((sc1c & 0x00) == 0x00) ? "4" : "??");
-	SPLIT_BYTE(sc1e, hi, lo);
-	p += sprintf(p, "Status Polling Period                : %d\n", hi);
-	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %s                         %s\n",
-		(c0&0x80)?"disabled":"enabled ",
-		(c1&0x80)?"disabled":"enabled ");
-	p += sprintf(p, "66 Clocking     %s                         %s\n",
-		(sc11&0x02)?"enabled ":"disabled",
-		(sc11&0x08)?"enabled ":"disabled");
-	p += sprintf(p, "           Mode %s                      Mode %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "                %s                     %s\n",
-		(sc1d & 0x08) ? "Error       " :
-		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
-		(sc1d & 0x04) ? "Interrupting" :
-		(sc1d & 0x02) ? "FIFO Full   " :
-		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
-		(sc1d & 0x80) ? "Error       " :
-		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
-		(sc1d & 0x40) ? "Interrupting" :
-		(sc1d & 0x20) ? "FIFO Full   " :
-		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s "
-			"            %s               %s\n",
-		(c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
-		(c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
-	p += sprintf(p, "DMA Mode:       %s           %s "
-			"         %s            %s\n",
-		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
-		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
-		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
-		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
-	p += sprintf(p, "PIO Mode:       %s            %s "
-			"          %s            %s\n",
-		pdc202xx_pio_verbose(reg60h),
-		pdc202xx_pio_verbose(reg64h),
-		pdc202xx_pio_verbose(reg68h),
-		pdc202xx_pio_verbose(reg6ch));
-#if 0
-	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
-#endif
-	return (char *)p;
-}
-
-static char * pdc202xx_info_new (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-//	u32 bibma = pci_resource_start(dev, 4);
-
-//	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-//	u16 reg50h = 0, word88 = 0;
-//	int udmasel[4]={0,0,0,0}, piosel[4]={0,0,0,0}, i=0, hd=0;
-
-	p += sprintf(p, "\n                                ");
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-			p += sprintf(p, "PDC20277");
-		case PCI_DEVICE_ID_PROMISE_20276:
-			p += sprintf(p, "PDC20276"); break;
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "PDC20275"); break;
-		case PCI_DEVICE_ID_PROMISE_20271:
-			p += sprintf(p, "PDC20271"); break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "PDC20269 TX2"); break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			p += sprintf(p, "PDC20268 TX2"); break;
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			p += sprintf(p, "PDC20270 TX2/4"); break;
-		default:
-			p += sprintf(p, "PDC202XX"); break;
-			break;
-	}
-	p += sprintf(p, " Chipset.\n");
-	return (char *)p;
-}
-
-static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	for (i = 0; i < n_pdc202_devs; i++) {
-		struct pci_dev *dev	= pdc202_devs[i];
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_PROMISE_20277:
-			case PCI_DEVICE_ID_PROMISE_20276:
-			case PCI_DEVICE_ID_PROMISE_20275:
-			case PCI_DEVICE_ID_PROMISE_20271:
-			case PCI_DEVICE_ID_PROMISE_20269:
-			case PCI_DEVICE_ID_PROMISE_20268:
-			case PCI_DEVICE_ID_PROMISE_20268R:
-				p = pdc202xx_info_new(buffer, dev);
-				break;
-			default:
-				p = pdc202xx_info(buffer, dev);
-				break;
-		}
-	}
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/* A Register */
-#define	SYNC_ERRDY_EN	0xC0
-
-#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
-#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
-#define	IORDY_EN	0x20	/* PIO: IOREADY */
-#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
-
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
-
-#if PDC202XX_DECODE_REGISTER_INFO
-
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
-
-static void decode_registers (byte registers, byte value)
-{
-	byte	bit = 0, bit1 = 0, bit2 = 0;
-
-	switch(registers) {
-		case REG_A:
-			bit2 = 0;
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			bit1 = 0;bit2 = 0;
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			bit2 = 0;
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
-
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-#if 0
-static byte pdc202xx_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	byte mode = 0x00;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-			{ mode |= 0x04; break; }
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			{ mode |= 0x03; break; }
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			{ mode |= 0x03; break; }
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			{ mode |= 0x02; break; }
-		case PCI_DEVICE_ID_PROMISE_20246:
-			{ mode |= 0x01; break; }
-		default:
-			return (mode &= ~0xF8);
-	}
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = pdc202xx_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-#else
-static byte pdc202xx_ratefilter (ide_drive_t *drive, byte speed)
-{
-	return speed;
-}
-#endif
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= pdc202xx_ratefilter(drive, xferspeed);
-
-	unsigned int		drive_conf;
-	byte			drive_pci, AP, BP, CP, DP;
-	byte			TA = 0, TB = 0, TC = 0;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0x60; break;
-		case 1: drive_pci = 0x64; break;
-		case 2: drive_pci = 0x68; break;
-		case 3: drive_pci = 0x6c; break;
-		default: return -1;
-	}
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	if (speed < XFER_SW_DMA_0) {
-		if ((AP & 0x0F) || (BP & 0x07)) {
-			/* clear PIO modes of lower 8421 bits of A Register */
-			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
-			/* clear PIO modes of lower 421 bits of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	} else {
-		if ((BP & 0xF0) && (CP & 0x0F)) {
-			/* clear DMA modes of upper 842 bits of B Register */
-			/* clear PIO forced mode upper 1 bit of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			/* clear DMA modes of lower 8421 bits of C Register */
-			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		/* case XFER_UDMA_6: */
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
-		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
-		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
-		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
-		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
-		case XFER_PIO_0:
-		default:		TA = 0x09; TB = 0x13; break;
-	}
-
-	if (speed < XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	} else {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	}
-
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, drive_conf);
-		pci_read_config_dword(dev, drive_pci, &drive_conf);
-	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long indexreg	= (hwif->dma_base + 1);
-	unsigned long datareg	= (hwif->dma_base + 3);
-#else
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
-	unsigned long datareg	= (indexreg + 2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte thold		= 0x10;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	byte speed		= pdc202xx_ratefilter(drive, xferspeed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed == XFER_UDMA_2) {
-		OUT_BYTE((thold + adj), indexreg);
-		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	switch (speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_7:
-			speed = XFER_UDMA_6;
-		case XFER_UDMA_6:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x1a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x01, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xcb, datareg);
-			break;
-		case XFER_UDMA_5:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x1a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x02, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xcb, datareg);
-			break;
-		case XFER_UDMA_4:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x1a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x03, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xcd, datareg);
-			break;
-		case XFER_UDMA_3:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x1a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x05, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xcd, datareg);
-			break;
-		case XFER_UDMA_2:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x2a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x07, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xcd, datareg);
-			break;
-		case XFER_UDMA_1:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x3a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x0a, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xd0, datareg);
-			break;
-		case XFER_UDMA_0:
-			OUT_BYTE((0x10 + adj), indexreg);
-			OUT_BYTE(0x4a, datareg);
-			OUT_BYTE((0x11 + adj), indexreg);
-			OUT_BYTE(0x0f, datareg);
-			OUT_BYTE((0x12 + adj), indexreg);
-			OUT_BYTE(0xd5, datareg);
-			break;
-		case XFER_MW_DMA_2:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0x69, datareg);
-			OUT_BYTE((0x0f + adj), indexreg);
-			OUT_BYTE(0x25, datareg);
-			break;
-		case XFER_MW_DMA_1:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0x6b, datareg);
-			OUT_BYTE((0x0f+ adj), indexreg);
-			OUT_BYTE(0x27, datareg);
-			break;
-		case XFER_MW_DMA_0:
-			OUT_BYTE((0x0e + adj), indexreg);
-			OUT_BYTE(0xdf, datareg);
-			OUT_BYTE((0x0f + adj), indexreg);
-			OUT_BYTE(0x5f, datareg);
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0x23, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x09, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0x25, datareg);
-			break;
-		case XFER_PIO_3:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0x27, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x0d, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0x35, datareg);
-			break;
-		case XFER_PIO_2:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0x23, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x26, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0x64, datareg);
-			break;
-		case XFER_PIO_1:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0x46, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x29, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0xa4, datareg);
-			break;
-		case XFER_PIO_0:
-			OUT_BYTE((0x0c + adj), indexreg);
-			OUT_BYTE(0xfb, datareg);
-			OUT_BYTE((0x0d + adj), indexreg);
-			OUT_BYTE(0x2b, datareg);
-			OUT_BYTE((0x13 + adj), indexreg);
-			OUT_BYTE(0xac, datareg);
-			break;
-		default:
-			break;
-	}
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed = 0x00;
-
-	pio = (pio == 5) ? 4 : pio;
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-        
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-//	byte mode               = pdc202xx_ratemask(drive);
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16   = pci_resource_start(dev, 4);
-	unsigned long dma_base  = hwif->dma_base;
-	unsigned long indexreg	= dma_base + 1;
-	unsigned long datareg	= dma_base + 3;
-	byte iordy		= 0x13;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	byte cable		= 0;
-	byte jumpbit		= 0;
-	unsigned int		drive_conf;
-	byte			drive_pci = 0;
-	byte			test1, test2, speed = -1;
-	byte			AP;
-	unsigned short		EP;
-	byte CLKSPD		= 0;
-	byte udma_33		= 1;
-	byte udma_66		= (eighty_ninty_three(drive)) ? 1 : 0;
-	byte udma_100		= 0;
-	byte udma_133		= 0;
-	byte mask		= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-			udma_133 = (udma_66) ? 1 : 0;
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			jumpbit = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			udma_100 = 1;
-			udma_66 = 1;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			jumpbit = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			jumpbit = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			udma_100 = (udma_66) ? 1 : 0;
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			jumpbit = 0;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			jumpbit = 0;
-			break;
-		default:
-			udma_100 = 0; udma_133 = 0; cable = 1; jumpbit = 0;
-			break;
-	}
-
-	if (!jumpbit)
-		CLKSPD = IN_BYTE(high_16 + 0x11);
-	/*
-	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operation. If one drive on
-	 * a channel is U66 capable but the other isn't we
-	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued. I don't
-	 * do that here because it would require modifying the
-	 * kernel, seperating the fop routines from the kernel or
-	 * somehow hooking the fops calls. It may also be possible to
-	 * leave the 66Mhz clock on and readjust the timing
-	 * parameters.
-	 */
-
-	if ((ultra_66) && (cable)) {
-#ifdef DEBUG
-		printk("ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
-			"requires an 80-pin cable for Ultra66 operation.\n",
-			hwif->channel ? "Secondary" : "Primary");
-		printk("         Switching to Ultra33 mode.\n");
-#endif /* DEBUG */
-		/* Primary   : zero out second bit */
-		/* Secondary : zero out fourth bit */
-		if (!jumpbit)
-			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
-		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
-		printk("%s reduced to Ultra33 mode.\n", drive->name);
-		udma_66 = 0;
-	} else {
-		if (ultra_66) {
-			/*
-			 * check to make sure drive on same channel
-			 * is u66 capable
-			 */
-			if (hwif->drives[!(drive->dn%2)].id) {
-				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
-					if (!jumpbit)
-						OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
-				} else {
-					if (!jumpbit)
-						OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
-				}
-			} else { /* udma4 drive by itself */
-				if (!jumpbit)
-					OUT_BYTE(CLKSPD | mask, (high_16 + 0x11));
-			}
-		}
-	}
-
-	if (jumpbit) {
-		if (drive->media != ide_disk)	return ide_dma_off_quietly;
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
-		}
-		goto jumpbit_is_set;
-	}
-
-	switch(drive->dn) {
-		case 0:	drive_pci = 0x60;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 1:	drive_pci = 0x64;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x60, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		case 2:	drive_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 3:	drive_pci = 0x6c;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x68, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		default:
-			return ide_dma_off;
-	}
-
-chipset_is_set:
-
-	if (drive->media != ide_disk) {
-		hwif->tuneproc(drive, 5);
-		return ide_dma_off_quietly;
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	if (id->capability & 4)	/* IORDY_EN */
-		pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	if (drive->media == ide_disk)	/* PREFETCH_EN */
-		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-
-jumpbit_is_set:
-
-	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if ((id->dma_1word & 0x0004)&&(!jumpbit))	speed = XFER_SW_DMA_2;
-	else if ((id->dma_1word & 0x0002)&&(!jumpbit))	speed = XFER_SW_DMA_1;
-	else if ((id->dma_1word & 0x0001)&&(!jumpbit))	speed = XFER_SW_DMA_0;
-	else {
-		/* restore original pci-config space */
-		if (!jumpbit)
-			pci_write_config_dword(dev, drive_pci, drive_conf);
-		hwif->tuneproc(drive, 5);
-		return ide_dma_off_quietly;
-	}
-
-	(void) hwif->speedproc(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_off_quietly;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		hwif->tuneproc(drive, 5);
-	}
-
-	return hwif->dmaproc(dma_func, drive);
-}
-
-int pdc202xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
-}
-
-/*
- * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte sc1d		= 0;
-	byte newchip		= 0;
-	byte clock		= 0;
-	byte hardware48hack	= 0;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
-	unsigned long dma_base	= hwif->dma_base;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hardware48hack = 1;
-			clock = IN_BYTE(high_16 + 0x11);
-		default:
-			break;
-	}
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			if ((drive->addressing == 1) && (hardware48hack)) {
-				struct request *rq = HWGROUP(drive)->rq;
-				unsigned long word_count = 0;
-
-				OUT_BYTE(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
-				word_count = (rq->nr_sectors << 8);
-				word_count = (rq->cmd == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
-				outl(word_count, atapi_reg);
-			}
-			break;
-		case ide_dma_end:
-			if ((drive->addressing == 1) && (hardware48hack)) {
-				outl(0, atapi_reg);	/* zero out extra */
-				clock = IN_BYTE(high_16 + 0x11);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
-			}
-			break;
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			if (newchip)
-				return (dma_stat & 4) == 4;
-
-			sc1d = IN_BYTE(high_16 + 0x001d);
-			if (hwif->channel) {
-				if ((sc1d & 0x50) == 0x50) goto somebody_else;
-				else if ((sc1d & 0x40) == 0x40)
-					return (dma_stat & 4) == 4;
-			} else {
-				if ((sc1d & 0x05) == 0x05) goto somebody_else;
-				else if ((sc1d & 0x04) == 0x04)
-					return (dma_stat & 4) == 4;
-			}
-somebody_else:
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			if (hwif->resetproc != NULL)
-				hwif->resetproc(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void pdc202xx_new_reset (ide_drive_t *drive)
-{
-	/*
-	 * Deleted this because it is redundant from the caller.
-	 */
-	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
-}
-
-void pdc202xx_reset_pci (struct pci_dev *dev)
-{
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
-
-	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	mdelay(100);
-	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	mdelay(2000);		/* 2 seconds ?! */
-}
-
-void pdc202xx_reset_host (ide_hwif_t *hwif)
-{
-	pdc202xx_reset_pci(hwif->pci_dev);
-	printk("PDC202XX: %s channel reset.\n",
-		hwif->channel ? "Secondary" : "Primary");
-}
-
-void pdc202xx_reset (ide_drive_t *drive)
-{
-	pdc202xx_reset_host(HWIF(drive));
-}
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
-	byte sc1f		= IN_BYTE(high_16 + 0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		OUT_BYTE(sc1f | 0x08, high_16 + 0x001f);
-	} else {
-		OUT_BYTE(sc1f & ~0x08, high_16 + 0x001f);
-	}
-#endif
-	return 0;
-}
-
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
-	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
-	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
-	byte newchip		= 0;
-
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n",
-			name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20268:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			pdc202xx_reset_pci(dev);
-			break;
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			/*
-			 * software reset -  this is required because the bios
-			 * will set UDMA timing on if the hdd supports it. The
-			 * user may want to turn udma off. A bug in the pdc20262
-			 * is that it cannot handle a downgrade in timing from
-			 * UDMA to DMA. Disk accesses after issuing a set
-			 * feature command will result in errors. A software
-			 * reset leaves the timing registers intact,
-			 * but resets the drives.
-			 */
-			pdc202xx_reset_pci(dev);
-		default:
-			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
-				byte irq = 0, irq2 = 0;
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
-				if (irq != irq2) {
-					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
-					printk("%s: pci-config space interrupt mirror fixed.\n", name);
-				}
-			}
-			break;
-	}
-
-	if (newchip)
-		goto fttk_tx_series;
-
-	printk("%s: (U)DMA Burst Bit %sABLED " \
-		"Primary %s Mode " \
-		"Secondary %s Mode.\n",
-		name,
-		(udma_speed_flag & 1) ? "EN" : "DIS",
-		(primary_mode & 1) ? "MASTER" : "PCI",
-		(secondary_mode & 1) ? "MASTER" : "PCI" );
-
-#ifdef CONFIG_PDC202XX_BURST
-	if (!(udma_speed_flag & 1)) {
-		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
-	}
-#endif /* CONFIG_PDC202XX_BURST */
-
-#ifdef CONFIG_PDC202XX_MASTER
-	if (!(primary_mode & 1)) {
-		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			name, primary_mode, (primary_mode|1));
-		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
-	}
-
-	if (!(secondary_mode & 1)) {
-		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
-			name, secondary_mode, (secondary_mode|1));
-		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
-	}
-#endif /* CONFIG_PDC202XX_MASTER */
-
-fttk_tx_series:
-
-	pdc202_devs[n_pdc202_devs++] = dev;
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdc202xx_proc) {
-		pdc202xx_proc = 1;
-		pdc202xx_display_info = &pdc202xx_get_info;
-	}
-#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
-{
-	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
-	unsigned short CIS;
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
-		case PCI_DEVICE_ID_PROMISE_20267:
-			hwif->addressing = (hwif->channel) ? 0 : 1;
-		default:
-			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-			return (!(CIS & mask));
-	}
-}
-
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
-
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-#undef CONFIG_PDC202XX_32_UNMASK
-#ifdef CONFIG_PDC202XX_32_UNMASK
-	hwif->drives[0].io_32bit = 1;
-	hwif->drives[1].io_32bit = 1;
-	hwif->drives[0].unmask = 1;
-	hwif->drives[1].unmask = 1;
-#endif /* CONFIG_PDC202XX_32_UNMASK */
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20277:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20271:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-			hwif->speedproc = &pdc202xx_new_tune_chipset;
-			hwif->resetproc = &pdc202xx_new_reset;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20263:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
-			hwif->resetproc	= &pdc202xx_reset;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			hwif->speedproc = &pdc202xx_tune_chipset;
-		default:
-			break;
-	}
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &pdc202xx_dmaproc;
-# ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-# endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if ((dev->bus->self) &&
-	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)) {
-		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
-				"attached to I2O RAID controller.\n");
-		return;
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
-
-void __init fixup_device_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-
-	if ((dev->bus->self &&
-	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
-		if (PCI_SLOT(dev->devfn) & 2) {
-			return;
-		}
-		d->extra = 0;
-		pci_for_each_dev(findev) {
-			if ((findev->vendor == dev->vendor) &&
-			    (findev->device == dev->device) &&
-			    (PCI_SLOT(findev->devfn) & 2)) {
-				byte irq = 0, irq2 = 0;
-				dev2 = findev;
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-				if (irq != irq2) {
-					dev2->irq = dev->irq;
-					pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-				}
-			}
-		}
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Sun Sep 15 19:19:46 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,716 +0,0 @@
-/*  -*- linux-c -*-
- *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
- *
- *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
- *
- *  This file provides support for the second port and cache of Promise
- *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
- *
- *  Thanks are due to Mark Lord for advice and patiently answering stupid
- *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
- *  especially Andre Hedrick.
- *
- *  Version 0.01	Initial version, #include'd in ide.c rather than
- *                      compiled separately.
- *                      Reads use Promise commands, writes as before. Drives
- *                      on second channel are read-only.
- *  Version 0.02        Writes working on second channel, reads on both
- *                      channels. Writes fail under high load. Suspect
- *			transfers of >127 sectors don't work.
- *  Version 0.03        Brought into line with ide.c version 5.27.
- *                      Other minor changes.
- *  Version 0.04        Updated for ide.c version 5.30
- *                      Changed initialization strategy
- *  Version 0.05	Kernel integration.  -ml
- *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
- *  Version 0.07	Added support for DC4030 variants
- *			Secondary interface autodetection
- *  Version 0.08	Renamed to pdc4030.c
- *  Version 0.09	Obsolete - never released - did manual write request
- *			splitting before max_sectors[major][minor] available.
- *  Version 0.10	Updated for 2.1 series of kernels
- *  Version 0.11	Updated for 2.3 series of kernels
- *			Autodetection code added.
- *
- *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
- */
-
-/*
- * Once you've compiled it in, you'll have to also enable the interface
- * setup routine from the kernel command line, as in 
- *
- *	'linux ide0=dc4030' or 'linux ide1=dc4030'
- *
- * It should now work as a second controller also ('ide1=dc4030') but only
- * if you DON'T have BIOS V4.44, which has a bug. If you have this version
- * and EPROM programming facilities, you need to fix 4 bytes:
- * 	2496:	81	81
- *	2497:	3E	3E
- *	2498:	22	98	*
- *	2499:	06	05	*
- *	249A:	F0	F0
- *	249B:	01	01
- *	...
- *	24A7:	81	81
- *	24A8:	3E	3E
- *	24A9:	22	98	*
- *	24AA:	06	05	*
- *	24AB:	70	70
- *	24AC:	01	01
- *
- * As of January 1999, Promise Technology Inc. have finally supplied me with
- * some technical information which has shed a glimmer of light on some of the
- * problems I was having, especially with writes. 
- *
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
- */
-
-#define DEBUG_READ
-#define DEBUG_WRITE
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "pdc4030.h"
-
-/*
- * promise_selectproc() is invoked by ide.c
- * in preparation for access to the specified drive.
- */
-static void promise_selectproc (ide_drive_t *drive)
-{
-	unsigned int number;
-
-	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
-	OUT_BYTE(number,IDE_FEATURE_REG);
-}
-
-/*
- * pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification -
- * 'P' (=0x50) on success, 'p' (=0x70) on failure.
- */
-int pdc4030_cmd(ide_drive_t *drive, byte cmd)
-{
-	unsigned long timeout, timer;
-	byte status_val;
-
-	promise_selectproc(drive);	/* redundant? */
-	OUT_BYTE(0xF3,IDE_SECTOR_REG);
-	OUT_BYTE(cmd,IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
-	timeout = HZ * 10;
-	timeout += jiffies;
-	do {
-		if(time_after(jiffies, timeout)) {
-			return 2; /* device timed out */
-		}
-		/* This is out of delay_10ms() */
-		/* Delays at least 10ms to give interface a chance */
-		timer = jiffies + (HZ + 99)/100 + 1;
-		while (time_after(timer, jiffies));
-		status_val = IN_BYTE(IDE_SECTOR_REG);
-	} while (status_val != 0x50 && status_val != 0x70);
-
-	if(status_val == 0x50)
-		return 0; /* device returned success */
-	else
-		return 1; /* device returned failure */
-}
-
-/*
- * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
- */
-int pdc4030_identify(ide_drive_t *drive)
-{
-	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
-}
-
-int enable_promise_support = 0;
-
-void __init init_pdc4030 (void)
-{
-	enable_promise_support = 1;
-}
-
-/*
- * setup_pdc4030()
- * Completes the setup of a Promise DC4030 controller card, once found.
- */
-int __init setup_pdc4030 (ide_hwif_t *hwif)
-{
-        ide_drive_t *drive;
-	ide_hwif_t *hwif2;
-	struct dc_ident ident;
-	int i;
-	ide_startstop_t startstop;
-	
-	if (!hwif) return 0;
-
-	drive = &hwif->drives[0];
-	hwif2 = &ide_hwifs[hwif->index+1];
-	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
-		return 1;
-
-	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF ||
-	    IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
-		return 0;
-	}
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(0x08,IDE_CONTROL_REG);
-	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
-		return 0;
-	}
-	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
-		printk(KERN_INFO
-			"%s: Failed Promise read config!\n",hwif->name);
-		return 0;
-	}
-	ata_input_data(drive, &ident, SECTOR_WORDS);
-	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
-		return 0;
-	}
-	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
-	switch(ident.type) {
-		case 0x43:	printk("DC4030VL-2, "); break;
-		case 0x41:	printk("DC4030VL-1, "); break;
-		case 0x40:	printk("DC4030VL, "); break;
-		default:
-			printk("unknown - type 0x%02x - please report!\n"
-			       ,ident.type);
-			printk("Please e-mail the following data to "
-			       "promise@pnd-pc.demon.co.uk along with\n"
-			       "a description of your card and drives:\n");
-			for (i=0; i < 0x90; i++) {
-				printk("%02x ", ((unsigned char *)&ident)[i]);
-				if ((i & 0x0f) == 0x0f) printk("\n");
-			}
-			return 0;
-	}
-	printk("%dKB cache, ",(int)ident.cache_mem);
-	switch(ident.irq) {
-            case 0x00: hwif->irq = 14; break;
-            case 0x01: hwif->irq = 12; break;
-            default:   hwif->irq = 15; break;
-	}
-	printk("on IRQ %d\n",hwif->irq);
-
-	/*
-	 * Once found and identified, we set up the next hwif in the array
-	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
-	 * and other settings as the main hwif. This gives us two "mated"
-	 * hwifs pointing to the Promise card.
-	 *
-	 * We also have to shift the default values for the remaining
-	 * interfaces "up by one" to make room for the second interface on the
-	 * same set of values.
-	 */
-
-	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->mate	= hwif2;
-	hwif2->mate	= hwif;
-	hwif2->channel	= 1;
-	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
-	hwif->serialized = hwif2->serialized = 1;
-
-/* Shift the remaining interfaces down by one */
-	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		ide_hwif_t *h = &ide_hwifs[i];
-
-#ifdef DEBUG
-		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
-#endif /* DEBUG */
-		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
-		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
-		h->noprobe = (h-1)->noprobe;
-	}
-	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
-	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
-	hwif2->irq = hwif->irq;
-	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
-	for (i=0; i<2 ; i++) {
-		hwif->drives[i].io_32bit = 3;
-		hwif2->drives[i].io_32bit = 3;
-		hwif->drives[i].keep_settings = 1;
-		hwif2->drives[i].keep_settings = 1;
-		if (!ident.current_tm[i].cyl)
-			hwif->drives[i].noprobe = 1;
-		if (!ident.current_tm[i+2].cyl)
-			hwif2->drives[i].noprobe = 1;
-	}
-        return 1;
-}
-
-/*
- * detect_pdc4030()
- * Tests for the presence of a DC4030 Promise card on this interface
- * Returns: 1 if found, 0 if not found
- */
-int __init detect_pdc4030(ide_hwif_t *hwif)
-{
-	ide_drive_t *drive = &hwif->drives[0];
-
-	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
-		return 0;
-	}
-	OUT_BYTE(0xF3, IDE_SECTOR_REG);
-	OUT_BYTE(0x14, IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
-	
-	ide_delay_50ms();
-
-	if (IN_BYTE(IDE_ERROR_REG) == 'P' &&
-	    IN_BYTE(IDE_NSECTOR_REG) == 'T' &&
-	    IN_BYTE(IDE_SECTOR_REG) == 'I') {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-void __init ide_probe_for_pdc4030(void)
-{
-	unsigned int	index;
-	ide_hwif_t	*hwif;
-
-	if (enable_promise_support == 0)
-		return;
-	for (index = 0; index < MAX_HWIFS; index++) {
-		hwif = &ide_hwifs[index];
-		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
-			setup_pdc4030(hwif);
-		}
-	}
-}
-
-/*
- * promise_read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t promise_read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int total_remaining;
-	unsigned int sectors_left, sectors_avail, nsect;
-	struct request *rq;
-#ifdef CONFIG_IDE_TASKFILE_IO
-	unsigned long flags;
-	char *to;
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT))
-		return DRIVER(drive)->error(drive, "promise_read_intr", stat);
-
-read_again:
-	do {
-		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
-		IN_BYTE(IDE_SECTOR_REG);
-	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
-	rq = HWGROUP(drive)->rq;
-	sectors_avail = rq->nr_sectors - sectors_left;
-	if (!sectors_avail)
-		goto read_again;
-
-read_next:
-	rq = HWGROUP(drive)->rq;
-	nsect = rq->current_nr_sectors;
-	if (nsect > sectors_avail)
-		nsect = sectors_avail;
-	sectors_avail -= nsect;
-#ifdef CONFIG_IDE_TASKFILE_IO
-	to = ide_map_buffer(rq, &flags);
-	ata_input_data(drive, to, nsect * SECTOR_WORDS);
-#else /* !CONFIG_IDE_TASKFILE_IO */
-	ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
-	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1,
-#ifdef CONFIG_IDE_TASKFILE_IO
-		(unsigned long) to,
-#else /* !CONFIG_IDE_TASKFILE_IO */
-		(unsigned long) rq->buffer,
-#endif /* CONFIG_IDE_TASKFILE_IO */
-	       rq->nr_sectors-nsect);
-#endif /* DEBUG_READ */
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-	ide_unmap_buffer(to, &flags);
-#else /* !CONFIG_IDE_TASKFILE_IO */
-	rq->buffer += nsect<<9;
-#endif /* CONFIG_IDE_TASKFILE_IO */
-	rq->sector += nsect;
-	rq->errors = 0;
-	rq->nr_sectors -= nsect;
-	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		DRIVER(drive)->end_request(drive, 1);
-	}
-/*
- * Now the data has been read in, do the following:
- * 
- * if there are still sectors left in the request, 
- *   if we know there are still sectors available from the interface,
- *     go back and read the next bit of the request.
- *   else if DRQ is asserted, there are more sectors available, so
- *     go back and find out how many, then read them in.
- *   else if BUSY is asserted, we are going to get an interrupt, so
- *     set the handler for the interrupt and just return
- */
-	if (total_remaining > 0) {
-		if (sectors_avail)
-			goto read_next;
-		stat = GET_STAT();
-		if (stat & DRQ_STAT)
-			goto read_again;
-		if (stat & BUSY_STAT) {
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
-#ifdef DEBUG_READ
-			printk(KERN_DEBUG "%s: promise_read: waiting for"
-			       "interrupt\n", drive->name);
-#endif /* DEBUG_READ */
-			return ide_started;
-		}
-		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
-		       "!DRQ !BUSY\n", drive->name);
-		return DRIVER(drive)->error(drive, "promise read intr", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_complete_pollfunc()
- * This is the polling function for waiting (nicely!) until drive stops
- * being busy. It is invoked at the end of a write, after the previous poll
- * has finished.
- *
- * Once not busy, the end request is called.
- */
-static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-	int i;
-
-	if (GET_STAT() & BUSY_STAT) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: completion timeout - still busy!\n",
-		       drive->name);
-		return DRIVER(drive)->error(drive, "busy timeout", GET_STAT());
-	}
-
-	hwgroup->poll_timeout = 0;
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
-#endif /* DEBUG_WRITE */
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		DRIVER(drive)->end_request(drive, 1);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multiple-sector write operation.
- *
- * Returns 0 on success.
- *
- * Note that we may be called from two contexts - the do_rw_disk context
- * and IRQ context. The IRQ can happen any time after we've output the
- * full "mcount" number of sectors, so we must make sure we update the
- * state _before_ we output the final part of the data!
- */
-int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
-{
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	struct request *rq	= &hwgroup->wrq;
-
-	do {
-		char *buffer;
-		int nsect = rq->current_nr_sectors;
-#ifdef CONFIG_IDE_TASKFILE_IO
-		unsigned long flags;
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-#ifdef CONFIG_IDE_TASKFILE_IO
-		buffer = ide_map_buffer(rq, &flags);
-		rq->sector += nsect;
-#else /* !CONFIG_IDE_TASKFILE_IO */
-		buffer = rq->buffer;
-
-		rq->sector += nsect;
-		rq->buffer += nsect << 9;
-#endif /* CONFIG_IDE_TASKFILE_IO */
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bh after this? */
-		if (!rq->current_nr_sectors) {
-			struct bio *bio = rq->bio;
-
-			/*
-			 * only move to next bio, when we have processed
-			 * all bvecs in this one.
-			 */
-			if (++bio->bi_idx >= bio->bi_vcnt) {
-				bio->bi_idx = 0;
-				bio = bio->bi_next;
-			}
-
-			/* end early early we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
-				rq->hard_cur_sectors = rq->current_nr_sectors;
-			}
-		}
-
-		/*
-		 * Ok, we're all setup for the interrupt
-		 * re-entering us on the last transfer.
-		 */
-		taskfile_output_data(drive, buffer, nsect<<7);
-#ifdef CONFIG_IDE_TASKFILE_IO
-		ide_unmap_buffer(buffer, &flags);
-#endif /* CONFIG_IDE_TASKFILE_IO */
-	} while (mcount);
-
-	return 0;
-}
-
-/*
- * promise_write_pollfunc() is the handler for disk write completion polling.
- */
-static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		return DRIVER(drive)->error(drive, "write timeout", GET_STAT());
-	}
-
-	/*
-	 * Now write out last 4 sectors and poll for not BUSY
-	 */
-	promise_multwrite(drive, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-		BUG();
-	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
-		drive->name, GET_STAT());
-#endif /* DEBUG_WRITE */
-	return ide_started;
-}
-
-/*
- * promise_write() transfers a block of one or more sectors of data to a
- * drive as part of a disk write operation. All but 4 sectors are transferred
- * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transferred. There is no interrupt generated
- * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
- */
-static ide_startstop_t promise_write (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
-	       "buffer=%p\n", drive->name, rq->sector,
-	       rq->sector + rq->nr_sectors - 1, rq->buffer);
-#endif /* DEBUG_WRITE */
-
-	/*
-	 * If there are more than 4 sectors to transfer, do n-4 then go into
-	 * the polling strategy as defined above.
-	 */
-	if (rq->nr_sectors > 4) {
-		if (promise_multwrite(drive, rq->nr_sectors - 4))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-			BUG();
-		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-		return ide_started;
-	} else {
-	/*
-	 * There are 4 or fewer sectors to transfer, do them all in one go
-	 * and wait for NOT BUSY.
-	 */
-		if (promise_multwrite(drive, rq->nr_sectors))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-			BUG();
-		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
-			"status = %02x\n", drive->name, GET_STAT());
-#endif /* DEBUG_WRITE */
-		return ide_started;
-	}
-}
-
-/*
- * do_pdc4030_io() is called from do_rw_disk, having had the block number
- * already set up. It issues a READ or WRITE command to the Promise
- * controller, assuming LBA has been used to set up the block number.
- */
-#ifndef CONFIG_IDE_TASKFILE_IO
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
-{
-#else /* CONFIG_IDE_TASKFILE_IO */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
-{
-	struct request *rq	= HWGROUP(drive)->rq;
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-#endif /* CONFIG_IDE_TASKFILE_IO */
-	ide_startstop_t startstop;
-	unsigned long timeout;
-	byte stat;
-
-	BUG_ON(!(rq->flags & REQ_CMD));
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
-	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-	if (rq_data_dir(rq) == READ) {
-#ifndef CONFIG_IDE_TASKFILE_IO
-		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-#endif /* CONFIG_IDE_TASKFILE_IO */
-/*
- * The card's behaviour is odd at this point. If the data is
- * available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the 
- * "interrupt" handler (promise_read_intr) directly. Otherwise, if
- * an interrupt is going to occur, bit0 of the SELECT register will
- * be high, so we can set the handler the just return and be interrupted.
- * If neither of these is the case, we wait for up to 50ms (badly I'm
- * afraid!) until one of them is.
- */
-		timeout = jiffies + HZ/20; /* 50ms wait */
-		do {
-			stat=GET_STAT();
-			if (stat & DRQ_STAT) {
-				udelay(1);
-				return promise_read_intr(drive);
-			}
-			if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
-#ifdef DEBUG_READ
-				printk(KERN_DEBUG "%s: read: waiting for "
-						"interrupt\n", drive->name);
-#endif /* DEBUG_READ */
-				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-				return ide_started;
-			}
-			udelay(1);
-		} while (time_before(jiffies, timeout));
-
-		printk(KERN_ERR "%s: reading: No DRQ and not "
-				"waiting - Odd!\n", drive->name);
-		return ide_stopped;
-	} else if (rq_data_dir(rq) == WRITE) {
-#ifndef CONFIG_IDE_TASKFILE_IO
-		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-#endif /* CONFIG_IDE_TASKFILE_IO */
-		if (ide_wait_stat(&startstop, drive, DATA_READY,
-				drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing "
-				"PROMISE_WRITE\n", drive->name);
-			return startstop;
-	    	}
-		if (!drive->unmask)
-			local_irq_disable();
-		HWGROUP(drive)->wrq = *rq; /* scratchpad */
-		return promise_write(drive);
-	} else {
-		blk_dump_rq_flags(rq, "do_pdc4030_io - bad command\n");
-		DRIVER(drive)->end_request(drive, 0);
-		return ide_stopped;
-	}
-}
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	ide_task_t			args;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
-	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= NULL;
-	args.handler		= NULL;
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_pdc4030_io(drive, &args);
-}
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
diff -Nru a/drivers/ide/pdc4030.h b/drivers/ide/pdc4030.h
--- a/drivers/ide/pdc4030.h	Sun Sep 15 19:20:08 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,44 +0,0 @@
-/*
- *  linux/drivers/ide/pdc4030.h
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & authors
- */
-
-/*
- * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
- */
-
-#ifndef IDE_PROMISE_H
-#define IDE_PROMISE_H
-
-#define	PROMISE_EXTENDED_COMMAND	0xF0
-#define	PROMISE_READ			0xF2
-#define	PROMISE_WRITE			0xF3
-/* Extended commands - main command code = 0xf0 */
-#define	PROMISE_GET_CONFIG		0x10
-#define	PROMISE_IDENTIFY		0x20
-
-struct translation_mode {
-	u16	cyl;
-	u8	head;
-	u8	sect;
-};
-
-struct dc_ident {
-	u8	type;
-	u8	unknown1;
-	u8	hw_revision;
-	u8	firmware_major;
-	u8	firmware_minor;
-	u8	bios_address;
-	u8	irq;
-	u8	unknown2;
-	u16	cache_mem;
-	u16	unknown3;
-	u8	id[2];
-	u16	info;
-	struct translation_mode current_tm[4];
-	u8	pad[SECTOR_WORDS*4 - 32];
-};
-
-#endif /* IDE_PROMISE_H */
diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
--- a/drivers/ide/pdcadma.c	Sun Sep 15 19:20:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,106 +0,0 @@
-/*
- * linux/drivers/ide/pdcadma.c		Version 0.01	June 21, 2001
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#undef DISPLAY_PDCADMA_TIMINGS
-
-#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdcadma_get_info(char *, char **, off_t, int);
-extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-
-	p += sprintf(p, "\n                                PDC ADMA %04X Chipset.\n", bmide_dev->device);
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte pdcadma_proc = 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * pdcadma_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int pdcadma_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			func = ide_dma_off_quietly;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdcadma_proc) {
-		pdcadma_proc = 1;
-		bmide_dev = dev;
-		pdcadma_display_info = &pdcadma_get_info;
-	}
-#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
-{
-	return 1;
-}
-
-void __init ide_init_pdcadma (ide_hwif_t *hwif)
-{
-	hwif->autodma = 0;
-	hwif->dma_base = 0;
-
-//	hwif->tuneproc = &pdcadma_tune_drive;
-//	hwif->speedproc = &pdcadma_tune_chipset;
-
-//	if (hwif->dma_base) {
-//		hwif->dmaproc = &pdcadma_dmaproc;
-//		hwif->autodma = 1;
-//	}
-}
-
-void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
-{
-//	ide_setup_dma(hwif, dmabase, 8);
-}
-
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,617 +0,0 @@
-/*
- *  linux/drivers/ide/piix.c		Version 0.32	June 9, 2000
- *
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  PIO mode setting function for Intel chipsets.  
- *  For use instead of BIOS settings.
- *
- * 40-41
- * 42-43
- * 
- *                 41
- *                 43
- *
- * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
- * 
- * sitre = word40 & 0x4000; primary
- * sitre = word42 & 0x4000; secondary
- *
- * 44 8421|8421    hdd|hdb
- * 
- * 48 8421         hdd|hdc|hdb|hda udma enabled
- *
- *    0001         hda
- *    0010         hdb
- *    0100         hdc
- *    1000         hdd
- *
- * 4a 84|21        hdb|hda
- * 4b 84|21        hdd|hdc
- *
- *    ata-33/82371AB
- *    ata-33/82371EB
- *    ata-33/82801AB            ata-66/82801AA
- *    00|00 udma 0              00|00 reserved
- *    01|01 udma 1              01|01 udma 3
- *    10|10 udma 2              10|10 udma 4
- *    11|11 reserved            11|11 reserved
- *
- * 54 8421|8421    ata66 drive|ata66 enable
- *
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define PIIX_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_PIIX_TIMINGS
-
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int piix_get_info(char *, char **, off_t, int);
-extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
-
-	p += sprintf(p, "\n                                ");
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-		case PCI_DEVICE_ID_INTEL_82801CA_10:
-		case PCI_DEVICE_ID_INTEL_82801CA_11:
-		case PCI_DEVICE_ID_INTEL_82801E_11:
-		case PCI_DEVICE_ID_INTEL_82801DB_11:
-			p += sprintf(p, "Intel PIIX4 Ultra 100 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-			p += sprintf(p, "Intel PIIX4 Ultra 66 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82371AB:
-			p += sprintf(p, "Intel PIIX4 Ultra 33 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			p += sprintf(p, "Intel PIIX3 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371MX:
-			p += sprintf(p, "Intel MPIIX Chipset.\n");
-			return p-buffer;	/* => must be less than 4k! */
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		default:
-			p += sprintf(p, "Intel PIIX Chipset.\n");
-			break;
-	}
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_byte(bmide_dev, 0x55, &reg55);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled "
-			"                        %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s "
-			"            %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s              %s "
-			"            %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s "
-			"              %s                 %s\n",
-			((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
-			((reg54&0x11) && (reg4a&0x02)) ? "4" :
-			((reg54&0x11) && (reg4a&0x01)) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" :
-			((reg54&0x22) && (reg4a&0x20)) ? "4" :
-			((reg54&0x22) && (reg4a&0x10)) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" :
-			((reg54&0x44) && (reg4b&0x02)) ? "4" :
-			((reg54&0x44) && (reg4b&0x01)) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" :
-			((reg54&0x88) && (reg4b&0x20)) ? "4" :
-			((reg54&0x88) && (reg4b&0x10)) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte piix_proc = 0;
-
-
-static byte piix_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= 0x00;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-		case PCI_DEVICE_ID_INTEL_82801CA_10:
-		case PCI_DEVICE_ID_INTEL_82801CA_11:
-		case PCI_DEVICE_ID_INTEL_82801E_11:
-		case PCI_DEVICE_ID_INTEL_82801DB_11:
-			mode |= 0x03;
-			break;
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-			mode |= 0x02;
-			break;
-		case PCI_DEVICE_ID_INTEL_82371AB:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-			mode |= 0x01;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		case PCI_DEVICE_ID_INTEL_82371MX:
-		default:
-			return (mode &= ~0xF8);
-	}
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte piix_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = piix_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static byte piix_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void piix_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
-	int master_port		= hwif->channel ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	spin_lock_irqsave(&ide_lock, flags);
-	pci_read_config_word(dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(dev, slave_port, &slave_data);
-		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
-	}
-	pci_write_config_word(dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(dev, slave_port, slave_data);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static int piix_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	byte speed		= piix_ratefilter(drive, xferspeed);
-	int a_speed		= 3 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int v_flag		= 0x01 << drive->dn;
-	int w_flag		= 0x10 << drive->dn;
-	int u_speed		= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a, reg54;
-	byte			reg55;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-	pci_read_config_word(dev, 0x54, &reg54);
-	pci_read_config_byte(dev, 0x55, &reg55);
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_0:	break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if (speed == XFER_UDMA_5) {
-			pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag);
-		} else {
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-		}
-		if (!(reg4a & u_speed)) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-		if (speed > XFER_UDMA_2) {
-			if (!(reg54 & v_flag)) {
-				pci_write_config_word(dev, 0x54, reg54|v_flag);
-			}
-		} else {
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		}
-	} else {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		if (reg54 & v_flag)
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		if (reg55 & w_flag)
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-	}
-
-	piix_tune_drive(drive, piix_dma_2_pio(speed));
-	return (ide_config_drive_speed(drive, speed));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= piix_ratemask(drive);
-	byte speed, tspeed, dma = 1;
-
-	switch(mode) {
-		case 0x03:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_5; break; }
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-		default:
-			tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
-			speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
-			dma = 0;
-			break;
-	}
-
-	(void) piix_tune_chipset(drive, speed);
-
-//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = piix_config_drive_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = piix_config_drive_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = piix_config_drive_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		piix_tune_drive(drive, 255);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
-{
-        switch(dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-		case PCI_DEVICE_ID_INTEL_82801CA_10:
-		case PCI_DEVICE_ID_INTEL_82801CA_11:
-		case PCI_DEVICE_ID_INTEL_82801E_11:
-		case PCI_DEVICE_ID_INTEL_82801DB_11:
-		{
-			unsigned int extra = 0;
-			pci_read_config_dword(dev, 0x54, &extra);
-			pci_write_config_dword(dev, 0x54, extra|0x400);
-		}
-		default:
-			break;
-	}
-
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!piix_proc) {
-		piix_proc = 1;
-		bmide_dev = dev;
-		piix_display_info = &piix_get_info;
-	}
-#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/*
- * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards.
- * It does not specify device detection, but channel!!!
- * You determine later if bit 13 of word93 is set...
- */
-unsigned int __init ata66_piix (ide_hwif_t *hwif)
-{
-	byte reg54h = 0, reg55h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0xc0 : 0x30;
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
-
-	ata66 = (reg54h & mask) ? 1 : 0;
-
-	return ata66;
-}
-
-void __init ide_init_piix (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_IA64
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-#endif /* CONFIG_IA64 */
-
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
-		/* This is a painful system best to let it self tune for now */
-		return;
-	}
-
-	hwif->autodma = 0;
-	hwif->tuneproc = &piix_tune_drive;
-	hwif->speedproc = &piix_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &piix_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_piix (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if (dev->resource[0].start != 0x01F1)
-		ide_register_xp_fix(dev);
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
diff -Nru a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ppc/Makefile	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,13 @@
+
+O_TARGET := idedriver-ppc.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ppc/mpc8xx.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,857 @@
+/*
+ *  linux/drivers/ide/ide-m8xx.c
+ *
+ *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
+ *  Modified for direct IDE interface
+ *	by Thomas Lange, thomas@corelatus.com
+ *  Modified for direct IDE interface on 8xx without using the PCMCIA
+ *  controller
+ *	by Steven.Scholz@imc-berlin.de
+ *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ *	by Mathew Locke <mattl@mvista.com>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+static int identify  (volatile u8 *p);
+static void print_fixed (volatile u8 *p);
+static void print_funcid (int func);
+static int check_ide_device (unsigned long base);
+
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+
+typedef	struct ide_ioport_desc {
+	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
+	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
+	int		irq;			/* IRQ				*/
+} ide_ioport_desc_t;
+
+ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
+#ifdef IDE0_BASE_OFFSET
+	{ IDE0_BASE_OFFSET,
+	    {
+		IDE0_DATA_REG_OFFSET,
+		IDE0_ERROR_REG_OFFSET,
+		IDE0_NSECTOR_REG_OFFSET,
+		IDE0_SECTOR_REG_OFFSET,
+		IDE0_LCYL_REG_OFFSET,
+		IDE0_HCYL_REG_OFFSET,
+		IDE0_SELECT_REG_OFFSET,
+		IDE0_STATUS_REG_OFFSET,
+		IDE0_CONTROL_REG_OFFSET,
+		IDE0_IRQ_REG_OFFSET,
+	    },
+	    IDE0_INTERRUPT,
+	},
+#ifdef IDE1_BASE_OFFSET
+	{ IDE1_BASE_OFFSET,
+	    {
+		IDE1_DATA_REG_OFFSET,
+		IDE1_ERROR_REG_OFFSET,
+		IDE1_NSECTOR_REG_OFFSET,
+		IDE1_SECTOR_REG_OFFSET,
+		IDE1_LCYL_REG_OFFSET,
+		IDE1_HCYL_REG_OFFSET,
+		IDE1_SELECT_REG_OFFSET,
+		IDE1_STATUS_REG_OFFSET,
+		IDE1_CONTROL_REG_OFFSET,
+		IDE1_IRQ_REG_OFFSET,
+	    },
+	    IDE1_INTERRUPT,
+	},
+#endif /* IDE1_BASE_OFFSET */
+#endif	/* IDE0_BASE_OFFSET */
+};
+
+ide_pio_timings_t ide_pio_clocks[6];
+int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
+
+/*
+ * Warning: only 1 (ONE) PCMCIA slot supported here,
+ * which must be correctly initialized by the firmware (PPCBoot).
+ */
+static int _slot_ = -1;			/* will be read from PCMCIA registers   */
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
+
+
+
+/*
+ * IDE stuff.
+ */
+static int
+m8xx_ide_default_irq(ide_ioreg_t base)
+{
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+	if (base >= MAX_HWIFS)
+		return 0;
+
+	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
+	
+	return (ioport_dsc[base].irq);
+#else
+        return 9;
+#endif
+}
+
+static ide_ioreg_t
+m8xx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
+#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef	CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
+#endif
+
+#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
+static int pcmcia_schlvl = PCMCIA_SCHLVL;
+#endif
+
+/*
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
+ */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
+ */
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+static void
+m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
+		ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	typedef struct {
+		ulong br;
+		ulong or;
+	} pcmcia_win_t;
+	volatile pcmcia_win_t *win;
+	volatile pcmconf8xx_t *pcmp;
+
+	uint *pgcrx;
+	u32 pcmcia_phy_base;
+	u32 pcmcia_phy_end;
+	static unsigned long pcmcia_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	if (!pcmcia_base) {
+                /*
+                 * Read out PCMCIA registers. Since the reset values
+                 * are undefined, we sure hope that they have been
+                 * set up by firmware
+		 */
+
+		/* Scan all registers for valid settings */
+		pcmcia_phy_base = 0xFFFFFFFF;
+		pcmcia_phy_end = 0;
+		/* br0 is start of brX and orX regs */
+		win = (pcmcia_win_t *) \
+			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
+		for (i = 0; i < 8; i++) {
+			if (win->or & 1) {	/* This bank is marked as valid */
+				if (win->br < pcmcia_phy_base) {
+					pcmcia_phy_base = win->br;
+				}
+				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
+					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
+				}
+				/* Check which slot that has been defined */
+				_slot_ = (win->or >> 2) & 1;
+
+			}					/* Valid bank */
+			win++;
+		}						/* for */
+
+		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
+			'A' + _slot_,
+			pcmcia_phy_base, pcmcia_phy_end,
+			pcmcia_phy_end - pcmcia_phy_base);
+
+		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
+						   pcmcia_phy_end-pcmcia_phy_base);
+
+#ifdef DEBUG
+		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
+#endif
+		/* Compute clock cycles for PIO timings */
+		for (i=0; i<6; ++i) {
+			bd_t	*binfo = (bd_t *)__res;
+
+			hold_time[i]   =
+				PCMCIA_MK_CLKS (hold_time[i],
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].setup_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].active_time =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].cycle_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+						binfo->bi_busfreq);
+#if 0
+			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
+				i,
+				ide_pio_clocks[i].setup_time,
+				ide_pio_clocks[i].active_time,
+				ide_pio_clocks[i].hold_time,
+				ide_pio_clocks[i].cycle_time,
+				ide_pio_timings[i].setup_time,
+				ide_pio_timings[i].active_time,
+				ide_pio_timings[i].hold_time,
+				ide_pio_timings[i].cycle_time);
+#endif
+		}
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	if (_slot_ == -1) {
+		printk ("PCMCIA slot has not been defined! Using A as default\n");
+		_slot_ = 0;
+	}
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#ifdef DEBUG
+	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
+		pcmp->pcmc_pipr,
+		'A' + _slot_,
+		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
+#endif /* DEBUG */
+
+	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
+		printk ("No card in slot %c: PIPR=%08x\n",
+			'A' + _slot_, (u32) pcmp->pcmc_pipr);
+		return;		/* No card in slot */
+	}
+
+	check_ide_device (pcmcia_base);
+
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	base = pcmcia_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+			pcmcia_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		unsigned int reg;
+
+		*irq = ioport_dsc[data_port].irq;
+		if (_slot_)
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
+		else
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
+
+		reg = *pgcrx;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
+		*pgcrx = reg;
+#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
+		*irq = ioport_dsc[data_port].irq;
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+					(0x80000000 >> ioport_dsc[data_port].irq);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	/* Make sure we dont get garbage irq */
+	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
+
+	/* Enable falling edge irq */
+	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
+#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
+ * MPC8xx's internal PCMCIA interface
+ */
+#if defined(CONFIG_IDE_EXT_DIRECT)
+void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	u32 ide_phy_base;
+	u32 ide_phy_end;
+	static unsigned long ide_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	if (!ide_base) {
+
+		/* TODO:
+		 * - add code to read ORx, BRx
+		 */
+		ide_phy_base = CFG_ATA_BASE_ADDR;
+		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
+
+		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
+			ide_phy_base, ide_phy_end,
+			ide_phy_end - ide_phy_base);
+		
+		ide_base=(unsigned long)ioremap(ide_phy_base,
+						ide_phy_end-ide_phy_base);
+
+#ifdef DEBUG
+		printk ("IDE virt base: %08lx\n", ide_base);
+#endif
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	base = ide_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+		ide_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+		/* direct connected IDE drive, i.e. external IRQ */
+		*irq = ioport_dsc[data_port].irq;
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
+			(0x80000000 >> ioport_dsc[data_port].irq);
+}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+
+/* -------------------------------------------------------------------- */
+
+
+/* PCMCIA Timing */
+#ifndef	PCMCIA_SHT
+#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
+#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
+#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
+#endif
+
+
+/* Calculate PIO timings */
+static void
+m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	volatile pcmconf8xx_t	*pcmp;
+	ulong timing, mask, reg;
+#endif
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+#if 1
+	printk("%s[%d] %s: best PIO mode: %d\n",
+		__FILE__,__LINE__,__FUNCTION__, pio);
+#endif
+
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+	timing  = PCMCIA_SHT(hold_time[pio]  )
+		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
+		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
+		;
+
+#if 1
+	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
+#endif
+	if ((reg = pcmp->pcmc_por0 & mask) != 0)
+		pcmp->pcmc_por0 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por1 & mask) != 0)
+		pcmp->pcmc_por1 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por2 & mask) != 0)
+		pcmp->pcmc_por2 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por3 & mask) != 0)
+		pcmp->pcmc_por3 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por4 & mask) != 0)
+		pcmp->pcmc_por4 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por5 & mask) != 0)
+		pcmp->pcmc_por5 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por6 & mask) != 0)
+		pcmp->pcmc_por6 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por7 & mask) != 0)
+		pcmp->pcmc_por7 = reg | timing;
+
+#elif defined(CONFIG_IDE_EXT_DIRECT)
+
+	printk("%s[%d] %s: not implemented yet!\n",
+		__FILE__,__LINE__,__FUNCTION__);
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
+}
+
+static void
+ide_interrupt_ack (void *dev)
+{
+#ifdef CONFIG_IDE_8xx_PCCARD
+	u_int pscr, pipr;
+
+#if (PCMCIA_SOCKETS_NO == 2)
+	u_int _slot_;
+#endif
+
+	/* get interrupt sources */
+
+	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+
+	/*
+	 * report only if both card detect signals are the same
+	 * not too nice done,
+	 * we depend on that CD2 is the bit to the left of CD1...
+	 */
+
+	if(_slot_==-1){
+	  printk("PCMCIA slot has not been defined! Using A as default\n");
+	  _slot_=0;
+	}
+
+	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
+	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
+	  printk ("card detect interrupt\n");
+	}
+	/* clear the interrupt sources */
+	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
+
+#else /* ! CONFIG_IDE_8xx_PCCARD */
+	/*
+	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
+	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
+	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
+	 * The interrupt is handled somewhere else.	-- Steven
+	 */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+}
+
+
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE	0x01
+
+#define CISTPL_FUNCE_IDE_IFACE	0x01
+#define CISTPL_FUNCE_IDE_MASTER	0x02
+#define CISTPL_FUNCE_IDE_SLAVE	0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON	0x04
+#define CISTPL_IDE_UNIQUE	0x08
+#define CISTPL_IDE_DUAL		0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP	0x01
+#define CISTPL_IDE_HAS_STANDBY	0x02
+#define CISTPL_IDE_HAS_IDLE	0x04
+#define CISTPL_IDE_LOW_POWER	0x08
+#define CISTPL_IDE_REG_INHIBIT	0x10
+#define CISTPL_IDE_HAS_INDEX	0x20
+#define CISTPL_IDE_IOIS16	0x40
+
+
+/* -------------------------------------------------------------------- */
+
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (unsigned long base)
+{
+	volatile u8 *ident = NULL;
+	volatile u8 *feature_p[MAX_FEATURES];
+	volatile u8 *p, *start;
+	int n_features = 0;
+	u8 func_id = ~0;
+	u8 code, len;
+	unsigned short config_base = 0;
+	int found = 0;
+	int i;
+
+#ifdef DEBUG
+	printk ("PCMCIA MEM: %08lX\n", base);
+#endif
+	start = p = (volatile u8 *) base;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#ifdef	DEBUG_PCMCIA
+		{ volatile u8 *q = p;
+			printk ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printk (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG_PCMCIA */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			func_id = *p;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((u8)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printk ("unknown card type\n");
+		return (1);
+	}
+
+	/* set level mode irq and I/O mapped device in config reg*/
+	*((u8 *)(base + config_base)) = 0x41;
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_funcid (int func)
+{
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		printk (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		printk (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		printk (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		printk (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		printk (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		printk (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		printk (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		printk (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		printk (" SCSI Adapter");
+		break;
+	default:
+		printk (" Unknown");
+		break;
+	}
+	printk (" Card\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_fixed (volatile u8 *p)
+{
+	if (p == NULL)
+		return;
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   u8 iface = *(p+2);
+
+		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		printk (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   u8 f1 = *(p+2);
+		u8 f2 = *(p+4);
+
+		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			printk (" [unique]");
+
+		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			printk (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			printk (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			printk (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			printk (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			printk (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			printk (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			printk (" [IOis16]");
+
+		break;
+	    }
+	}
+	printk ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static u8 *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile u8 *p)
+{
+	u8 id_str[MAX_IDENT_CHARS];
+	u8 data;
+	u8 *t;
+	u8 **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	printk ("Card ID: %s\n", id_str);
+
+	for (card=known_cards; *card; ++card) {
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+
+void m8xx_ide_init(void)
+{
+	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
+	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+}
diff -Nru a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ppc/pmac.c	Sun Sep 15 19:19:29 2002
@@ -0,0 +1,1783 @@
+/*
+ * linux/drivers/ide/ide-pmac.c
+ *
+ * Support for IDE interfaces on PowerMacs.
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+ * for doing DMA.
+ *
+ *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
+ *
+ *  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.
+ *
+ * Some code taken from drivers/ide/ide-dma.c:
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/ide.h>
+#include <asm/mediabay.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#include "ide_modes.h"
+
+extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+
+#define IDE_PMAC_DEBUG
+
+#define DMA_WAIT_TIMEOUT	500
+
+typedef struct pmac_ide_hwif {
+	ide_ioreg_t			regbase;
+	int				irq;
+	int				kind;
+	int				aapl_bus_id;
+	struct device_node*		node;
+	u32				timings[2];
+	int				index;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
+	volatile struct dbdma_regs*	dma_regs;
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
+#endif
+	
+} pmac_ide_hwif_t;
+
+static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata;
+static int pmac_ide_count;
+
+enum {
+	controller_ohare,	/* OHare based */
+	controller_heathrow,	/* Heathrow/Paddington */
+	controller_kl_ata3,	/* KeyLargo ATA-3 */
+	controller_kl_ata4,	/* KeyLargo ATA-4 */
+	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
+#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ * 
+ * 3 Values can be programmed:
+ *  - Write data setup, which appears to match the cycle time. They
+ *    also call it DIOW setup.
+ *  - Ready to pause time (from spec)
+ *  - Address setup. That one is weird. I don't see where exactly
+ *    it fits in UDMA cycles, I got it's name from an obscure piece
+ *    of commented out code in Darwin. They leave it to 0, we do as
+ *    well, despite a comment that would lead to think it has a
+ *    min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads. I can't explain that, I tried it and it broke everything
+ * here.
+ */
+#define TR_66_UDMA_MASK			0xfff00000
+#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT	29
+#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT	25
+#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT	21
+#define TR_66_MDMA_MASK			0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT	15
+#define TR_66_MDMA_ACCESS_MASK		0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT		10
+#define TR_66_PIO_MASK			0x000003ff
+#define TR_66_PIO_RECOVERY_MASK		0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT	5
+#define TR_66_PIO_ACCESS_MASK		0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT		0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ * 
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK			0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT	16
+#define TR_33_MDMA_ACCESS_MASK		0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT		11
+#define TR_33_MDMA_HALFTICK		0x00200000
+#define TR_33_PIO_MASK			0x000007ff
+#define TR_33_PIO_E			0x00000400
+#define TR_33_PIO_RECOVERY_MASK		0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT	5
+#define TR_33_PIO_ACCESS_MASK		0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT		0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/* Rounded Multiword DMA timings
+ * 
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
+	int	accessTime;
+	int	recoveryTime;
+	int	cycleTime;
+};
+
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  75,  75, 150 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 150, 150, 300 },
+    { 120, 120, 240 },
+    {  90, 120, 210 },
+    {  90,  90, 180 },
+    {  90,  60, 150 },
+    {  90,  30, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  90,  75, 165 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+/* Ultra DMA timings (rounded) */
+struct {
+	int	addrSetup; /* ??? */
+	int	rdy2pause;
+	int	wrDataSetup;
+} udma_timings[] __pmacdata =
+{
+    {   0, 180,  120 },	/* Mode 0 */
+    {   0, 150,  90 },	/*      1 */
+    {   0, 120,  60 },	/*      2 */
+    {   0, 90,   45 },	/*      3 */
+    {   0, 90,   30 }	/*      4 */
+};
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS		256
+
+/* Wait 2s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS	2000
+
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static int pmac_ide_dma_begin (ide_drive_t *drive);
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+#ifdef CONFIG_PMAC_PBOOK
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * N.B. this can't be an initfunc, because the media-bay task can
+ * call ide_[un]register at any time.
+ */
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
+			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
+			      int *irq)
+{
+	int i, ix;
+
+	if (data_port == 0)
+		return;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (data_port == pmac_ide[ix].regbase)
+			break;
+
+	if (ix >= MAX_HWIFS) {
+		/* Probably a PCI interface... */
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+		return;
+	}
+
+	for (i = 0; i < 8; ++i)
+		hw->io_ports[i] = data_port + i * 0x10;
+	hw->io_ports[8] = data_port + 0x160;
+
+	if (irq != NULL)
+		*irq = pmac_ide[ix].irq;
+}
+
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void __pmac
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (drive->select.b.unit & 0x01)
+		writel(pmif->timings[1],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	else
+		writel(pmif->timings[0],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+}
+
+
+static int __pmac
+pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int result = 1;
+	
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	/* Get rid of pending error state */
+	(void) hwif->INB(IDE_STATUS_REG);
+	/* Timeout bumped for some powerbooks */
+	if (wait_for_ready(drive, 2000)) {
+		/* Timeout bumped for some powerbooks */
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"before SET_FEATURE!\n");
+		goto out;
+	}
+	udelay(10);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(command, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	udelay(1);
+	/* Timeout bumped for some powerbooks */
+	result = wait_for_ready(drive, 2000);
+	hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (result)
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"after SET_FEATURE !\n");
+out:
+	SELECT_MASK(drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:
+				drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:
+				drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:
+				drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:
+				drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:
+				drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:
+				drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:
+				drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:
+				drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2:
+				drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1:
+				drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0:
+				drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2:
+				drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1:
+				drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0:
+				drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
+	enable_irq(hwif->irq);
+	return result;
+}
+
+/* Calculate PIO timings */
+static void __pmac
+pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	u32 *timings;
+	unsigned accessTicks, recTicks;
+	unsigned accessTime, recTime;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	
+	if (pmif == NULL)
+		return;
+		
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	recTime = d.cycle_time - ide_pio_timings[pio].active_time
+			- ide_pio_timings[pio].setup_time;
+	recTime = max(recTime, 150U);
+	accessTime = ide_pio_timings[pio].active_time;
+	accessTime = max(accessTime, 150U);
+	if (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_66_PIO_MASK) |
+				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell */
+		int ebit = 0;
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 4U);
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 5U) - 4;
+		if (recTicks > 9) {
+			recTicks--; /* guess, but it's only for PIO0, so... */
+			ebit = 1;
+		}
+		*timings = ((*timings) & ~TR_33_PIO_MASK) |
+				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
+		if (ebit)
+			*timings |= TR_33_PIO_E;
+	}
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+		pio,  *timings);
+#endif	
+
+	if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+		pmac_ide_selectproc(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+static int __pmac
+set_timings_udma(u32 *timings, u8 speed)
+{
+	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
+
+	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
+	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
+	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
+
+	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
+			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+			TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+
+	return 0;
+}
+
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, u8 speed, int drive_cycle_time)
+{
+	int cycleTime, accessTime, recTime;
+	unsigned accessTicks, recTicks;
+	struct mdma_timings_t* tm;
+	int i;
+
+	/* Get default cycle time for mode */
+	switch(speed & 0xf) {
+		case 0: cycleTime = 480; break;
+		case 1: cycleTime = 150; break;
+		case 2: cycleTime = 120; break;
+		default:
+			return -1;
+	}
+	/* Adjust for drive */
+	if (drive_cycle_time && drive_cycle_time > cycleTime)
+		cycleTime = drive_cycle_time;
+	/* OHare limits according to some old Apple sources */	
+	if ((intf_type == controller_ohare) && (cycleTime < 150))
+		cycleTime = 150;
+	/* Get the proper timing array for this controller */
+	switch(intf_type) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			tm = mdma_timings_66;
+			break;
+		case controller_kl_ata3:
+			tm = mdma_timings_33k;
+			break;
+		default:
+			tm = mdma_timings_33;
+			break;
+	}
+	/* Lookup matching access & recovery times */
+	i = -1;
+	for (;;) {
+		if (tm[i+1].cycleTime < cycleTime)
+			break;
+		i++;
+	}
+	if (i < 0)
+		return -1;
+	cycleTime = tm[i].cycleTime;
+	accessTime = tm[i].accessTime;
+	recTime = tm[i].recoveryTime;
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+		cycleTime, accessTime, recTime);
+#endif	
+	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 0x1U);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 0x3U);
+		/* Clear out mdma bits and disable udma */
+		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+	} else if (intf_type == controller_kl_ata3) {
+		/* 33Mhz cell on KeyLargo */
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 1U);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell on others */
+		int halfTick = 0;
+		int origAccessTime = accessTime;
+		int origRecTime = recTime;
+		
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 2U) - 1;
+		recTicks = min(recTicks, 0x1fU);
+		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+		if ((accessTicks > 1) &&
+		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+            		halfTick = 1;
+			accessTicks--;
+		}
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		if (halfTick)
+			*timings |= TR_33_MDMA_HALFTICK;
+	}
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+	return 0;
+}
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/* You may notice we don't use this function on normal operation,
+ * our, normal mdma function is supposed to be more precise
+ */
+static int __pmac
+pmac_ide_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	int unit = (drive->select.b.unit & 0x01);
+	int ret = 0;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	
+	if (pmif == NULL)
+		return 1;
+
+	timings = &pmif->timings[unit];
+	
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+			if (pmif->kind != controller_kl_ata4_80)
+				return 1;		
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (pmif->kind != controller_kl_ata4 &&
+				pmif->kind != controller_kl_ata4_80)
+				return 1;		
+			ret = set_timings_udma(timings, speed);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			ret = set_timings_mdma(pmif->kind, timings, speed, 0);
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			return 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pmac_ide_tuneproc(drive, speed & 0x07);
+			break;
+		default:
+			ret = 1;
+	}
+	if (ret)
+		return ret;
+
+	ret = pmac_ide_do_setfeature(drive, speed);
+	if (ret)
+		return ret;
+		
+	pmac_ide_selectproc(drive);	
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+static void __pmac
+sanitize_timings(pmac_ide_hwif_t *pmif)
+{
+	unsigned value;
+	
+	switch(pmif->kind) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			value = 0x0008438c;
+			break;
+		case controller_kl_ata3:
+			value = 0x00084526;
+			break;
+		case controller_heathrow:
+		case controller_ohare:
+		default:
+			value = 0x00074526;
+			break;
+	}
+	pmif->timings[0] = pmif->timings[1] = value;
+}
+
+ide_ioreg_t __pmac
+pmac_ide_get_base(int index)
+{
+	return pmac_ide[index].regbase;
+}
+
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+	int ix;
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return ix;
+	return -1;
+}
+
+int __pmac
+pmac_ide_get_irq(ide_ioreg_t base)
+{
+	int ix;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return pmac_ide[ix].irq;
+	return 0;
+}
+
+static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
+
+kdev_t __init
+pmac_find_ide_boot(char *bootdevice, int n)
+{
+	int i;
+	
+	/*
+	 * Look through the list of IDE interfaces for this one.
+	 */
+	for (i = 0; i < pmac_ide_count; ++i) {
+		char *name;
+		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+			continue;
+		name = pmac_ide[i].node->full_name;
+		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+			/* XXX should cope with the 2nd drive as well... */
+			return MKDEV(ide_majors[i], 0);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_ide_probe(void)
+{
+	struct device_node *np;
+	int i;
+	struct device_node *atas;
+	struct device_node *p, **pp, *removables, **rp;
+	unsigned long base;
+	int irq, big_delay;
+	ide_hwif_t *hwif;
+
+	if (_machine != _MACH_Pmac)
+		return;
+	pp = &atas;
+	rp = &removables;
+	p = find_devices("ATA");
+	if (p == NULL)
+		p = find_devices("IDE");
+	if (p == NULL)
+		p = find_type_devices("ide");
+	if (p == NULL)
+		p = find_type_devices("ata");
+	/* Move removable devices such as the media-bay CDROM
+	   on the PB3400 to the end of the list. */
+	for (; p != NULL; p = p->next) {
+		if (p->parent && p->parent->type
+		    && strcasecmp(p->parent->type, "media-bay") == 0) {
+			*rp = p;
+			rp = &p->next;
+		} else {
+			*pp = p;
+			pp = &p->next;
+		}
+	}
+	*rp = NULL;
+	*pp = removables;
+	big_delay = 0;
+
+	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+		struct device_node *tp;
+		struct pmac_ide_hwif* pmif;
+		int *bidp;
+		int in_bay = 0;
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
+
+		/*
+		 * If this node is not under a mac-io or dbdma node,
+		 * leave it to the generic PCI driver.
+		 */
+		for (tp = np->parent; tp != 0; tp = tp->parent)
+			if (tp->type && (strcmp(tp->type, "mac-io") == 0
+					 || strcmp(tp->type, "dbdma") == 0))
+				break;
+		if (tp == 0)
+			continue;
+
+		if (np->n_addrs == 0) {
+			printk(KERN_WARNING "ide: no address for device %s\n",
+			       np->full_name);
+			continue;
+		}
+
+		/* We need to find the pci_dev of the mac-io holding the
+		 * IDE interface
+		 */
+		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+			       np->full_name);
+
+		/*
+		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
+		 */
+		while (i < MAX_HWIFS
+		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
+			++i;
+		if (i >= MAX_HWIFS)
+			break;
+		pmif = &pmac_ide[i];
+
+		/*
+		 * Some older OFs have bogus sizes, causing request_OF_resource
+		 * to fail. We fix them up here
+		 */
+		if (np->addrs[0].size > 0x1000)
+			np->addrs[0].size = 0x1000;
+		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+			np->addrs[1].size = 0x100;
+
+		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+			continue;
+		}
+
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x400);
+
+		/* XXX This is bogus. Should be fixed in the registry by checking
+		   the kind of host interrupt controller, a bit like gatwick
+		   fixes in irq.c
+		 */
+		if (np->n_intrs == 0) {
+			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
+			       np->full_name);
+			irq = 13;
+		} else {
+			irq = np->intrs[0].line;
+		}
+		pmif->regbase = base;
+		pmif->irq = irq;
+		pmif->node = np;
+		pmif->index = i;
+		if (device_is_compatible(np, "keylargo-ata")) {
+			if (strcmp(np->name, "ata-4") == 0)
+				pmif->kind = controller_kl_ata4;
+			else
+				pmif->kind = controller_kl_ata3;
+		} else if (device_is_compatible(np, "heathrow-ata"))
+			pmif->kind = controller_heathrow;
+		else
+			pmif->kind = controller_ohare;
+
+		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+
+		if (pmif->kind == controller_kl_ata4) {
+			char* cable = get_property(np, "cable-type", NULL);
+			if (cable && !strncmp(cable, "80-", 3))
+				pmif->kind = controller_kl_ata4_80;
+		}
+
+		/* Make sure we have sane timings */
+		sanitize_timings(pmif);
+
+		if (np->parent && np->parent->name
+		    && strcasecmp(np->parent->name, "media-bay") == 0) {
+#ifdef CONFIG_PMAC_PBOOK
+			media_bay_set_ide_infos(np->parent,base,irq,i);
+#endif /* CONFIG_PMAC_PBOOK */
+			in_bay = 1;
+			if (!bidp)
+				pmif->aapl_bus_id = 1;
+		} else if (pmif->kind == controller_ohare) {
+			/* The code below is having trouble on some ohare machines
+			 * (timing related ?). Until I can put my hand on one of these
+			 * units, I keep the old way
+			 */
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
+		} else {
+ 			/* This is necessary to enable IDE when net-booting */
+			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
+				pmif->aapl_bus_id);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+			mdelay(10);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+			big_delay = 1;
+		}
+
+		hwif = &ide_hwifs[i];
+		/* Setup MMIO ops */
+		default_hwif_mmiops(hwif);
+		/* Tell common code _not_ to mess with resources */
+		hwif->mmio = 2;
+		hwif->hwif_data = pmif;
+		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->chipset = ide_pmac;
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+		hwif->pci_dev = pdev;
+		hwif->drives[0].unmask = 1;
+		hwif->drives[1].unmask = 1;
+		hwif->tuneproc = pmac_ide_tuneproc;
+		hwif->selectproc = pmac_ide_selectproc;
+		hwif->speedproc = pmac_ide_tune_chipset;
+#ifdef CONFIG_PMAC_PBOOK
+		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
+			hwif->noprobe = 0;
+#endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		if (np->n_addrs >= 2) {
+			/* has a DBDMA controller channel */
+			pmac_ide_setup_dma(np, i);
+		}
+		hwif->atapi_dma = 1;
+		hwif->ultra_mask = 0x1f;
+		hwif->mwdma_mask = 0x07;
+		hwif->swdma_mask = 0x07;
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+		++i;
+	}
+	pmac_ide_count = i;
+	if (big_delay)
+		mdelay(IDE_WAKEUP_DELAY_MS);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+static int
+pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct buffer_head *bh;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	if (rq->cmd == READ)
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+static int
+pmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int
+pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
+{
+	struct dbdma_cmd *table;
+	int i, count = 0;
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	volatile struct dbdma_regs *dma = pmif->dma_regs;
+	struct scatterlist *sg;
+
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmif->dma_table_cpu;
+
+	/* Make sure DMA controller is stopped (necessary ?) */
+	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
+	while (readl(&dma->status) & RUN)
+		udelay(1);
+
+	/* Build sglist */
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq);
+	else
+		pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq);
+	if (!i)
+		return 0;
+
+	/* Build DBDMA commands list */
+	sg = pmif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+			if (++count >= MAX_DCMDS) {
+				printk(KERN_WARNING "%s: DMA table too small\n",
+				       drive->name);
+				return 0; /* revert to PIO for this request */
+			}
+			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
+			st_le16(&table->req_count, tc);
+			st_le32(&table->phy_addr, cur_addr);
+			table->cmd_dep = 0;
+			table->xfer_status = 0;
+			table->res_count = 0;
+			cur_addr += tc;
+			cur_len -= tc;
+			++table;
+		}
+		sg++;
+		i--;
+	}
+
+	/* convert the last command to an input/output last command */
+	if (count)
+		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
+	else
+		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+
+	/* add the stop command to the end of the list */
+	memset(table, 0, sizeof(struct dbdma_cmd));
+	st_le16(&table->command, DBDMA_STOP);
+	mb();
+	writel(pmif->dma_table_dma, &dma->cmdptr);
+	return 1;
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = pmif->sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction);
+		pmif->sg_nents = 0;
+	}
+}
+
+static __inline__ unsigned char
+dma_bits_to_command(unsigned char bits)
+{
+	if(bits & 0x04)
+		return XFER_MW_DMA_2;
+	if(bits & 0x02)
+		return XFER_MW_DMA_1;
+	if(bits & 0x01)
+		return XFER_MW_DMA_0;
+	return 0;
+}
+
+static __inline__ unsigned char
+udma_bits_to_command(unsigned char bits, int high_speed)
+{
+	if (high_speed) {
+		if(bits & 0x10)
+			return XFER_UDMA_4;
+		if(bits & 0x08)
+			return XFER_UDMA_3;
+	}
+	if(bits & 0x04)
+		return XFER_UDMA_2;
+	if(bits & 0x02)
+		return XFER_UDMA_1;
+	if(bits & 0x01)
+		return XFER_UDMA_0;
+	return 0;
+}
+
+/* Calculate MultiWord DMA timings */
+static int __pmac
+pmac_ide_mdma_enable(ide_drive_t *drive)
+{
+	u8 bits = drive->id->dma_mword & 0x07;
+	u8 feature = dma_bits_to_command(bits);
+	u32 *timings;
+	int drive_cycle_time;
+	struct hd_driveid *id = drive->id;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
+	    	return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+	
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	/* Check if drive provide explicit cycle time */
+	if ((id->field_valid & 2) && (id->eide_dma_time))
+		drive_cycle_time = id->eide_dma_time;
+	else
+		drive_cycle_time = 0;
+
+	/* Calculate controller timings */
+	set_timings_mdma(pmif->kind, timings, feature, drive_cycle_time);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, int high_speed)
+{
+	u8 bits = drive->id->dma_ultra & 0x1f;
+	u8 feature = udma_bits_to_command(bits, high_speed);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+		printk(KERN_WARNING "%s: Failed !\n", drive->name);
+		return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	set_timings_udma(timings, feature);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+int pmac_ide_dma_check(ide_drive_t *drive)
+{
+	int ata4, udma;
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	int enable = 1;
+
+	drive->using_dma = 0;
+	
+	if (pmif == NULL)
+		return 0;
+		
+	if (drive->media == ide_floppy)
+		enable = 0;
+	if (((id->capability & 1) == 0) &&
+	    !HWIF(drive)->ide_dma_good_drive(drive))
+		enable = 0;
+	if (HWIF(drive)->ide_dma_bad_drive(drive))
+		enable = 0;
+	udma = 0;
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+			
+	if(enable) {
+		if (ata4 && (drive->media == ide_disk) &&
+		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
+			/* UltraDMA modes. */
+			drive->using_dma = pmac_ide_udma_enable(drive,
+				pmif->kind == controller_kl_ata4_80);
+		}
+		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
+			/* Normal MultiWord DMA modes. */
+			drive->using_dma = pmac_ide_mdma_enable(drive);
+		}
+		hwif->OUTB(0, IDE_CONTROL_REG);
+		/* Apply settings to controller */
+		pmac_ide_selectproc(drive);
+	}
+	return 0;
+}
+
+static int
+pmac_ide_dma_read (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 0))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit]+0x00800000UL,
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_write (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 1))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_begin (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+
+	if (pmif == NULL)
+		return 1;
+	dma = pmif->dma_regs;
+
+	writel((RUN << 16) | RUN, &dma->control);
+	/* Make sure it gets to the controller right now */
+	(void)readl(&dma->control);
+	return 0;
+}
+
+static int
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	u32 dstat;
+	
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	drive->waiting_for_dma = 0;
+	dstat = readl(&dma->status);
+	writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+	pmac_ide_destroy_dmatable(drive);
+	/* verify good dma status */
+	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+}
+
+static int
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	/* We have to things to deal with here:
+	 * 
+	 * - The dbdma won't stop if the command was started
+	 * but completed with an error without transfering all
+	 * datas. This happens when bad blocks are met during
+	 * a multi-block transfer.
+	 * 
+	 * - The dbdma fifo hasn't yet finished flushing to
+	 * to system memory when the disk interrupt occurs.
+	 * 
+	 * The trick here is to increment drive->waiting_for_dma,
+	 * and return as if no interrupt occured. If the counter
+	 * reach a certain timeout value, we then return 1. If
+	 * we really got the interrupt, it will happen right away
+	 * again.
+	 * Apple's solution here may be more elegant. They issue
+	 * a DMA channel interrupt (a separate irq line) via a DBDMA
+	 * NOP command just before the STOP, and wait for both the
+	 * disk and DBDMA interrupts to have completed.
+	 */
+ 
+	/* If ACTIVE is cleared, the STOP command have passed and
+	 * transfer is complete.
+	 */
+	status = readl(&dma->status);
+	if (!(status & ACTIVE))
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+			called while not waiting\n", pmif->index);
+
+	/* If dbdma didn't execute the STOP command yet, the
+	 * active bit is still set */
+	drive->waiting_for_dma++;
+	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+		printk(KERN_WARNING "ide%d, timeout waiting \
+			for dbdma command stop\n", pmif->index);
+		return 1;
+	}
+	udelay(1);
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_on (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_lostirq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	status = readl(&dma->status);
+	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+	return 0;
+}
+
+static void __init 
+pmac_ide_setup_dma(struct device_node *np, int ix)
+{
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
+		return;
+	}
+
+	pmif->dma_regs =
+		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
+
+	/*
+	 * Allocate space for the DBDMA commands.
+	 * The +2 is +1 for the stop command and +1 to allow for
+	 * aligning the start address to a multiple of 16 bytes.
+	 */
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+		       ide_hwifs[ix].name);
+		return;
+	}
+
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
+	ide_hwifs[ix].ide_dma_off = &__ide_dma_off;
+	ide_hwifs[ix].ide_dma_off_quietly = &__ide_dma_off_quietly;
+	ide_hwifs[ix].ide_dma_on = &__ide_dma_on;
+	ide_hwifs[ix].ide_dma_check = &pmac_ide_dma_check;
+	ide_hwifs[ix].ide_dma_read = &pmac_ide_dma_read;
+	ide_hwifs[ix].ide_dma_write = &pmac_ide_dma_write;
+	ide_hwifs[ix].ide_dma_count = &pmac_ide_dma_count;
+	ide_hwifs[ix].ide_dma_begin = &pmac_ide_dma_begin;
+	ide_hwifs[ix].ide_dma_end = &pmac_ide_dma_end;
+	ide_hwifs[ix].ide_dma_test_irq = &pmac_ide_dma_test_irq;
+	ide_hwifs[ix].ide_dma_host_off = &pmac_ide_dma_host_off;
+	ide_hwifs[ix].ide_dma_host_on = &pmac_ide_dma_host_on;
+	ide_hwifs[ix].ide_dma_good_drive = &__ide_dma_good_drive;
+	ide_hwifs[ix].ide_dma_bad_drive = &__ide_dma_bad_drive;
+	ide_hwifs[ix].ide_dma_verbose = &__ide_dma_verbose;
+	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;
+	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;
+	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+	if (!noautodma)
+		ide_hwifs[ix].autodma = 1;
+#endif
+	ide_hwifs[ix].drives[0].autodma = ide_hwifs[ix].autodma;
+	ide_hwifs[ix].drives[1].autodma = ide_hwifs[ix].autodma;
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+static void __pmac
+idepmac_sleep_device(ide_drive_t *drive, unsigned base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int j;
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
+		/* Spin down the drive */
+		hwif->OUTB(drive->select.all, base+0x60);
+		(void) hwif->INB(base+0x60);
+		udelay(100);
+		hwif->OUTB(0x0, base+0x30);
+		hwif->OUTB(0x0, base+0x20);
+		hwif->OUTB(0x0, base+0x40);
+		hwif->OUTB(0x0, base+0x50);
+		hwif->OUTB(0xe0, base+0x70);
+		hwif->OUTB(0x2, base+0x160);   
+		for (j = 0; j < 10; j++) {
+			u8 status;
+			mdelay(100);
+			status = hwif->INB(base+0x70);
+			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+				break;
+		}
+		break;
+	case ide_cdrom:
+		// todo
+		break;
+	case ide_floppy:
+		// todo
+		break;
+	}
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	if (DRIVER(drive) && DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_dma_check(drive);
+		HWGROUP(drive)->busy = 0;
+		if (!list_empty(&drive->queue.queue_head))
+			ide_do_request(HWGROUP(drive), 0);
+		spin_unlock_irq(&io_request_lock);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void __pmac
+idepmac_sleep_interface(pmac_ide_hwif_t *pmif, unsigned base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	/* We clear the timings */
+	pmif->timings[0] = 0;
+	pmif->timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable the bus */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 0);
+}
+
+static void __pmac
+idepmac_wake_interface(pmac_ide_hwif_t *pmif, unsigned long base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+		mdelay(10);
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+	}
+}
+
+static void
+idepmac_sleep_drive(ide_drive_t *drive, unsigned long base)
+{
+	int unlock = 0;
+
+	/* Wait for HW group to complete operations */
+	if (ide_spin_wait_hwgroup(drive)) {
+		// What can we do here ? Wake drive we had already
+		// put to sleep and return an error ?
+	} else {
+		unlock = 1;
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		/* Stop the device */
+		idepmac_sleep_device(drive, base);
+	}
+	if (unlock)
+		spin_unlock_irq(&io_request_lock);
+}
+
+static void
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int j;
+	
+	/* Reset timings */
+	pmac_ide_selectproc(drive);
+	mdelay(10);
+	
+	/* Wait up to 20 seconds for the drive to be ready */
+	for (j = 0; j < 200; j++) {
+		u8 status = 0;
+		mdelay(100);
+		hwif->OUTB(drive->select.all, base + 0x60);
+		if ((hwif->INB(base + 0x60)) != drive->select.all)
+			continue;
+		status = hwif->INB(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+
+	/* We resume processing on the HW group */
+	spin_lock_irqsave(&io_request_lock, flags);
+	HWGROUP(drive)->busy = 0;
+	if (!list_empty(&drive->queue.queue_head))
+		ide_do_request(HWGROUP(drive), 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);			
+}
+
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	int i, ret;
+	unsigned long base;
+	int big_delay;
+ 
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int dn;
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				if (!hwif->drives[dn].present)
+					continue;
+				idepmac_sleep_drive(&hwif->drives[dn], base);
+			}
+			/* Disable irq during sleep */
+			disable_irq(pmac_ide[i].irq);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(&pmac_ide[i], base, (ret == 0));
+		}
+		break;
+	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Make sure we have sane timings */		
+			sanitize_timings(&pmac_ide[i]);
+
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(&pmac_ide[i], base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int used_dma, dn;
+			int irq_on = 0;
+			
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				ide_drive_t *drive = &hwif->drives[dn];
+				if (!drive->present)
+					continue;
+				/* We don't have re-configured DMA yet */
+				used_dma = drive->using_dma;
+				drive->using_dma = 0;
+				idepmac_wake_drive(drive, base);
+				if (!irq_on) {
+					enable_irq(pmac_ide[i].irq);
+					irq_on = 1;
+				}
+				idepmac_wake_device(drive, used_dma);
+			}
+			if (!irq_on)
+				enable_irq(pmac_ide[i].irq);
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Nru a/drivers/ide/ppc/swarm.c b/drivers/ide/ppc/swarm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/ppc/swarm.c	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define __IDE_SWARM_C
+
+#include <asm/sibyte/swarm_ide.h>
+
+void __init swarm_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Set up our stuff */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
+	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
+//	hwif->hw->ack_intr                    = swarm_ide_ack_intr;
+	hwif->hw.irq                          = SWARM_IDE_INT;
+#if 0
+	hwif->iops                            = swarm_iops;
+#else
+	hwif->OUTB      = hwif->OUTBP         = swarm_outb;
+	hwif->OUTW      = hwif->OUTWP         = swarm_outw;
+	hwif->OUTL      = hwif->OUTLP         = swarm_outl;
+	hwif->OUTSW     = hwif->OUTSWP        = swarm_outsw;
+	hwif->OUTSL     = hwif->OUTSLP        = swarm_outsl;
+	hwif->INB       = hwif->INBP          = swarm_inb;
+	hwif->INW       = hwif->INWP          = swarm_inw;
+	hwif->INL       = hwif->INLP          = swarm_inl;
+	hwif->INSW      = hwif->INSWP         = swarm_insw;
+	hwif->INSL      = hwif->INSLP         = swarm_insl;
+#endif
+#if 0
+	hwif->pioops                          = swarm_pio_ops;
+#else
+	hwif->ata_input_data                  = swarm_ata_input_data;
+	hwif->ata_output_data                 = swarm_ata_output_data;
+	hwif->atapi_input_bytes               = swarm_atapi_input_bytes;
+	hwif->atapi_output_bytes              = swarm_atapi_output_bytes;
+#endif
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->irq                             = hwif->hw.irq;
+	printk("SWARM onboard IDE configured as device %i\n", i);
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif->index);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
diff -Nru a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
--- a/drivers/ide/q40ide.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,91 +0,0 @@
-/*
- *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
- *
- *     (c) Richard Zidlicky
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/ide.h>
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define Q40IDE_NUM_HWIFS	2
-
-#define PCIDE_BASE1	0x1f0
-#define PCIDE_BASE2	0x170
-#define PCIDE_BASE3	0x1e8
-#define PCIDE_BASE4	0x168
-#define PCIDE_BASE5	0x1e0
-#define PCIDE_BASE6	0x160
-
-static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
-    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
-    PCIDE_BASE6 */
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-
-/* HD_DATA was redefined in asm-m68k/ide.h */
-#undef HD_DATA
-#define HD_DATA  0x1f0
-
-
-#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
-
-static const int pcide_offsets[IDE_NR_PORTS] = {
-    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
-    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
-    PCIDE_REG(CMD)
-};
-
-static int q40ide_default_irq(q40ide_ioreg_t base)
-{
-           switch (base) { 
-	            case 0x1f0: return 14;
-		    case 0x170: return 15;
-		    case 0x1e8: return 11;
-		    default:
-			return 0;
-	   }
-}
-
-
-
-    /*
-     *  Probe for Q40 IDE interfaces
-     */
-
-void q40ide_init(void)
-{
-    int i;
-
-    if (!MACH_IS_Q40)
-      return ;
-
-    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
-	hw_regs_t hw;
-
-	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
-			pcide_bases[i]+0x206, 
-			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
-    }
-}
-
diff -Nru a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
--- a/drivers/ide/qd65xx.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,453 +0,0 @@
-/*
- *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
- *
- *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
- */
-
-/*
- *  Version 0.03	Cleaned auto-tune, added probe
- *  Version 0.04	Added second channel tuning
- *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	Added dos driver's list
- *  Version 0.07	Second channel bug fix 
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * Please set local bus speed using kernel parameter idebus
- * 	for example, "idebus=33" stands for 33Mhz VLbus
- * To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "ide0=autotune"
- * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include "ide_modes.h"
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- *	-- qd6500 is a single IDE interface
- *	-- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- *        qd6580: 1
- * upper nibble:
- *        qd6500: 1100
- *        qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- *                                                   channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- *         0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- * 	(maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-static void qd_write_reg (byte content, byte reg)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	OUT_BYTE(content,reg);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-byte __init qd_read_reg (byte reg)
-{
-	unsigned long flags;
-	byte read;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	read = IN_BYTE(reg);
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return read;
-}
-
-/*
- * qd_select:
- *
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-
-static void qd_select (ide_drive_t *drive)
-{
-	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
-			(QD_TIMREG(drive) & 0x02);
-
-	if (timings[index] != QD_TIMING(drive))
-		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- * 	lower nibble represents active time,   in count of VLB clocks
- * 	upper nibble represents recovery time, in count of VLB clocks
- */
-
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
-	byte active_cycle,recovery_cycle;
-
-	if (ide_system_bus_speed()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
-	} else {
-		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
-	}
-
-	return((recovery_cycle<<4) | 0x08 | active_cycle);
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static byte qd6580_compute_timing (int active_time, int recovery_time)
-{
-	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
-
-	return((recovery_cycle<<4) | active_cycle);
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
-		int *active_time, int *recovery_time)
-{
-	struct qd65xx_timing_s *p;
-	char model[40];
-
-	if (!*drive->id->model) return 0;
-
-	strncpy(model,drive->id->model,40);
-	ide_fixstring(model,40,1); /* byte-swap */
-
-	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset,4)) {
-			printk(KERN_DEBUG "%s: listed !\n",drive->name);
-			*active_time = p->active;
-			*recovery_time = p->recovery;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * qd_timing_ok:
- *
- * check whether timings don't conflict
- */
-
-static int qd_timing_ok (ide_drive_t drives[])
-{
-	return (IDE_IMPLY(drives[0].present && drives[1].present,
-			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
-			          QD_TIMING(drives) == QD_TIMING(drives+1))));
-	/* if same timing register, must be same timing */
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing, and enables selectproc as needed
- */
-
-static void qd_set_timing (ide_drive_t *drive, byte timing)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	if (qd_timing_ok(hwif->drives)) {
-		qd_select(drive); /* selects once */
-		hwif->selectproc = NULL;
-	} else
-		hwif->selectproc = &qd_select;
-
-	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
-}
-
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
-		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
-		&& drive->id->eide_pio >= 240) {
-
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
-		active_time = 110;
-		recovery_time = drive->id->eide_pio - 120;
-	}
-
-	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
-}
-
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int base = HWIF(drive)->select_data;
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
-		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
-		pio = IDE_MIN(pio,4);
-
-		switch (pio) {
-			case 0: break;
-			case 3:
-				if (d.cycle_time >= 110) {
-					active_time = 86;
-					recovery_time = d.cycle_time-102;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			case 4:
-				if (d.cycle_time >= 69) {
-					active_time = 70;
-					recovery_time = d.cycle_time-61;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			default:
-				if (d.cycle_time >= 180) {
-					active_time = 110;
-					recovery_time = d.cycle_time - 120;
-				} else {
-					active_time = ide_pio_timings[pio].active_time;
-					recovery_time = d.cycle_time
-							-active_time;
-				}
-		}
-		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
-	}
-
-	if (!HWIF(drive)->channel && drive->media != ide_disk) {
-		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
-	}
-
-	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
-	byte savereg;
-	byte readreg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ide_lock, flags);
-	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
-	readreg = inb_p(port);
-	OUT_BYTE(savereg,port);
-	spin_unlock_irqrestore(&ide_lock, flags);
-
-	if (savereg == QD_TESTVAL) {
-		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
-		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
-		printk(KERN_ERR "Assuming qd65xx is not present.\n");
-		return 1;
-	}
-
-	return (readreg != QD_TESTVAL);
-}
-
-/*
- * probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-int __init probe (int base)
-{
-	byte config;
-	byte index;
-
-	config = qd_read_reg(QD_CONFIG_PORT);
-
-	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
-
-	index = ! (config & QD_CONFIG_IDE_BASEPORT);
-
-	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
-
-		if (qd_testreg(base)) return 1;		/* bad register */
-
-			/* qd6500 found */
-
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
-			ide_hwifs[index].name, base);
-		
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-			config, QD_ID3);
-		
-		if (config & QD_CONFIG_DISABLED) {
-			printk(KERN_WARNING "qd6500 is disabled !\n");
-			return 1;
-		}
-
-		hwif->chipset = ide_qd65xx;
-		hwif->select_data = base;
-		hwif->config_data = config;
-		hwif->drives[0].drive_data =
-		hwif->drives[1].drive_data = QD6500_DEF_DATA;
-		hwif->drives[0].io_32bit =
-		hwif->drives[1].io_32bit = 1;
-		hwif->tuneproc = &qd6500_tune_drive;
-		return 1;
-	}
-
-	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
-		byte control;
-
-		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
-			/* bad registers */
-
-			/* qd6580 found */
-
-		control = qd_read_reg(QD_CONTROL_PORT);
-
-		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-			config, control, QD_ID3);
-
-		if (control & QD_CONTR_SEC_DISABLED) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-
-			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n",
-					ide_hwifs[index].name);
-
-			hwif->chipset = ide_qd65xx;
-			hwif->select_data = base;
-			hwif->config_data = config | (control <<8);
-			hwif->drives[0].drive_data =
-			hwif->drives[1].drive_data = QD6580_DEF_DATA;
-			hwif->drives[0].io_32bit =
-			hwif->drives[1].io_32bit = 1;
-			hwif->tuneproc = &qd6580_tune_drive;
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 1;
-		} else {
-			int i,j;
-			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
-					ide_hwifs[0].name,ide_hwifs[1].name);
-
-			for (i=0;i<2;i++) {
-
-				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].mate = &ide_hwifs[i^1];
-				ide_hwifs[i].channel = i;
-
-				ide_hwifs[i].select_data = base;
-				ide_hwifs[i].config_data = config | (control <<8);
-				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
-
-				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data =
-					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
-					ide_hwifs[i].drives[j].io_32bit = 1;
-				}
-			}
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 0; /* no other qd65xx possible */
-		}
-	}
-	/* no qd65xx found */
-	return 1;
-}
-
-/*
- * init_qd65xx:
- *
- * called at the very beginning of initialization ; should just probe and link
- */
-
-void __init init_qd65xx (void)
-{
-	if (probe(0x30)) probe(0xb0);
-}
diff -Nru a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
--- a/drivers/ide/qd65xx.h	Sun Sep 15 19:19:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,140 +0,0 @@
-/*
- * linux/drivers/ide/qd65xx.h
- *
- * Copyright (c) 2000	Linus Torvalds & authors
- */
-
-/*
- * Authors:	Petr Soucek <petr@ryston.cz>
- * 		Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b)	((!(a)) || (b))
-
-#define QD_TIM1_PORT		(base)
-#define QD_CONFIG_PORT		(base+0x01)
-#define QD_TIM2_PORT		(base+0x02)
-#define QD_CONTROL_PORT		(base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT	0x01
-#define QD_CONFIG_BASEPORT	0x02
-#define QD_CONFIG_ID3		0x04
-#define QD_CONFIG_DISABLED	0x08
-#define QD_CONFIG_QD6500	0xc0
-#define QD_CONFIG_QD6580_A	0xa0
-#define QD_CONFIG_QD6580_B	0x50
-
-#define QD_CONTR_SEC_DISABLED	0x01
-
-#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
-
-#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
-#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
-
-#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
-#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
-
-#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
-#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
-
-#define QD_TESTVAL		0x19	/* safe value */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-struct qd65xx_timing_s {
-	char	offset;   /* ofset from the beginning of Model Number" */
-	char	model[4];    /* 4 chars from Model number, no conversion */
-	short	active;   /* active time */
-	short	recovery; /* recovery time */
-} qd65xx_timing [] = {
-	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
-	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
-	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
-	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
-	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
-	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
-	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
-	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
-	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
-	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
-	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
-	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
-	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
-	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
-	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
-	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
-	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
-	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
-	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
-	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
-	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
-	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
-	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
-	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
-	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
-	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
-	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
-	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
-	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
-	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
-	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
-	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
-	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
-	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
-	{  6, "61 0", 135, 285 },  /* WD AC160				*/
-	{  6, "1107", 135, 235 },  /* WD AC1170				*/
-	{  6, "2101", 110, 220 },  /* WD AC1210				*/
-	{  6, "4202", 135, 245 },  /* WD AC2420				*/
-	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
-	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
-	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
-	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
-	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
-	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
-	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
-	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
-	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
-	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
-	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
-	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
-	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
-	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
-	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
-	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
-	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
-	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
-	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
-	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
-	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
-	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
-	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
-	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
-	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
-	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
-	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
-	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
-	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
-	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
-	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
-	{  2, "2309", 175, 295 },  /* ST3290A				*/
-	{  2, "3358", 180, 310 },  /* ST3385A				*/
-	{  2, "6355", 180, 310 },  /* ST3655A				*/
-	{  2, "1900", 175, 270 },  /* ST9100A				*/
-	{  2, "1954", 175, 270 },  /* ST9145A				*/
-	{  2, "1909", 175, 270 },  /* ST9190AG				*/
-	{  2, "2953", 175, 270 },  /* ST9235A				*/
-	{  2, "1359", 175, 270 },  /* ST3195A				*/
-	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
-	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
-	{  4, "2253", 175, 300 },  /* HP C2235A				*/
-	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
-	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
-	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
-	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
-	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
-};
diff -Nru a/drivers/ide/rapide.c b/drivers/ide/rapide.c
--- a/drivers/ide/rapide.c	Sun Sep 15 19:20:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,94 +0,0 @@
-/*
- * linux/drivers/ide/rapide.c
- *
- * Copyright (c) 1996-1998 Russell King.
- *
- * Changelog:
- *  08-06-1996	RMK	Created
- *  13-04-1998	RMK	Added manufacturer and product IDs
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static card_ids __init rapide_cids[] = {
-	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-	{ 0xffff, 0xffff }
-};
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS];
-
-static inline int rapide_register(struct expansion_card *ec)
-{
-	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-	hw_regs_t hw;
-
-	int i;
-
-	memset(&hw, 0, sizeof(hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw.io_ports[i] = (ide_ioreg_t)port;
-		port += 1 << 4;
-	}
-	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
-	hw.irq = ec->irq;
-
-	return ide_register_hw(&hw, NULL);
-}
-
-int __init rapide_init(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		ec[i] = NULL;
-
-	ecard_startfind();
-
-	for (i = 0; ; i++) {
-		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
-			break;
-
-		ecard_claim(ec[i]);
-		result[i] = rapide_register(ec[i]);
-	}
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i] && result[i] < 0) {
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module (void)
-{
-	return rapide_init();
-}
-
-void cleanup_module (void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i]) {
-			unsigned long port;
-			port = ecard_address(ec[i], ECARD_MEMC, 0);
-
-			ide_unregister_port(port, ec[i]->irq, 16);
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-		}
-}
-#endif
-
diff -Nru a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
--- a/drivers/ide/rz1000.c	Sun Sep 15 19:19:30 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author:  mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for disabling the buggy read-ahead
- *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- *  Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-
-void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
-{
-	unsigned short reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_rz1000;
-	if (!pci_read_config_word (dev, 0x40, &reg) &&
-	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
-		printk("%s: disabled chipset read-ahead "
-			"(buggy RZ1000/RZ1001)\n", hwif->name);
-	} else {
-		hwif->serialized = 1;
-		hwif->drives[0].no_unmask = 1;
-		hwif->drives[1].no_unmask = 1;
-		printk("%s: serialized, disabled unmasking "
-			"(buggy RZ1000/RZ1001)\n", hwif->name);
-	}
-}
-
-#else
-
-static void __init init_rz1000 (struct pci_dev *dev, const char *name)
-{
-	unsigned short reg, h;
-
-	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) &&
-	    !(reg & PCI_COMMAND_IO)) {
-		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
-		return;
-	}
-	if (!pci_read_config_word (dev, 0x40, &reg) &&
-	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
-		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
-	} else {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ide_hwif_t *hwif = &ide_hwifs[h];
-			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 ||
-			     hwif->io_ports[IDE_DATA_OFFSET] == 0x170)  &&
-			    (hwif->chipset == ide_unknown ||
-			     hwif->chipset == ide_generic)) {
-				hwif->chipset = ide_rz1000;
-				hwif->serialized = 1;
-				hwif->drives[0].no_unmask = 1;
-				hwif->drives[1].no_unmask = 1;
-				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->channel = 1;
-				printk("%s: serialized, disabled unmasking "
-					"(buggy %s)\n", hwif->name, name);
-			}
-		}
-	}
-}
-
-void __init ide_probe_for_rz100x (void)	/* called from ide.c */
-{
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		init_rz1000 (dev, "RZ1000");
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		init_rz1000 (dev, "RZ1001");
-}
-
-#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,789 +0,0 @@
-/*
- * linux/drivers/ide/serverworks.c		Version 0.6	05 April 2002
- *
- * Copyright (C) 1998-2000 Michel Aubry
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Portions copyright (c) 2001 Sun Microsystems
- *
- *
- * RCC/ServerWorks IDE driver for Linux
- *
- *   OSB4: `Open South Bridge' IDE Interface (fn 1)
- *         supports UDMA mode 2 (33 MB/s)
- *
- *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
- *         all revisions support UDMA mode 4 (66 MB/s)
- *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
- *
- *         *** The CSB5 does not provide ANY register ***
- *         *** to detect 80-conductor cable presence. ***
- *
- *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_SVWKS_TIMINGS	1
-#undef SVWKS_DEBUG_DRIVE_INFO
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-#define SVWKS_MAX_DEVS		2
-static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
-static int n_svwks_devs;
-
-static byte svwks_revision = 0;
-
-static int svwks_get_info(char *, char **, off_t, int);
-extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	p += sprintf(p, "\n                             "
-			"ServerWorks OSB4/CSB5/CSB6\n");
-
-	for (i = 0; i < n_svwks_devs; i++) {
-		struct pci_dev *dev = svwks_devs[i];
-		u32 bibma = pci_resource_start(dev, 4);
-		u32 reg40, reg44;
-		u16 reg48, reg56;
-		u8  reg54, c0=0, c1=0;
-
-		pci_read_config_dword(dev, 0x40, &reg40);
-		pci_read_config_dword(dev, 0x44, &reg44);
-		pci_read_config_word(dev, 0x48, &reg48);
-		pci_read_config_byte(dev, 0x54, &reg54);
-		pci_read_config_word(dev, 0x56, &reg56);
-
-		/*
-		 * at that point bibma+0x2 et bibma+0xa are byte registers
-		 * to investigate:
-		 */
-		c0 = inb_p((unsigned short)bibma + 0x02);
-		c1 = inb_p((unsigned short)bibma + 0x0a);
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
-				p += sprintf(p, "\n                            "
-					"ServerWorks CSB6 Chipset (rev %02x)\n",
-					svwks_revision);
-				break;
-			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-				p += sprintf(p, "\n                            "
-					"ServerWorks CSB5 Chipset (rev %02x)\n",
-					svwks_revision);
-				break;
-			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
-				p += sprintf(p, "\n                            "
-					"ServerWorks OSB4 Chipset (rev %02x)\n",
-					svwks_revision);
-				break;
-			default:
-				p += sprintf(p, "\n                            "
-					"ServerWorks %04x Chipset (rev %02x)\n",
-					dev->device, svwks_revision);
-				break;
-		}
-
-		p += sprintf(p, "------------------------------- "
-				"General Status "
-				"---------------------------------\n");
-		p += sprintf(p, "--------------- Primary Channel "
-				"---------------- Secondary Channel "
-				"-------------\n");
-		p += sprintf(p, "                %sabled                         %sabled\n",
-				(c0&0x80) ? "dis" : " en",
-				(c1&0x80) ? "dis" : " en");
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"-------- drive0 ---------- drive1 ------\n");
-		p += sprintf(p, "DMA enabled:    %s              %s"
-				"             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-		p += sprintf(p, "UDMA enabled:   %s              %s"
-				"             %s               %s\n",
-			(reg54 & 0x01) ? "yes" : "no ",
-			(reg54 & 0x02) ? "yes" : "no ",
-			(reg54 & 0x04) ? "yes" : "no ",
-			(reg54 & 0x08) ? "yes" : "no " );
-		p += sprintf(p, "UDMA enabled:   %s                %s"
-				"               %s                 %s\n",
-			((reg56&0x0005)==0x0005)?"5":
-				((reg56&0x0004)==0x0004)?"4":
-				((reg56&0x0003)==0x0003)?"3":
-				((reg56&0x0002)==0x0002)?"2":
-				((reg56&0x0001)==0x0001)?"1":
-				((reg56&0x000F))?"?":"0",
-			((reg56&0x0050)==0x0050)?"5":
-				((reg56&0x0040)==0x0040)?"4":
-				((reg56&0x0030)==0x0030)?"3":
-				((reg56&0x0020)==0x0020)?"2":
-				((reg56&0x0010)==0x0010)?"1":
-				((reg56&0x00F0))?"?":"0",
-			((reg56&0x0500)==0x0500)?"5":
-				((reg56&0x0400)==0x0400)?"4":
-				((reg56&0x0300)==0x0300)?"3":
-				((reg56&0x0200)==0x0200)?"2":
-				((reg56&0x0100)==0x0100)?"1":
-				((reg56&0x0F00))?"?":"0",
-			((reg56&0x5000)==0x5000)?"5":
-				((reg56&0x4000)==0x4000)?"4":
-				((reg56&0x3000)==0x3000)?"3":
-				((reg56&0x2000)==0x2000)?"2":
-				((reg56&0x1000)==0x1000)?"1":
-				((reg56&0xF000))?"?":"0");
-		p += sprintf(p, "DMA enabled:    %s                %s"
-				"               %s                 %s\n",
-			((reg44&0x00002000)==0x00002000)?"2":
-				((reg44&0x00002100)==0x00002100)?"1":
-				((reg44&0x00007700)==0x00007700)?"0":
-				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
-			((reg44&0x00000020)==0x00000020)?"2":
-				((reg44&0x00000021)==0x00000021)?"1":
-				((reg44&0x00000077)==0x00000077)?"0":
-				((reg44&0x000000FF)==0x000000FF)?"X":"?",
-			((reg44&0x20000000)==0x20000000)?"2":
-				((reg44&0x21000000)==0x21000000)?"1":
-				((reg44&0x77000000)==0x77000000)?"0":
-				((reg44&0xFF000000)==0xFF000000)?"X":"?",
-			((reg44&0x00200000)==0x00200000)?"2":
-				((reg44&0x00210000)==0x00210000)?"1":
-				((reg44&0x00770000)==0x00770000)?"0":
-				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-
-		p += sprintf(p, "PIO  enabled:   %s                %s"
-				"               %s                 %s\n",
-			((reg40&0x00002000)==0x00002000)?"4":
-				((reg40&0x00002200)==0x00002200)?"3":
-				((reg40&0x00003400)==0x00003400)?"2":
-				((reg40&0x00004700)==0x00004700)?"1":
-				((reg40&0x00005D00)==0x00005D00)?"0":"?",
-			((reg40&0x00000020)==0x00000020)?"4":
-				((reg40&0x00000022)==0x00000022)?"3":
-				((reg40&0x00000034)==0x00000034)?"2":
-				((reg40&0x00000047)==0x00000047)?"1":
-				((reg40&0x0000005D)==0x0000005D)?"0":"?",
-			((reg40&0x20000000)==0x20000000)?"4":
-				((reg40&0x22000000)==0x22000000)?"3":
-				((reg40&0x34000000)==0x34000000)?"2":
-				((reg40&0x47000000)==0x47000000)?"1":
-				((reg40&0x5D000000)==0x5D000000)?"0":"?",
-			((reg40&0x00200000)==0x00200000)?"4":
-				((reg40&0x00220000)==0x00220000)?"3":
-				((reg40&0x00340000)==0x00340000)?"2":
-				((reg40&0x00470000)==0x00470000)?"1":
-				((reg40&0x005D0000)==0x005D0000)?"0":"?");
-
-	}
-	p += sprintf(p, "\n");
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-
-#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
-
-byte svwks_proc = 0;
-
-static struct pci_dev *isa_dev;
-
-static byte svwks_ratemask (ide_drive_t *drive)
-{
-	struct pci_dev *dev     = HWIF(drive)->pci_dev;
-	byte mode		= 0;
-
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		u32 reg = 0;
-		mode &= ~0x01;
-		if (isa_dev)
-			pci_read_config_dword(isa_dev, 0x64, &reg);
-		if ((reg & 0x00004000) == 0x00004000)
-			mode |= 0x01;
-	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
-		mode |= 0x01;
-	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
-		u8 btr =0;
-		pci_read_config_byte(dev, 0x5A, &btr);
-		mode |= btr;
-		if (!eighty_ninty_three(drive))
-			mode &= ~0x02;
-	}
-	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
-	    (!(PCI_FUNC(dev->devfn) & 1)))
-		mode = 0x02;
-	mode &= ~0xFC;
-	return (mode);
-}
-
-static byte svwks_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = svwks_ratemask(drive);
-	
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static byte svwks_csb_check (struct pci_dev *dev)
-{
-	switch (dev->device) {
-		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
-			return 1;
-		default:
-			break;
-	}
-	return 0;
-}
-static int svwks_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
-	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte csb5		= svwks_csb_check(dev);
-
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
-
-	byte ultra_enable	= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_timing		= 0x00;
-	byte pio_timing		= 0x00;
-	unsigned short csb5_pio	= 0x00;
-
-	byte pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
-	byte speed	= svwks_ratefilter(drive, xferspeed);
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
-		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
-		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
-		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
-		default:
-			return -1;
-	}
-
-	pci_read_config_byte(dev, drive_pci, &pio_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_timing);
-	pci_read_config_byte(dev, drive_pci3, &ultra_timing);
-	pci_read_config_word(dev, 0x4A, &csb5_pio);
-	pci_read_config_byte(dev, 0x54, &ultra_enable);
-
-	pio_timing	&= ~0xFF;
-	dma_timing	&= ~0xFF;
-	ultra_timing	&= ~(0x0F << (4*unit));
-	ultra_enable	&= ~(0x01 << drive->dn);
-	csb5_pio	&= ~(0x0F << (4*drive->dn));
-
-	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pio_timing |= pio_modes[speed - XFER_PIO_0];
-			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
-			break;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			pio_timing   |= pio_modes[pio];
-			csb5_pio     |= (pio << (4*drive->dn));
-			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-#endif
-		default:
-			break;
-	}
-
-	pci_write_config_byte(dev, drive_pci, pio_timing);
-	if (csb5)
-		pci_write_config_word(dev, 0x4A, csb5_pio);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci2, dma_timing);
-	pci_write_config_byte(dev, drive_pci3, ultra_timing);
-	pci_write_config_byte(dev, 0x54, ultra_enable);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	return (ide_config_drive_speed(drive, speed));
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0)
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	else
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void svwks_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= svwks_ratemask(drive);
-	byte speed, dma		= 1;
-
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
-		mode = 0;
-
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-#if 0
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-#endif
-		default:
-			speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-			dma = 0;
-			break;
-	}
-
-	(void) svwks_tune_chipset(drive, speed);
-
-//	return ((int) (dma) ? ide_dma_on : ide_dma_off_quietly);
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-		//	HWIF(drive)->tuneproc(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_end:
-		{
-			ide_hwif_t *hwif		= HWIF(drive);
-			unsigned long dma_base		= hwif->dma_base;
-	
-			if(IN_BYTE(dma_base+0x02)&1)
-			{
-#if 0		
-				int i;
-				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
-				for(i=0;i<10;i++)
-				{
-					if(!(IN_BYTE(dma_base+0x02)&1))
-					{
-						printk(KERN_ERR "OSB4 now finished.\n");
-						break;
-					}
-					udelay(5);
-				}
-#endif		
-				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
-				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
-				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
-#if 0		
-				/* Panic might sys_sync -> death by corrupt disk */
-				panic("OSB4: continuing might cause disk corruption.\n");
-#else
-				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
-				while(1)
-					cpu_relax();
-#endif				
-			}
-			/* and drop through */
-		}
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
-{
-	unsigned int reg;
-	byte btr;
-
-	/* save revision id to determine DMA capability */
-	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
-	/* force Master Latency Timer value to 64 PCICLKs */
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
-	/* OSB4 : South Bridge and IDE */
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
-			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
-		if (isa_dev) {
-			pci_read_config_dword(isa_dev, 0x64, &reg);
-			reg &= ~0x00002000; /* disable 600ns interrupt mask */
-			reg |=  0x00004000; /* enable UDMA/33 support */
-			pci_write_config_dword(isa_dev, 0x64, reg);
-		}
-	}
-
-	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
-	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
-		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) {
-		/* Third Channel Test */
-		if (!(PCI_FUNC(dev->devfn) & 1)) {
-#if 1
-			struct pci_dev * findev = NULL;
-			unsigned int reg4c = 0;
-			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
-				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
-			if (findev) {
-				pci_read_config_dword(findev, 0x4C, &reg4c);
-				reg4c &= ~0x000007FF;
-				reg4c |=  0x00000040;
-				reg4c |=  0x00000020;
-				pci_write_config_dword(findev, 0x4C, reg4c);
-			}
-#endif
-			outb_p(0x06, 0x0c00);
-			dev->irq = inb_p(0x0c01);
-#if 1
-			/* WE need to figure out how to get the correct one */
-			printk("%s: interrupt %d\n", name, dev->irq);
-			if (dev->irq != 0x0B)
-				dev->irq = 0x0B;
-#endif
-		} else {
-			/*
-			 * This is a device pin issue on CSB6.
-			 * Since there will be a future raid mode,
-			 * early versions of the chipset require the
-			 * interrupt pin to be set, and it is a compatablity
-			 * mode issue.
-			 */
-			dev->irq = 0;
-		}
-		pci_write_config_dword(dev, 0x40, 0x99999999);
-		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
-		/* setup the UDMA Control register
-		 *
-		 * 1. clear bit 6 to enable DMA
-		 * 2. enable DMA modes with bits 0-1
-		 * 	00 : legacy
-		 * 	01 : udma2
-		 * 	10 : udma2/udma4
-		 * 	11 : udma2/udma4/udma5
-		 */
-		pci_read_config_byte(dev, 0x5A, &btr);
-		btr &= ~0x40;
-		if (!(PCI_FUNC(dev->devfn) & 1))
-			btr |= 0x2;
-		else
-			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
-		pci_write_config_byte(dev, 0x5A, btr);
-	}
-
-	svwks_devs[n_svwks_devs++] = dev;
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!svwks_proc) {
-		svwks_proc = 1;
-		svwks_display_info = &svwks_get_info;
-	}
-#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
-
-	return (dev->irq) ? dev->irq : 0;
-}
-
-static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
-{
-//	struct pci_dev *dev = hwif->pci_dev;
-//	return 0;
-	return 1;
-}
-
-/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
- * of the subsystem device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set   = secondary IDE channel has 80-pin cable.
- * Bit 14 clear = primary IDE channel does not have 80-pin cable.
- * Bit 14 set   = primary IDE channel has 80-pin cable.
- */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
-	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-/* Sun Cobalt Alpine hardware avoids the 80-pin cable
- * detect issue by attaching the drives directly to the board.
- * This check follows the Dell precedent (how scary is that?!)
- *
- * WARNING: this only works on Alpine hardware!
- */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-
-	/* Server Works */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
-		return ata66_svwks_svwks (hwif);
-	
-	/* Dell PowerEdge */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
-		return ata66_svwks_dell (hwif);
-
-	/* Cobalt Alpine */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
-		return ata66_svwks_cobalt (hwif);
-
-	return 0;
-}
-
-void __init ide_init_svwks (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &svwks_tune_drive;
-	hwif->speedproc = &svwks_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &svwks_dmaproc;
-# ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-# endif /* CONFIG_IDEDMA_AUTO */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
-
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-void __init ide_dmacapable_svwks (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) &&
-	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
-		return;
-#if 0
-	if (svwks_revision == (SVWKS_CSB5_REVISION_NEW + 1)) {
-		if (hwif->mate && hwif->mate->dma_base) {
-	                dmabase = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-		} else {
-			dmabase = pci_resource_start(dev, 4);
-			if (!dmabase) {
-				printk("%s: dma_base is invalid (0x%04lx)\n",
-					hwif->name, dmabase);
-				dmabase = 0;
-			}
-		}
-	}
-#endif
-	ide_setup_dma(hwif, dmabase, 8);
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if (!(PCI_FUNC(dev->devfn) & 1)) {
-		d->bootable = NEVER_BOARD;
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
- 
diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/setup-pci.c	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,948 @@
+/*
+ *  linux/drivers/ide/setup-pci.c		Version 1.10	2002/08/19
+ *
+ *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  Recent Changes
+ *	Split the set up function into multiple functions
+ *	Use pci_set_master
+ *	Fix misreporting of I/O v MMIO problems
+ */
+
+/*
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+/**
+ *	ide_match_hwif	-	match a PCI IDE against an ide_hwif
+ *	@io_base: I/O base of device
+ *	@bootable: set if its bootable
+ *	@name: name of device
+ *
+ *	Match a PCI IDE port against an entry in ide_hwifs[],
+ *	based on io_base port if possible. Return the matching hwif,
+ *	or a new hwif. If we find an error (clashing, out of devices, etc)
+ *	return NULL
+ */
+
+static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
+{
+	int h;
+	ide_hwif_t *hwif;
+
+	/*
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
+				name, io_base, hwif->name);
+			return NULL;	/* already claimed */
+		}
+	}
+	/*
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
+	 * Give preference to claiming other slots before claiming ide0/ide1,
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 *
+	 * Unless there is a bootable card that does not use the standard
+	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 */
+	if (bootable) {
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			hwif = &ide_hwifs[h];
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	} else {
+		for (h = 2; h < MAX_HWIFS; ++h) {
+			hwif = ide_hwifs + h;
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	}
+	for (h = 0; h < 2; ++h) {
+		hwif = ide_hwifs + h;
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
+	}
+	printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
+	return NULL;
+}
+
+/**
+ *	ide_setup_pci_baseregs	-	place a PCI IDE controller native
+ *	@dev: PCI device of interface to switch native
+ *	@name: Name of interface
+ *
+ *	We attempt to place the PCI interface into PCI native mode. If
+ *	we succeed the BARs are ok and the controller is in PCI mode.
+ *	Returns 0 on success or an errno code. 
+ *
+ *	FIXME: if we program the interface and then fail to set the BARS
+ *	we don't switch it back to legacy mode. Do we actually care ??
+ */
+ 
+static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+{
+	u8 progif = 0;
+
+	/*
+	 * Place both IDE interfaces into PCI "native" mode:
+	 */
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+			 (progif & 5) != 5) {
+		if ((progif & 0xa) != 0xa) {
+			printk(KERN_INFO "%s: device not capable of full "
+				"native PCI mode\n", name);
+			return -EOPNOTSUPP;
+		}
+		printk("%s: placing both ports into native PCI mode\n", name);
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+		    (progif & 5) != 5) {
+			printk(KERN_ERR "%s: rewrite of PROGIF failed, wanted "
+				"0x%04x, got 0x%04x\n",
+				name, progif|5, progif);
+			return -EOPNOTSUPP;
+		}
+	}
+
+#if 0
+	/*
+	 * At this point we have enabled the device, but may previously
+	 * have done a BAR4 enable alone. We should be prepared to assign
+	 * resources here.
+	 */
+	
+	/*
+	 * Setup base registers for IDE command/control
+	 * spaces for each interface:
+	 */
+	for (reg = 0; reg < 4; reg++) {
+		struct resource *res = dev->resource + reg;
+		if ((res->flags & IORESOURCE_IO) == 0)
+			continue;
+		if (!res->start) {
+			if(pci_assign_resource(dev, reg)) {
+				printk(KERN_ERR "%s: Missing I/O address #%d\n", name, reg);
+				return -ENXIO;
+			}
+		}
+	}
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed.  Oh the things we forget.  I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+/**
+ *	ide_get_or_set_dma_base		-	setup BMIBA
+ *	@hwif: Interface
+ *
+ *	Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ *	If need be we set up the DMA base. Where a device has a partner that
+ *	is already in DMA mode we check and enforce IDE simplex rules.
+ *
+ *	FIXME: currently we are sometimes enforicng simplex when it is not
+ *	needed. We fail the safe way but why is it occurring ??
+ */
+
+static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if ((hwif->mmio) && (hwif->dma_base))
+		return hwif->dma_base;
+
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else {
+		dma_base = (hwif->mmio) ?
+			((unsigned long) hwif->hwif_data) :
+			(pci_resource_start(dev, 4));
+		if (!dma_base) {
+			printk(KERN_ERR "%s: dma_base is invalid (0x%04lx)\n",
+				hwif->cds->name, dma_base);
+			dma_base = 0;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	/* FIXME - should use pci_assign_resource surely */
+	if ((!dma_base) && (!second_chance)) {
+		unsigned long set_bmiba = 0;
+		second_chance++;
+		switch(dev->vendor) {
+			case PCI_VENDOR_ID_AL:
+				set_bmiba = DEFAULT_BMALIBA; break;
+			case PCI_VENDOR_ID_VIA:
+				set_bmiba = DEFAULT_BMCRBA; break;
+			case PCI_VENDOR_ID_INTEL:
+				set_bmiba = DEFAULT_BMIBA; break;
+			default:
+				return dma_base;
+		}
+		pci_write_config_dword(dev, 0x20, set_bmiba|1);
+		goto second_chance_to_dma;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (dma_base) {
+		u8 simplex_stat = 0;
+		dma_base += hwif->channel ? 8 : 0;
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_AL_M5219:
+			case PCI_DEVICE_ID_AMD_VIPER_7409:
+			case PCI_DEVICE_ID_CMD_643:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				simplex_stat = hwif->INB(dma_base + 2);
+				hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					printk(KERN_INFO "%s: simplex device: "
+						"DMA forced\n",
+						hwif->cds->name);
+				}
+				break;
+			default:
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					/* simplex device? */
+					
+					/* Don't enable DMA on a simplex channel with no drives */
+					if (!hwif->drives[0].present && !hwif->drives[1].present)
+					{
+						printk(KERN_INFO "%s: simplex device with no drives: DMA disabled\n",
+								hwif->cds->name);
+						dma_base = 0;
+					}
+					/* If our other channel has DMA then we cannot */
+					else if(hwif->mate && hwif->mate->dma_base) 
+					{
+						printk(KERN_INFO "%s: simplex device: "
+							"DMA disabled\n",
+							hwif->cds->name);
+						dma_base = 0;
+					}
+				}
+		}
+	}
+	return dma_base;
+}
+#endif	/* CONFIG_BLK_DEV_IDEDMA */
+
+static void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((d->vendor != dev->vendor) && (d->device != dev->device)) {
+		printk(KERN_INFO "%s: unknown IDE controller at PCI slot "
+			"%s, VID=%04x, DID=%04x\n",
+			d->name, dev->slot_name, dev->vendor, dev->device);
+        } else {
+		printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
+			d->name, dev->slot_name);
+	}
+}
+
+/**
+ *	ide_pci_enable	-	do PCI enables
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable the IDE PCI device. We attempt to enable the device in full
+ *	but if that fails then we only need BAR4 so we will enable that.
+ *	
+ *	Returns zero on success or an error code
+ */
+ 
+static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	
+	if (pci_enable_device(dev)) {
+		if (pci_enable_device_bars(dev, 1 << 4)) {
+			printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+				"Could not enable device.\n", d->name);
+			return -EBUSY;
+		} else
+			printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name);
+	}
+	/* FIXME: Temporary - until we put in the hotplug interface logic
+	   Check that the bits we want are not in use by someone else */
+	if (pci_request_region(dev, 4, "ide_tmp"))
+		return -EBUSY;
+	pci_release_region(dev, 4);
+	
+	return 0;	
+}
+
+/**
+ *	ide_pci_configure	-	configure an unconfigured device
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable and configure the PCI device we have been passed.
+ *	Returns zero on success or an error code.
+ */
+ 
+static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u16 pcicmd = 0;
+	/*
+	 * PnP BIOS was *supposed* to have setup this device, but we
+	 * can do it ourselves, so long as the BIOS has assigned an IRQ
+	 * (or possibly the device is using a "legacy header" for IRQs).
+	 * Maybe the user deliberately *disabled* the device,
+	 * but we'll eventually ignore it again if no drives respond.
+	 */
+	if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO)) 
+	{
+		printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name);
+		return -ENODEV;
+	}
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {
+		printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name);
+		return -ENXIO;
+	}
+	return 0;
+}
+
+/**
+ *	ide_pci_check_iomem	-	check a register is I/O
+ *	@dev: pci device
+ *	@d: ide_pci_device
+ *	@bar: bar number
+ *
+ *	Checks if a BAR is configured and points to MMIO space. If so
+ *	print an error and return an error code. Otherwise return 0
+ */
+ 
+static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar)
+{
+	ulong flags = pci_resource_flags(dev, bar);
+	
+	/* Unconfigured ? */
+	if(pci_resource_len(dev, bar) == 0)
+		return 0;
+
+	/* I/O space */		
+	if(flags & PCI_BASE_ADDRESS_IO_MASK)
+		return 0;
+		
+	/* Bad */
+	printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
+			"as MEM, report to "
+			"<andre@linux-ide.org>.\n", d->name);
+	return -EINVAL;
+}
+	
+		
+/**
+ *	ide_hwif_configure	-	configure an IDE interface
+ *	@dev: PCI device holding interface
+ *	@d: IDE pci data
+ *	@mate: Paired interface if any
+ *
+ *	Perform the initial set up for the hardware interface structure. This
+ *	is done per interface port rather than per PCI device. There may be
+ *	more than one port per device.
+ *
+ *	Returns the new hardware interface structure, or NULL on a failure
+ */
+ 
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+{
+	unsigned long ctl = 0, base = 0;
+	ide_hwif_t *hwif;
+	
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE ||
+	    ((dev->class & ~(0xfa))) ||
+	    (dev->class & (port ? 4 : 1)) != 0) 
+	{    
+	    	/*  Possibly we should fail if these checks report true */
+	    	ide_pci_check_iomem(dev, d, 2*port);
+	    	ide_pci_check_iomem(dev, d, 2*port+1);
+	 
+		ctl  = pci_resource_start(dev, 2*port+1);
+		base = pci_resource_start(dev, 2*port);
+		if ((ctl && !base) || (base && !ctl)) {
+			printk(KERN_ERR "%s: inconsistent baseregs (BIOS) "
+				"for port %d, skipping\n", d->name, port);
+			return NULL;
+		}
+	}
+	if (!ctl)
+	{
+		/* Use default values */
+		ctl = port ? 0x374 : 0x3f4;
+		base = port ? 0x170 : 0x1f0;
+	}
+	if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+		return NULL;	/* no room in ide_hwifs[] */
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+fixup_address:
+		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	} else if (hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+		goto fixup_address;
+	}
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->cds = (struct ide_pci_device_s *) d;
+	hwif->channel = port;
+
+	if (!hwif->irq)
+		hwif->irq = irq;
+	if (mate) {
+		hwif->mate = mate;
+		mate->mate = hwif;
+	}
+	return hwif;
+}
+
+/**
+ *	ide_hwif_setup_dma	-	configure DMA interface
+ *	@dev: PCI device
+ *	@d: IDE pci data
+ *	@hwif: Hardware interface we are configuring
+ *
+ *	Set up the DMA base for the interface. Enable the master bits as
+ *	neccessary and attempt to bring the device DMA into a ready to use
+ *	state
+ */
+ 
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+	u16 pcicmd;
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	if ((d->autodma == AUTODMA) ||
+	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	     (dev->class & 0x80))) {
+		u32 dma_base = ide_get_or_set_dma_base(hwif);
+		if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+			/*
+ 			 * Set up BM-DMA capability
+			 * (PnP BIOS should have done this)
+ 			 */
+			if ((d->device != PCI_DEVICE_ID_CYRIX_5530_IDE)
+			    && (d->vendor != PCI_VENDOR_ID_CYRIX)) {
+				/*
+				 * default DMA off if we had to
+				 * configure it here
+				 */
+				hwif->autodma = 0;
+			}
+			pci_set_master(dev);
+			if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+				printk(KERN_ERR "%s: %s error updating PCICMD\n",
+					hwif->name, d->name);
+				dma_base = 0;
+			}
+		}
+		if (dma_base) {
+			if (d->init_dma) {
+				d->init_dma(hwif, dma_base);
+			} else {
+				ide_setup_dma(hwif, dma_base, 8);
+			}
+		} else {
+			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+				"(BIOS)\n", hwif->name, d->name);
+		}
+	}
+}
+
+/**
+ *	ide_setup_pci_controller	-	set up IDE PCI
+ *	@dev: PCI device
+ *	@d: IDE PCI data
+ *	@noisy: verbose flag
+ *	@config: returned as 1 if we configured the hardware
+ *
+ *	Set up the PCI and controller side of the IDE interface. This brings
+ *	up the PCI side of the device, checks that the device is enabled
+ *	and enables it if need be
+ */
+ 
+static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config)
+{
+	int ret = 0;
+	u32 class_rev;
+	u16 pcicmd;
+
+	if (!noautodma)
+		ret = 1;
+
+	if (noisy)
+		ide_setup_pci_noise(dev, d);
+
+	if (ide_pci_enable(dev, d))
+		return -EBUSY;
+		
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
+		if (ide_pci_configure(dev, d))
+			return -ENODEV;
+		/* default DMA off if we had to configure it here */
+		ret = 0;
+		*config = 1;
+		printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
+	}
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	if (noisy)
+		printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
+	return ret;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy)
+{
+	u32 port, at_least_one_hwif_enabled = 0, autodma = 0;
+	int pciirq = 0;
+	int tried_config = 0;
+	ata_index_t index;
+	u8 tmp = 0;
+	ide_hwif_t *hwif, *mate = NULL;
+	static int secondpdc = 0;
+
+	index.all = 0xf0f0;
+
+	if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0)
+		return index;
+
+	/*
+	 * Can we trust the reported IRQ?
+	 */
+	pciirq = dev->irq;
+	
+	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
+		if (noisy)
+			printk(KERN_INFO "%s: not 100%% native mode: "
+				"will probe irqs later\n", d->name);
+		/*
+		 * This allows offboard ide-pci cards the enable a BIOS,
+		 * verify interrupt settings of split-mirror pci-config
+		 * space, place chipset into init-mode, and/or preserve
+		 * an interrupt if the card is not native ide support.
+		 */
+		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0;
+	} else if (tried_config) {
+		if (noisy)
+			printk(KERN_INFO "%s: will probe irqs later\n", d->name);
+		pciirq = 0;
+	} else if (!pciirq) {
+		if (noisy)
+			printk(KERN_WARNING "%s: bad irq (%d): will probe later\n",
+				d->name, pciirq);
+		pciirq = 0;
+	} else {
+		if (d->init_chipset)
+		{
+			if(d->init_chipset(dev, d->name) < 0)
+				return index;
+		}
+		if (noisy)
+#ifdef __sparc__
+			printk(KERN_INFO "%s: 100%% native mode on irq %s\n",
+			       d->name, __irq_itoa(pciirq));
+#else
+			printk(KERN_INFO "%s: 100%% native mode on irq %d\n",
+				d->name, pciirq);
+#endif
+	}
+	
+	if(pciirq < 0)		/* Error not an IRQ */
+		return index;
+
+	/*
+	 * Set up the IDE ports
+	 */
+	 
+	for (port = 0; port <= 1; ++port) {
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	
+		/* 
+		 * If this is a Promise FakeRaid controller,
+		 * the 2nd controller will be marked as 
+		 * disabled while it is actually there and enabled
+		 * by the bios for raid purposes. 
+		 * Skip the normal "is it enabled" test for those.
+		 */
+		if (((d->vendor == PCI_VENDOR_ID_PROMISE) &&
+		     ((d->device == PCI_DEVICE_ID_PROMISE_20262) ||
+		      (d->device == PCI_DEVICE_ID_PROMISE_20265))) &&
+		    (secondpdc++==1) && (port==1))
+			goto controller_ok;
+			
+		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+		    (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+controller_ok:
+
+		if (d->channels	<= port)
+			return index;
+	
+		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+			continue;
+
+		if (hwif->channel) {
+			index.b.high = hwif->index;
+		} else {
+			index.b.low = hwif->index;
+		}
+
+		
+		if (d->init_iops)
+			d->init_iops(hwif);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		if (d->autodma == NODMA)
+			goto bypass_legacy_dma;
+		if (d->autodma == NOAUTODMA)
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
+		ide_hwif_setup_dma(dev, d, hwif);
+bypass_legacy_dma:
+#endif	/* CONFIG_BLK_DEV_IDEDMA */
+		if (d->init_hwif)
+			/* Call chipset-specific routine
+			 * for each enabled hwif
+			 */
+			d->init_hwif(hwif);
+
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
+	}
+	if (!at_least_one_hwif_enabled)
+		printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
+	return index;
+}
+
+void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ata_index_t index_list = do_ide_setup_pci_device(dev, d, 1);
+
+	if ((index_list.b.low & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list.b.low]);
+	if ((index_list.b.high & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list.b.high]);
+}
+
+void ide_setup_pci_devices (struct pci_dev *dev, struct pci_dev *dev2, ide_pci_device_t *d)
+{
+	ata_index_t index_list  = do_ide_setup_pci_device(dev, d, 1);
+	ata_index_t index_list2 = do_ide_setup_pci_device(dev2, d, 0);
+
+	if ((index_list.b.low & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list.b.low]);
+	if ((index_list.b.high & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list.b.high]);
+	if ((index_list2.b.low & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list2.b.low]);
+	if ((index_list2.b.high & 0xf0) != 0xf0)
+		probe_hwif_init(&ide_hwifs[index_list2.b.high]);
+}
+
+/*
+ * ide_scan_pcibus() gets invoked at boot time from ide.c.
+ * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
+ */
+void __init ide_scan_pcidev (struct pci_dev *dev)
+{
+#if 0
+	printk(" PCI slot %s, VID=%04x, DID=%04x\n",
+		dev->slot_name, dev->vendor, dev->device);
+#endif
+
+	if ((dev->vendor == PCI_VENDOR_ID_CMD) &&
+	    (dev->device == PCI_DEVICE_ID_CMD_640)) {
+		return;
+#ifdef CONFIG_BLK_DEV_ALI15X3
+	}{
+		extern int ali15x3_scan_pcidev(struct pci_dev *dev);
+		if (ali15x3_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD74XX
+	}{
+		extern int amd74xx_scan_pcidev(struct pci_dev *dev);
+		if (amd74xx_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_AMD74XX */
+#ifdef CONFIG_BLK_DEV_CS5530
+	}{
+		extern int cs5530_scan_pcidev(struct pci_dev *dev);
+		if (cs5530_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_CY82C693
+	}{
+		extern int cy82c693_scan_pcidev(struct pci_dev *dev);
+		if (cy82c693_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_CY82C693 */
+#ifdef CONFIG_BLK_DEV_IT8172
+	}{
+		extern int it8172_scan_pcidev(struct pci_dev *dev);
+		if (it8172_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_IT8172 */
+#ifdef CONFIG_BLK_DEV_NFORCE
+	}{
+		extern int nforce_scan_pcidev(struct pci_dev *dev);
+		if (nforce_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_NFORCE */
+#ifdef CONFIG_BLK_DEV_NS87415
+	}{
+		extern int ns87415_scan_pcidev(struct pci_dev *dev);
+		if (ns87415_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_NS87415 */
+#ifdef CONFIG_BLK_DEV_OPTI621
+	}{
+		extern int opti621_scan_pcidev(struct pci_dev *dev);
+		if (opti621_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_OPTI621 */
+#ifdef CONFIG_BLK_DEV_PIIX
+	}{
+		extern int piix_scan_pcidev(struct pci_dev *dev);
+		if (piix_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_PIIX */
+#ifdef CONFIG_BLK_DEV_RZ1000
+	}{
+		extern int rz1000_scan_pcidev(struct pci_dev *dev);
+		if (rz1000_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_RZ1000 */
+#ifdef CONFIG_BLK_DEV_SVWKS
+	}{
+		extern int serverworks_scan_pcidev(struct pci_dev *dev);
+		if (serverworks_scan_pcidev(dev))	return;
+#endif /* CONFIG_BLK_DEV_SVWKS */
+#ifdef CONFIG_BLK_DEV_SIS5513
+	}{
+		extern int sis5513_scan_pcidev(struct pci_dev *dev);
+		if (sis5513_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_SIS5513 */
+#ifdef CONFIG_BLK_DEV_SLC90E66
+	}{
+		extern int slc90e66_scan_pcidev(struct pci_dev *dev);
+		if (slc90e66_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_SLC90E66 */
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	}{
+		extern int via82cxxx_scan_pcidev(struct pci_dev *dev);
+		if (via82cxxx_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	}{
+		extern int aec62xx_scan_pcidev(struct pci_dev *dev);
+		if (aec62xx_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_AEC62XX */
+#ifdef CONFIG_BLK_DEV_CMD64X
+	}{
+		extern int cmd64x_scan_pcidev(struct pci_dev *dev);
+		if (cmd64x_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_HPT34X
+	}{
+		extern int hpt34x_scan_pcidev(struct pci_dev *dev);
+		if (hpt34x_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+	}{
+		extern int hpt366_scan_pcidev(struct pci_dev *dev);
+		if (hpt366_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX_OLD
+	}{
+		extern int pdc202xx_scan_pcidev(struct pci_dev *dev);
+		if (pdc202xx_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_PDC202XX_OLD */
+#ifdef CONFIG_BLK_DEV_PDC202XX_NEW
+	}{
+		extern int pdcnew_scan_pcidev(struct pci_dev *dev);
+		if (pdcnew_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_PDC202XX_NEW */
+#ifdef CONFIG_BLK_DEV_PDC_ADMA
+	}{
+		extern int pdcadma_scan_pcidev(struct pci_dev *dev);
+		if (pdcadma_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_PDC_ADMA */
+#ifdef CONFIG_BLK_DEV_SIIMAGE
+	}{
+		extern int siimage_scan_pcidev(struct pci_dev *dev);
+		if (siimage_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_SIIMAGE */
+#ifdef CONFIG_BLK_DEV_SL82C105
+	}{
+		extern int sl82c105_scan_pcidev(struct pci_dev *dev);
+		if (sl82c105_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_SL82C105 */
+#ifdef CONFIG_BLK_DEV_TRM290
+	}{
+		extern int trm290_scan_pcidev(struct pci_dev *dev);
+		if (trm290_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_TRM290 */
+#ifdef CONFIG_BLK_DEV_GENERIC
+	}{
+		extern int generic_scan_pcidev(struct pci_dev *dev);
+		if (generic_scan_pcidev(dev))		return;
+#endif /* CONFIG_BLK_DEV_GENERIC */
+	}
+}
+
+
+/*
+ *	Module interfaces - not yet functional.
+ */
+ 
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	ide_register_pci_driver		-	attach IDE driver
+ *	@driver: pci driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then 
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	The driver_data of the driver table must point to an ide_pci_device_t
+ *	describing the interface.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int ide_register_pci_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		return pci_register_driver(driver);
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_register_pci_driver);
+
+/**
+ *	ide_unregister_pci_driver	-	unregister an IDE driver
+ *	@driver: driver to remove
+ *
+ *	Unregister a currently installed IDE driver. Returns are the same
+ *	as for pci_unregister_driver
+ */
+ 
+void ide_unregister_pci_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		pci_unregister_driver(driver);
+	else
+		list_del(&driver->node);
+}
+
+EXPORT_SYMBOL(ide_unregister_pci_driver);
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *	@scan_direction: set for reverse order scanning
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+ 	
+void __init ide_scan_pcibus (int scan_direction)
+{
+	struct pci_dev *dev;
+
+	pre_init = 0;
+	if (!scan_direction) {
+		pci_for_each_dev(dev) {
+			ide_scan_pcidev(dev);
+		}
+	} else {
+		pci_for_each_dev_reverse(dev) {
+			ide_scan_pcidev(dev);
+		}
+	}
+	/* FIXME: now add the drivers list to the real pci probe list */
+}
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Sun Sep 15 19:19:46 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,927 +0,0 @@
-/*
- * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
- *
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan		: for direct support and hardware.
- * Daniela Engert	: for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul :
- *			  for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620/5513 chipset.
- * ATA100 tests and design on the SiS735/5513 chipset.
- * ATA16/33 design from specs
- */
-
-/*
- * TODO:
- *	- Get ridden of SisHostChipInfo[] completness dependancy.
- *	- Get ATA-133 datasheets, implement ATA-133 init code.
- *	- Study drivers/ide/ide-timing.h.
- *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
- *	  or remove ATA_00 define
- *	- More checks in the config registers (force values instead of
- *	  relying on the BIOS setting them correctly).
- *	- Further optimisations ?
- *	  . for example ATA66+ regs 0x48 & 0x4A
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-/* When DEBUG is defined it outputs initial PCI config register
-   values and changes made to them by the driver */   
-// #define DEBUG
-/* When BROKEN_LEVEL is defined it limits the DMA mode
-   at boot time to its value */
-// #define BROKEN_LEVEL XFER_SW_DMA_0
-#define DISPLAY_SIS_TIMINGS
-
-/* Miscellaneaous flags */
-#define SIS5513_LATENCY		0x01
-
-/* registers layout and init values are chipset family dependant */
-/* 1/ define families */
-#define ATA_00		0x00
-#define ATA_16		0x01
-#define ATA_33		0x02
-#define ATA_66		0x03
-#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
-#define ATA_100		0x05
-#define ATA_133		0x06
-/* 2/ variable holding the controller chipset family value */
-static unsigned char chipset_family;
-
-
-/*
- * Debug code: following IDE config registers' changes
- */
-#ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x57
-   Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[0x58];
-
-static byte sis5513_max_config_register(void) {
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:	return 0x4f;
-		case ATA_33:	return 0x52;
-		case ATA_66:
-		case ATA_100a:
-		case ATA_100:
-		case ATA_133:
-		default:	return 0x57;
-	}
-}
-
-/* Read config registers, print differences from previous read */
-static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
-	int i;
-	byte reg_val;
-	byte changed=0;
-	byte max = sis5513_max_config_register();
-
-	printk("SIS5513: %s, changed registers:\n", info);
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &reg_val);
-		if (reg_val != ide_regs_copy[i]) {
-			printk("%0#x: %0#x -> %0#x\n",
-			       i, ide_regs_copy[i], reg_val);
-			ide_regs_copy[i]=reg_val;
-			changed=1;
-		}
-	}
-
-	if (!changed) {
-		printk("none\n");
-	}
-}
-
-/* Load config registers, no printing */
-static void sis5513_load_registers(struct pci_dev* dev) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
-	}
-}
-
-/* Print a register */
-static void sis5513_print_register(int reg) {
-	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
-}
-
-/* Print valuable registers */
-static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	sis5513_load_registers(dev);
-	printk("SIS5513 %s\n", marker);
-	printk("SIS5513 dump:");
-	for(i=0x00; i<0x40; i++) {
-		if ((i % 0x10)==0) printk("\n             ");
-		sis5513_print_register(i);
-	}
-	for(; i<49; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n             ");
-
-	for(; i<=max; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n");
-}
-#endif
-
-
-/*
- * Devices supported
- */
-static const struct {
-	const char *name;
-	unsigned short host_id;
-	unsigned char chipset_family;
-	unsigned char flags;
-} SiSHostChipInfo[] = {
-	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
-	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
-	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
-	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
-};
-
-/* Cycle time bits and values vary accross chip dma capabilities
-   These three arrays hold the register layout and the values to set.
-   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
-static byte cycle_time_range[] = {0,0,2,3,3,4,4};
-static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
-	{0,0,0,0,0,0}, /* no udma */
-	{0,0,0,0,0,0}, /* no udma */
-	{3,2,1,0,0,0},
-	{7,5,3,2,1,0},
-	{7,5,3,2,1,0},
-	{11,7,5,4,2,1},
-	{0,0,0,0,0,0} /* not yet known, ask SiS */
-};
-
-static struct pci_dev *host_dev = NULL;
-
-
-/*
- * Printing configuration
- */
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int sis_get_info(char *, char **, off_t, int);
-extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static char* cable_type[] = {
-	"80 pins",
-	"40 pins"
-};
-
-static char* recovery_time[] ={
-	"12 PCICLK", "1 PCICLK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLCK",
-	"6 PCICLK", "7 PCICLCK",
-	"8 PCICLK", "9 PCICLCK",
-	"10 PCICLK", "11 PCICLK",
-	"13 PCICLK", "14 PCICLK",
-	"15 PCICLK", "15 PCICLK"
-};
-
-static char* active_time[] = {
-	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLK",
-	"6 PCICLK", "12 PCICLK"
-};
-
-static char* cycle_time[] = {
-	"Reserved", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK",
-	"9 CLK", "10 CLK",
-	"11 CLK", "12 CLK",
-	"Reserved", "Reserved",
-	"Reserved", "Reserved"
-};
-
-/* Generic add master or slave info function */
-static char* get_drives_info (char *buffer, byte pos)
-{
-	byte reg00, reg01, reg10, reg11; /* timing registers */
-	char* p = buffer;
-
-/* Postwrite/Prefetch */
-	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
-	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
-		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
-
-	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
-	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
-	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
-	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
-
-/* UDMA */
-	if (chipset_family >= ATA_33) {
-		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
-			     (reg11 & 0x80) ? "Enabled" : "Disabled");
-
-		p += sprintf(p, "                UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, " \t UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, "\n");
-	}
-
-/* Data Active */
-	p += sprintf(p, "                Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16: /* confirmed */
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, " \t Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, "\n");
-
-/* Data Recovery */
-	/* warning: may need (reg&0x07) for pre ATA66 chips */
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
-
-	return p;
-}
-
-static char* get_masters_info(char* buffer)
-{
-	return get_drives_info(buffer, 0);
-}
-
-static char* get_slaves_info(char* buffer)
-{
-	return get_drives_info(buffer, 1);
-}
-
-/* Main get_info, called on /proc/ide/sis reads */
-static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	byte reg;
-	u16 reg2, reg3;
-
-	p += sprintf(p, "\nSiS 5513 ");
-	switch(chipset_family) {
-		case ATA_00: p += sprintf(p, "Unknown???"); break;
-		case ATA_16: p += sprintf(p, "DMA 16"); break;
-		case ATA_33: p += sprintf(p, "Ultra 33"); break;
-		case ATA_66: p += sprintf(p, "Ultra 66"); break;
-		case ATA_100a:
-		case ATA_100: p += sprintf(p, "Ultra 100"); break;
-		case ATA_133:
-		default: p+= sprintf(p, "Ultra 133+"); break;
-	}
-	p += sprintf(p, " chipset\n");
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-
-/* Status */
-	pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: ");
-	if (chipset_family < ATA_66) {
-		p += sprintf(p, "%s \t \t \t \t %s\n",
-			     (reg & 0x04) ? "On" : "Off",
-			     (reg & 0x02) ? "On" : "Off");
-	} else {
-		p += sprintf(p, "%s \t \t \t \t %s \n",
-			     (reg & 0x02) ? "On" : "Off",
-			     (reg & 0x04) ? "On" : "Off");
-	}
-
-/* Operation Mode */
-	pci_read_config_byte(bmide_dev, 0x09, &reg);
-	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
-		     (reg & 0x01) ? "Native" : "Compatible",
-		     (reg & 0x04) ? "Native" : "Compatible");
-
-/* 80-pin cable ? */
-	if (chipset_family > ATA_33) {
-		pci_read_config_byte(bmide_dev, 0x48, &reg);
-		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-			     (reg & 0x10) ? cable_type[1] : cable_type[0],
-			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-	}
-
-/* Prefetch Count */
-	pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	p = get_masters_info(p);
-	p = get_slaves_info(p);
-
-	return p-buffer;
-}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-
-byte sis_proc = 0;
-
-static byte sis5513_ratemask (ide_drive_t *drive)
-{
-//	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte mode		= 0x00;
-
-	switch(chipset_family) {
-		case ATA_133:	//	{ mode |= 0x04; break; }
-		case ATA_100:
-		case ATA_100a:	{ mode |= 0x03; break; }
-		case ATA_66:	{ mode |= 0x02; break; }
-		case ATA_33:	{ mode |= 0x01; break; }
-		case ATA_16:
-                case ATA_00:	
-		default:
-			return (mode &= ~0xF8);
-	}
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte sis5513_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = sis5513_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-/*
- * Configuration functions
- */
-/* Enables per-drive prefetch and postwrite */
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte reg4bh		= 0;
-	byte rw_prefetch	= (0x11 << drive->dn);
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
-#endif
-
-	if (drive->media != ide_disk)
-		return;
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
-
-	if ((reg4bh & rw_prefetch) != rw_prefetch)
-		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
-#endif
-}
-
-
-/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			timing, drive_pci, test1, test2;
-
-	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-
-	config_drive_art_rwp(drive);
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			(xfer_pio > 0) &&
-			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
-	       drive->dn, pio, timing);
-#endif
-
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return;
-	}
-
-	/* register layout changed with newer ATA100 chips */
-	if (chipset_family < ATA_100) {
-		pci_read_config_byte(dev, drive_pci, &test1);
-		pci_read_config_byte(dev, drive_pci+1, &test2);
-
-		/* Clear active and recovery timings */
-		test1 &= ~0x0F;
-		test2 &= ~0x07;
-
-		switch(timing) {
-			case 4:		test1 |= 0x01; test2 |= 0x03; break;
-			case 3:		test1 |= 0x03; test2 |= 0x03; break;
-			case 2:		test1 |= 0x04; test2 |= 0x04; break;
-			case 1:		test1 |= 0x07; test2 |= 0x06; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-		pci_write_config_byte(dev, drive_pci+1, test2);
-	} else {
-		switch(timing) { /*   active  recovery
-					  v     v */
-			case 4:		test1 = 0x30|0x01; break;
-			case 3:		test1 = 0x30|0x03; break;
-			case 2:		test1 = 0x40|0x04; break;
-			case 1:		test1 = 0x60|0x07; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-	}
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-}
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	config_art_rwp_pio(drive, pio);
-	return (ide_config_drive_speed(drive, speed));
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte speed		= sis5513_ratefilter(drive, xferspeed);
-	byte			drive_pci, reg;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
-	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
-	       drive->dn, speed);
-#endif
-#if 1
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return ide_dma_off;
-	}
-#else
-//	drive_pci = (0x40 + ((drive->dn) *2));
-//	drive_pci = 0x40;
-//	drive_pci |= ((drive->dn) << 1);
-#endif
-
-#ifdef BROKEN_LEVEL
-#ifdef DEBUG
-	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
-#endif
-	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
-#endif
-
-	pci_read_config_byte(dev, drive_pci+1, &reg);
-	/* Disable UDMA bit for non UDMA modes on UDMA chips */
-	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
-		reg &= 0x7F;
-		pci_write_config_byte(dev, drive_pci+1, reg);
-	}
-
-	/* Config chip for mode */
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			/* Force the UDMA bit on if we want to use UDMA */
-			reg |= 0x80;
-			/* clean reg cycle time bits */
-			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-				 << cycle_time_offset[chipset_family]);
-			/* set reg cycle time bits */
-			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
-				<< cycle_time_offset[chipset_family];
-			pci_write_config_byte(dev, drive_pci+1, reg);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
-		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
-		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
-		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
-		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));	
-	}
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
-#endif
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= sis5513_ratemask(drive);
-	byte speed		= 0;
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d ultra %d\n",
-	       drive->dn, mode);
-#endif
-
-	switch(mode) {
-		case 0x04:
-			if (id->dma_ultra & 0x0040)
-				{ speed = XFER_UDMA_6; break; }
-		case 0x03:
-			if (id->dma_ultra & 0x0020)
-				{ speed = XFER_UDMA_5; break; }
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_mword & 0x0001)
-				{ speed = XFER_MW_DMA_0; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-			if (id->dma_1word & 0x0002)
-				{ speed = XFER_SW_DMA_1; break; }
-			if (id->dma_1word & 0x0001)
-				{ speed = XFER_SW_DMA_0; break; }
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-	sis5513_tune_chipset(drive, speed);
-//	return ((int) ide_dma_on);
-	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_dma_action_t dma_func	= ide_dma_off_quietly;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
-			   (id->eide_dma_time > 150)) {
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		sis5513_tune_drive(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/* initiates/aborts (U)DMA read/write operations on a drive. */
-int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			config_drive_art_rwp(drive);
-			config_art_rwp_pio(drive, 5);
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/* Chip detection and general config */
-unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *host;
-	int i = 0;
-
-	/* Find the chip */
-	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
-		host = pci_find_device (PCI_VENDOR_ID_SI,
-					SiSHostChipInfo[i].host_id,
-					NULL);
-		if (!host)
-			continue;
-
-		host_dev = host;
-		chipset_family = SiSHostChipInfo[i].chipset_family;
-		printk(SiSHostChipInfo[i].name);
-		printk("\n");
-
-#ifdef DEBUG
-		sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
-		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
-			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
-		}
-	}
-
-	/* Make general config ops here
-	   1/ tell IDE channels to operate in Compabitility mode only
-	   2/ tell old chips to allow per drive IDE timings */
-	if (host_dev) {
-		byte reg;
-		switch(chipset_family) {
-			case ATA_133:
-			case ATA_100:
-				/* Set compatibility bit */
-				pci_read_config_byte(dev, 0x49, &reg);
-				if (!(reg & 0x01)) {
-					pci_write_config_byte(dev, 0x49, reg|0x01);
-				}
-				break;
-			case ATA_100a:
-			case ATA_66:
-				/* On ATA_66 chips the bit was elsewhere */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x04)) {
-					pci_write_config_byte(dev, 0x52, reg|0x04);
-				}
-				break;
-			case ATA_33:
-				/* On ATA_33 we didn't have a single bit to set */
-				pci_read_config_byte(dev, 0x09, &reg);
-				if ((reg & 0x0f) != 0x00) {
-					pci_write_config_byte(dev, 0x09, reg&0xf0);
-				}
-			case ATA_16:
-				/* force per drive recovery and active timings
-				   needed on ATA_33 and below chips */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x08)) {
-					pci_write_config_byte(dev, 0x52, reg|0x08);
-				}
-				break;
-			case ATA_00:
-			default: break;
-		}
-
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-		if (!sis_proc) {
-			sis_proc = 1;
-			bmide_dev = dev;
-			sis_display_info = &sis_get_info;
-		}
-#endif
-	}
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
-#endif
-	return 0;
-}
-
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
-{
-	byte reg48h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x20 : 0x10;
-	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
-
-	if (chipset_family >= ATA_66) {
-		ata66 = (reg48h & mask) ? 0 : 1;
-	}
-        return ata66;
-}
-
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
-{
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &sis5513_tune_drive;
-	hwif->speedproc = &sis5513_tune_chipset;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-	if (!(hwif->dma_base))
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (host_dev) {
-		if (chipset_family > ATA_16)
-			hwif->dmaproc = &sis5513_dmaproc;
-		else
-			hwif->autodma = 0;
-	}
-# ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-# endif /* CONFIG_IDEDMA_AUTO */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	return;
-}
-
-extern void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d);
-
-void __init fixup_device_sis5513 (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	if (dev->resource[0].start != 0x01F1)
-		ide_register_xp_fix(dev);
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n",
-		d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-}
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Sun Sep 15 19:19:30 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,272 +0,0 @@
-/*
- * linux/drivers/ide/sl82c105.c
- *
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- *  -- Russell King (15/11/98) linux@arm.linux.org.uk
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "ide_modes.h"
-
-/*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface.  This has protection against run-away
- * timings.
- */
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
-{
-	unsigned int cmd_on;
-	unsigned int cmd_off;
-
-	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
-
-	if (cmd_on > 32)
-		cmd_on = 32;
-	if (cmd_on == 0)
-		cmd_on = 1;
-
-	if (cmd_off > 32)
-		cmd_off = 32;
-	if (cmd_off == 0)
-		cmd_off = 1;
-
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
-}
-
-/*
- * Configure the drive and chipset for PIO
- */
-static void config_for_pio(ide_drive_t *drive, int pio, int report)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	ide_pio_data_t p;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int xfer_mode, reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
-	switch (pio) {
-	default:
-	case 0:		xfer_mode = XFER_PIO_0;		break;
-	case 1:		xfer_mode = XFER_PIO_1;		break;
-	case 2:		xfer_mode = XFER_PIO_2;		break;
-	case 3:		xfer_mode = XFER_PIO_3;		break;
-	case 4:		xfer_mode = XFER_PIO_4;		break;
-	}
-
-	if (ide_config_drive_speed(drive, xfer_mode) == 0)
-		drv_ctrl = get_timing_sl82c105(&p);
-
-	if (drive->using_dma == 0) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg, drv_ctrl);
-		pci_read_config_word(dev, reg, &drv_ctrl);
-
-		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
-		}
-	}
-}
-
-/*
- * Configure the drive and the chipset for DMA
- */
-static int config_for_dma(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
-		drv_ctrl = 0x0240;
-
-	pci_write_config_word(dev, reg, drv_ctrl);
-
-	return 0;
-}
-
-/*
- * Check to see if the drive and
- * chipset is capable of DMA mode
- */
-static int sl82c105_check_drive(ide_drive_t *drive)
-{
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	do {
-		struct hd_driveid *id = drive->id;
-		ide_hwif_t *hwif = HWIF(drive);
-
-		if (!hwif->autodma)
-			break;
-
-		if (!id || !(id->capability & 1))
-			break;
-
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			break;
-		}
-
-		if (id->field_valid & 2) {
-			if  (id->dma_mword & 7 || id->dma_1word & 7)
-				dma_func = ide_dma_on;
-			break;
-		}
-
-		if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			dma_func = ide_dma_on;
-			break;
-		}
-	} while (0);
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * Our own dmaproc, only to intercept ide_dma_check
- */
-static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-	case ide_dma_check:
-		return sl82c105_check_drive(drive);
-	case ide_dma_on:
-		if (config_for_dma(drive))
-			func = ide_dma_off;
-		/* fall through */
-	case ide_dma_off_quietly:
-	case ide_dma_off:
-		config_for_pio(drive, 4, 0);
-		break;
-	default:
-		break;
-	}
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
-{
-	config_for_pio(drive, pio, 1);
-
-	/*
-	 * We support 32-bit I/O on this interface, and it
-	 * doesn't have problems with interrupts.
-	 */
-	drive->io_32bit = 1;
-	drive->unmask = 1;
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
-{
-	struct pci_dev *bridge;
-	unsigned char rev;
-
-	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
-
-	/*
-	 * If we are part of a Winbond 553
-	 */
-	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
-		return -1;
-
-	if (bridge->bus != dev->bus ||
-	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
-		return -1;
-
-	/*
-	 * We need to find function 0's revision, not function 1
-	 */
-	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
-
-	return rev;
-}
-
-/*
- * Enable the PCI device
- */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
-{
-	unsigned char ctrl_stat;
-
-	/*
-	 * Enable the ports
-	 */
-	pci_read_config_byte(dev, 0x40, &ctrl_stat);
-	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
-
-	return dev->irq;
-}
-
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
-	unsigned int rev;
-	byte dma_state;
-
-	dma_state = IN_BYTE(dma_base + 2);
-	rev = sl82c105_bridge_revision(hwif->pci_dev);
-	if (rev <= 5) {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-		dma_state &= ~0x60;
-	} else {
-		dma_state |= 0x60;
-		hwif->autodma = 1;
-	}
-	OUT_BYTE(dma_state, dma_base + 2);
-
-	hwif->dmaproc = NULL;
-	ide_setup_dma(hwif, dma_base, 8);
-	if (hwif->dmaproc)
-		hwif->dmaproc = sl82c105_dmaproc;
-}
-
-/*
- * Initialise the chip
- */
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
-{
-	hwif->tuneproc = tune_sl82c105;
-}
-
diff -Nru a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
--- a/drivers/ide/slc90e66.c	Sun Sep 15 19:20:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,470 +0,0 @@
-/*
- *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
- *
- *  Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- * 00:07.1 IDE interface: EFAR Microsystems:
- * 		Unknown device 9130 (prog-if 8a [Master SecP PriP])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV-
- * 		VGASnoop- ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium
- * 		>TAbort- <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 64
- * Interrupt: pin A routed to IRQ 255
- * Region 4: I/O ports at 1050
- *
- * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00
- * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00
- * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define SLC90E66_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SLC90E66_TIMINGS
-
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int slc90e66_get_info(char *, char **, off_t, int);
-extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x47, &reg47);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-#ifdef __mips__	/* only for mips? */
-	c0 = inb_p(bibma + 0x02);
-	c1 = inb_p(bibma + 0x0a);
-#else
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-#endif
-
-	p += sprintf(p, "                                SLC90E66 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel "
-			"---------------- Secondary Channel "
-			"-------------\n");
-	p += sprintf(p, "                %sabled "
-			"                        %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 "
-			"-------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s "
-			"            %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s              %s "
-			"            %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s "
-			"              %s                 %s\n",
-			((reg4a&0x04)==0x04) ? "4" :
-			((reg4a&0x03)==0x03) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4a&0x40)==0x40) ? "4" :
-			((reg4a&0x30)==0x30) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4b&0x04)==0x04) ? "4" :
-			((reg4b&0x03)==0x03) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg4b&0x40)==0x40) ? "4" :
-			((reg4b&0x30)==0x30) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte slc90e66_proc = 0;
-
-static byte slc90e66_ratemask (ide_drive_t *drive)
-{
-	byte mode	= 0x00;
-
-	mode |= 0x02;
-
-	if (!eighty_ninty_three(drive)) {
-		mode &= ~0xFE;
-		mode |= 0x01;
-	}
-	return (mode &= ~0xF8);
-}
-
-static byte slc90e66_ratefilter (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	byte mode = slc90e66_ratemask(drive);
-
-	switch(mode) {
-		case 0x04:	// while (speed > XFER_UDMA_6) speed--; break;
-		case 0x03:	// while (speed > XFER_UDMA_5) speed--; break;
-		case 0x02:	while (speed > XFER_UDMA_4) speed--; break;
-		case 0x01:	while (speed > XFER_UDMA_2) speed--; break;
-		case 0x00:
-		default:	while (speed > XFER_MW_DMA_2) speed--; break;
-			break;
-	}
-#else
-	while (speed > XFER_PIO_4) speed--;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-//	printk("%s: mode == %02x speed == %02x\n", drive->name, mode, speed);
-	return speed;
-}
-
-static byte slc90e66_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int is_slave		= (&hwif->drives[1] == drive);
-	int master_port		= hwif->channel ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	spin_lock_irqsave(&ide_lock, flags);
-	pci_read_config_word(dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(dev, slave_port, &slave_data);
-		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
-	}
-	pci_write_config_word(dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(dev, slave_port, slave_data);
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static int slc90e66_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	byte speed		= slc90e66_ratefilter(drive, xferspeed);
-	int a_speed		= 7 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_0:        break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if ((reg4a & u_speed) != u_speed) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_read_config_word(dev, 0x4a, &reg4a);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-	} else {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-	}
-
-	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
-	return (ide_config_drive_speed(drive, speed));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte mode		= slc90e66_ratemask(drive);
-	byte speed, tspeed, dma = 1;
-
-	switch(mode) {
-		case 0x02:
-			if (id->dma_ultra & 0x0010)
-				{ speed = XFER_UDMA_4; break; }
-			if (id->dma_ultra & 0x0008)
-				{ speed = XFER_UDMA_3; break; }
-		case 0x01:
-			if (id->dma_ultra & 0x0004)
-				{ speed = XFER_UDMA_2; break; }
-			if (id->dma_ultra & 0x0002)
-				{ speed = XFER_UDMA_1; break; }
-			if (id->dma_ultra & 0x0001)
-				{ speed = XFER_UDMA_0; break; }
-		case 0x00:
-			if (id->dma_mword & 0x0004)
-				{ speed = XFER_MW_DMA_2; break; }
-			if (id->dma_mword & 0x0002)
-				{ speed = XFER_MW_DMA_1; break; }
-			if (id->dma_1word & 0x0004)
-				{ speed = XFER_SW_DMA_2; break; }
-		default:
-			tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
-			speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
-			dma = 0;
-			break;
-	}
-
-	(void) slc90e66_tune_chipset(drive, speed);
-//	return ((int)   (dma) ? ide_dma_on : ide_dma_off_quietly);
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	drive->init_speed = 0;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = slc90e66_config_drive_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = slc90e66_config_drive_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = slc90e66_config_drive_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		slc90e66_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!slc90e66_proc) {
-		slc90e66_proc = 1;
-		bmide_dev = dev;
-		slc90e66_display_info = &slc90e66_get_info;
-	}
-#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
-{
-	byte reg47 = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x01 : 0x02;	/* bit0:Primary */
-
-	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
-	ata66 = (reg47 & mask) ? 0 : 1;	/* bit[0(1)]: 0:80, 1:40 */
-	return ata66;
-}
-
-void __init ide_init_slc90e66 (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->autodma = 0;
-	hwif->speedproc = &slc90e66_tune_chipset;
-	hwif->tuneproc = &slc90e66_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA 
-	hwif->dmaproc = &slc90e66_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		hwif->autodma = 1;
-#endif /* CONFIG_IDEDMA_AUTO */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,315 +0,0 @@
-/*
- *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
- *
- *  Copyright (c) 1997-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- * This module provides support for the bus-master IDE DMA function
- * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board.  The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL!  It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- *	bit7 must always be written as "1"
- *	bits6-2 undefined
- *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
- *	bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- *	bits7-2 undefined
- *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- *	bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- *	bits7-5 undefined
- *	bit4 legacy_header: 1=present, 0=absent
- *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- *	bit5 0=enabled master burst access (default), 1=disable  (write only)
- *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- *	bit3 0=primary IDE channel, 1=secondary IDE channel
- *	bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- *	two sets of seven config registers,
- *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- *	each index defined below:
- *
- * Index-0 Base address register for command block (word)
- *	defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- *	bit7 1=DMA enable, 0=DMA disable
- *	bit6 1=activate IDE_RESET, 0=no action (default)
- *	bit5 1=enable IORDY, 0=disable IORDY (default)
- *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- *	bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- *	bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- *	bit7 1=enable_readahead, 0=disable_readahead(default)
- *	bit6 1=clear_FIFO, 0=no_action
- *	bit5 undefined
- *	bit4 mode4 timing control: 1=enable, 0=disable(default)
- *	bit3 undefined
- *	bit2 undefined
- *	bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- *	defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- *	standard PCI "clk" (clock) counts, default value = 0xf5
- *
- *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
- *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
- *				011=4clk, 100=5clk, 101=6clk,
- *				110=8clk, 111=12clk
- *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
- *				011=5clk, 100=6clk, 101=8clk,
- *				110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- *	same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int reg;
-	unsigned long flags;
-
-	/* select PIO or DMA */
-	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
-	local_irq_save(flags);
-
-	if (reg != hwif->select_data) {
-		hwif->select_data = reg;
-		/* set PIO/DMA */
-		OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
-		OUT_WORD(reg & 0xff, hwif->config_data);
-	}
-
-	/* enable IRQ if not probing */
-	if (drive->present) {
-		reg = IN_WORD(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
-		OUT_WORD(reg, hwif->config_data+3);
-	}
-
-	local_irq_restore(flags);
-}
-
-static void trm290_selectproc (ide_drive_t *drive)
-{
-	trm290_prepare_drive(drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-//	ide_task_t *args = HWGROUP(drive)->rq->special;
-	unsigned int count, reading = 2, writing = 0;
-
-	switch (func) {
-		case ide_dma_write:
-			reading = 0;
-			writing = 1;
-#ifdef TRM290_NO_DMA_WRITES
-			break;	/* always use PIO for writes */
-#endif
-		case ide_dma_read:
-			if (!(count = ide_build_dmatable(drive, func)))
-				/* try PIO instead of DMA */
-				break;
-			/* select DMA xfer */
-			trm290_prepare_drive(drive, 1);
-			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
-			drive->waiting_for_dma = 1;
-			/* start DMA */
-			OUT_WORD((count * 2) - 1, hwif->dma_base+2);
-			if (drive->media != ide_disk)
-				return 0;
-			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
-				BUG();
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-/*
- * FIX ME to use only ACB ide_task_t args Struct
- */
-#if 0
-		{
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		}
-#else
-			if (HWGROUP(drive)->rq->flags == REQ_DRIVE_TASKFILE) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing == 1)
-				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-			else
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-#endif
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-		case ide_dma_begin:
-			return 0;
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			/* purge DMA mappings */
-			ide_destroy_dmatable(drive);
-			return (IN_WORD(hwif->dma_base+2) != 0x00ff);
-		case ide_dma_test_irq:
-			return (IN_WORD(hwif->dma_base+2) == 0x00ff);
-		default:
-			return ide_dmaproc(func, drive);
-	}
-	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-	return 1;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Invoked from ide-dma.c at boot time.
- */
-void __init ide_init_trm290 (ide_hwif_t *hwif)
-{
-	unsigned int cfgbase = 0;
-	unsigned long flags;
-	byte reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_trm290;
-	cfgbase = pci_resource_start(dev, 4);
-	if ((dev->class & 5) && cfgbase) {
-		hwif->config_data = cfgbase;
-		printk("TRM290: chip config base at 0x%04lx\n",
-			hwif->config_data);
-	} else {
-		hwif->config_data = 0x3df0;
-		printk("TRM290: using default config base at 0x%04lx\n",
-			hwif->config_data);
-	}
-
-	local_irq_save(flags);
-	/* put config reg into first byte of hwif->select_data */
-	OUT_BYTE(0x51|(hwif->channel<<3), hwif->config_data+1);
-	/* select PIO as default */
-	hwif->select_data = 0x21;
-	OUT_BYTE(hwif->select_data, hwif->config_data);
-	/* get IRQ info */
-	reg = IN_BYTE(hwif->config_data+3);
-	/* mask IRQs for both ports */
-	reg = (reg & 0x10) | 0x03;
-	OUT_BYTE(reg, hwif->config_data+3);
-	local_irq_restore(flags);
-
-	if ((reg & 0x10))
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &trm290_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &trm290_selectproc;
-	hwif->autodma = 0;			/* play it safe for now */
-#if 1
-	{
-	/*
-	 * My trm290-based card doesn't seem to work with all possible values
-	 * for the control basereg, so this kludge ensures that we use only
-	 * values that are known to work.  Ugh.		-ml
-	 */
-		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
-		static unsigned short next_offset = 0;
-
-		OUT_BYTE(0x54|(hwif->channel<<3), hwif->config_data+1);
-		old = IN_WORD(hwif->config_data) & ~1;
-		if (old != compat && IN_BYTE(old+2) == 0xff) {
-			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
-#if 1
-			if (ide_check_region(compat + 2, 1))
-				printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2));
-			/*
-			 * The region check is not needed; however.........
-			 * Since this is the checked in ide-probe.c,
-			 * this is only an assignment.
-			 */
-#endif
-			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
-			OUT_WORD(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, IN_WORD(hwif->config_data) & ~1);
-		}
-	}
-#endif
-}
diff -Nru a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
--- a/drivers/ide/umc8672.c	Sun Sep 15 19:19:29 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/*
- *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- *  This file provides support for the advanced features
- *  of the UMC 8672 IDE interface.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	now configs/compiles separate from ide.c  -ml
- *  Version 0.03	enhanced auto-tune, fix display bug
- *  Version 0.05	replace sti() with restore_flags()  -ml
- *			add detection of possible race condition  -ml
- */
-
-/*
- * VLB Controller Support from 
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the 
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO		/* some systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0      1              /* DOS measured drive speeds */
-#define UMC_DRIVE1      1              /* 0 to 11 allowed */
-#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
-#define UMC_DRIVE3      1              /* In case of crash reduce speed */
-
-static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const byte pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
-
-/*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const byte speedtab [3][12] = {
-	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
-
-static void out_umc (char port,char wert)
-{
-	outb_p(port,0x108);
-	outb_p(wert,0x109);
-}
-
-static inline byte in_umc (char port)
-{
-	outb_p(port,0x108);
-	return inb_p(0x109);
-}
-
-static void umc_set_speeds (byte speeds[])
-{
-	int i, tmp;
-
-	outb_p(0x5A,0x108); /* enable umc */
-
-	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
-	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
-	tmp = 0;
-	for (i = 3; i >= 0; i--) {
-		tmp = (tmp << 2) | speedtab[1][speeds[i]];
-	}
-	out_umc (0xdc,tmp);
-	for (i = 0;i < 4; i++) {
-		out_umc (0xd0+i,speedtab[2][speeds[i]]);
-		out_umc (0xd8+i,speedtab[2][speeds[i]]);
-	}
-	outb_p(0xa5,0x108); /* disable umc */
-
-	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
-		speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void tune_umc (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
-		drive->name, pio, pio_to_umc[pio]);
-	spin_lock_irqsave(&ide_lock, flags);
-	if (hwgroup && hwgroup->handler != NULL) {
-		printk("umc8672: other interface is busy: exiting tune_umc()\n");
-	} else {
-		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-		umc_set_speeds (current_speeds);
-	}
-	spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-void __init init_umc8672 (void)	/* called from ide.c */
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	if (check_region(0x108, 2)) {
-		local_irq_restore(flags);
-		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
-		return;
-	}
-	outb_p(0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0) {
-		local_irq_restore(flags);
-		printk ("umc8672: not found\n");
-		return;  
-	}
-	outb_p(0xa5,0x108); /* disable umc */
-
-	umc_set_speeds (current_speeds);
-	local_irq_restore(flags);
-
-	request_region(0x108, 2, "umc8672");
-	ide_hwifs[0].chipset = ide_umc8672;
-	ide_hwifs[1].chipset = ide_umc8672;
-	ide_hwifs[0].tuneproc = &tune_umc;
-	ide_hwifs[1].tuneproc = &tune_umc;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Sun Sep 15 19:19:28 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,565 +0,0 @@
-/*
- * $Id: via82cxxx.c,v 3.34 2002/02/12 11:26:11 vojtech Exp $
- *
- *  Copyright (c) 2000-2001 Vojtech Pavlik
- *
- *  Based on the work of:
- *	Michel Aubry
- *	Jeff Garzik
- *	Andre Hedrick
- */
-
-/*
- * VIA IDE driver for Linux. Supports
- *
- *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a
- *
- * southbridges, which can be found in
- *
- *  VIA Apollo Master, VP, VP2, VP2/97, VP3, VPX, VPX/97, MVP3, MVP4, P6, Pro,
- *    ProII, ProPlus, Pro133, Pro133+, Pro133A, Pro133A Dual, Pro133T, Pro133Z,
- *    PLE133, PLE133T, Pro266, Pro266T, ProP4X266, PM601, PM133, PN133, PL133T,
- *    PX266, PM266, KX133, KT133, KT133A, KT133E, KLE133, KT266, KX266, KM133,
- *    KM133A, KL133, KN133, KM266
- *  PC-Chips VXPro, VXPro+, VXTwo, TXPro-III, TXPro-AGP, AGPPro, ViaGra, BXToo,
- *    BXTel, BXpert
- *  AMD 640, 640 AGP, 750 IronGate, 760, 760MP
- *  ETEQ 6618, 6628, 6629, 6638
- *  Micron Samurai
- *
- * chipsets. Supports
- *
- *   PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-6
- *
- * (this includes UDMA33, 66, 100 and 133) modes. UDMA66 and higher modes are
- * autoenabled only in case the BIOS has detected a 80 wire cable. To ignore
- * the BIOS data and assume the cable is present, use 'ide0=ata66' or
- * 'ide1=ata66' on the kernel command line.
- */
-
-/*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-
-#include "ide-timing.h"
-
-#define VIA_IDE_ENABLE		0x40
-#define VIA_IDE_CONFIG		0x41
-#define VIA_FIFO_CONFIG		0x43
-#define VIA_MISC_1		0x44
-#define VIA_MISC_2		0x45
-#define VIA_MISC_3		0x46
-#define VIA_DRIVE_TIMING	0x48
-#define VIA_8BIT_TIMING		0x4e
-#define VIA_ADDRESS_SETUP	0x4c
-#define VIA_UDMA_TIMING		0x50
-
-#define VIA_UDMA		0x007
-#define VIA_UDMA_NONE		0x000
-#define VIA_UDMA_33		0x001
-#define VIA_UDMA_66		0x002
-#define VIA_UDMA_100		0x003
-#define VIA_UDMA_133		0x004
-#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
-#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
-	char *name;
-	unsigned short id;
-	unsigned char rev_min;
-	unsigned char rev_max;
-	unsigned short flags;
-} via_isa_bridges[] = {
-#ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
-#endif
-	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-	{ NULL }
-};
-
-static struct via_isa_bridge *via_config;
-static unsigned char via_enabled;
-static unsigned int via_80w;
-static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
-
-/*
- * VIA /proc entry.
- */
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-int via_proc, via_base;
-static struct pci_dev *bmide_dev, *isa_dev;
-extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static char *via_control3[] = { "No limit", "64", "128", "192" };
-
-#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
-#define via_print_drive(name, format, arg...)\
-	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
-
-static int via_get_info(char *buffer, char **addr, off_t offset, int count)
-{
-	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
-		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
-	struct pci_dev *dev = bmide_dev;
-	unsigned int v, u, i;
-	unsigned short c, w;
-	unsigned char t, x;
-	char *p = buffer;
-
-	via_print("----------VIA BusMastering IDE Configuration----------------");
-
-	via_print("Driver Version:                     3.34");
-	via_print("South Bridge:                       VIA %s", via_config->name);
-
-	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
-	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
-	via_print("Revision:                           ISA %#x IDE %#x", t, x);
-	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
-
-	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
-
-	pci_read_config_byte(dev, VIA_MISC_1, &t);
-	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
-	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
-	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_MISC_3, &t);
-	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
-
-	via_print("-----------------------Primary IDE-------Secondary IDE------");
-	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
-	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
-	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
-	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
-	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
-
-	c = IN_BYTE(via_base + 0x02) | (IN_BYTE(via_base + 0x0a) << 8);
-	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
-
-	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
-
-	via_print("-------------------drive0----drive1----drive2----drive3-----");
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
-	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
-
-	if (via_config->flags & VIA_UDMA)
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-	else u = 0;
-
-	for (i = 0; i < 4; i++) {
-
-		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
-		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
-		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
-		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
-		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
-		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
-		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
-		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
-		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
-
-		speed[i] = 2 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
-
-		if (!uen[i] || !den[i])
-			continue;
-
-		switch (via_config->flags & VIA_UDMA) {
-
-			case VIA_UDMA_33:
-				speed[i] = 2 * via_clock / udma[i];
-				cycle[i] = 1000000 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_66:
-				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
-				break;
-
-			case VIA_UDMA_100:
-				speed[i] = 6 * via_clock / udma[i];
-				cycle[i] = 333333 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_133:
-				speed[i] = 8 * via_clock / udma[i];
-				cycle[i] = 250000 * udma[i] / via_clock;
-				break;
-		}
-	}
-
-	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
-
-	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
-	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
-	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
-	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
-	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
-	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
-
-	return p - buffer;	/* hoping it is less than 4K... */
-}
-
-#endif
-
-/*
- * via_set_speed() writes timing values to the chipset registers
- */
-
-static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
-{
-	unsigned char t;
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
-
-	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
-		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
-
-	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
-		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
-		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		default: return;
-	}
-
-	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
-}
-
-/*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
-
-static int via_set_drive(ide_drive_t *drive, unsigned char speed)
-{
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
-	struct ide_timing t, p;
-	unsigned int T, UT;
-
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
-
-	T = 1000000000 / via_clock;
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:   UT = T;   break;
-		case VIA_UDMA_66:   UT = T/2; break;
-		case VIA_UDMA_100:  UT = T/3; break;
-		case VIA_UDMA_133:  UT = T/4; break;
-		default: UT = T;
-	}
-
-	ide_timing_compute(drive, speed, &t, T, UT);
-
-	if (peer->present) {
-		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-	}
-
-	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-/*
- * via82cxxx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
- */
-
-static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
-{
-	if (!((via_enabled >> HWIF(drive)->channel) & 1))
-		return;
-
-	if (pio == 255) {
-		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
-	}
-
-	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-
-/*
- * via82cxxx_dmaproc() is a callback from upper layers that can do
- * a lot, but we use it for DMA/PIO tuning only, delegating everything
- * else to the default ide_dmaproc().
- */
-
-int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-
-	if (func == ide_dma_check) {
-
-		short w80 = HWIF(drive)->udma_four;
-
-		short speed = ide_find_best_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
-
-		via_set_drive(drive, speed);
-
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
-			? ide_dma_on : ide_dma_off_quietly;
-	}
-
-	return ide_dmaproc(func, drive);
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *isa = NULL;
-	unsigned char t, v;
-	unsigned int u;
-	int i;
-
-/*
- * Find the ISA bridge to see how good the IDE is.
- */
-
-	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
-			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
-
-			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-			if (t >= via_config->rev_min && t <= via_config->rev_max)
-				break;
-		}
-
-	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
-		return -ENODEV;
-	}
-
-/*
- * Check 80-wire cable presence and setup Clk66.
- */
-
-	switch (via_config->flags & VIA_UDMA) {
-
-		case VIA_UDMA_66:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
-			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
-					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
-			break;
-
-		case VIA_UDMA_100:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-		case VIA_UDMA_133:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-	}
-
-	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a and 686 */
-		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
-	}
-
-/*
- * Check whether interfaces are enabled.
- */
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
-
-/*
- * Set up FIFO sizes and thresholds.
- */
-
-	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
-	if (via_config->flags & VIA_BAD_PREQ)				/* Disable PREQ# till DDACK# */
-		t &= 0x7f;						/* Would crash on 586b rev 41 */
-
-	if (via_config->flags & VIA_SET_FIFO) {				/* Fix FIFO split between channels */
-		t &= (t & 0x9f);
-		switch (via_enabled) {
-			case 1: t |= 0x00; break;			/* 16 on primary */
-			case 2: t |= 0x60; break;			/* 16 on secondary */
-			case 3: t |= 0x20; break;			/* 8 pri 8 sec */
-		}
-	}
-
-	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
-/*
- * Determine system bus clock.
- */
-
-	via_clock = system_bus_clock() * 1000;
-
-	switch (via_clock) {
-		case 33000: via_clock = 33333; break;
-		case 37000: via_clock = 37500; break;
-		case 41000: via_clock = 41666; break;
-	}
-
-	if (via_clock < 20000 || via_clock > 50000) {
-		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
-		via_clock = 33333;
-	}
-
-/*
- * Print the boot message.
- */
-
-	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
-		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
-
-/*
- * Setup /proc/ide/via entry.
- */
-
-#ifdef CONFIG_PROC_FS
-	if (!via_proc) {
-		via_base = pci_resource_start(dev, 4);
-		bmide_dev = dev;
-		isa_dev = isa;
-		via_display_info = &via_get_info;
-		via_proc = 1;
-	}
-#endif
-
-	return 0;
-}
-
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
-{
-	return ((via_enabled & via_80w) >> hwif->channel) & 1;
-}
-
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
-{
-	int i;
-
-	hwif->tuneproc = &via82cxxx_tune_drive;
-	hwif->speedproc = &via_set_drive;
-	hwif->autodma = 0;
-
-	for (i = 0; i < 2; i++) {
-		hwif->drives[i].io_32bit = 1;
-		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &via82cxxx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((via_enabled >> hwif->channel) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
-}
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/ieee1394/sbp2.c	Sun Sep 15 19:19:29 2002
@@ -326,7 +326,6 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/scatterlist.h>
 
 #ifdef CONFIG_KBUILD_2_5
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Sun Sep 15 19:19:50 2002
+++ b/drivers/input/input.c	Sun Sep 15 19:19:50 2002
@@ -605,7 +605,7 @@
 
 		len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
 		len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
-		len += sprintf(buf + len, "D: Drivers=");
+		len += sprintf(buf + len, "H: Handlers=");
 
 		list_for_each(hnode,&dev->h_list) {
 			struct input_handle * handle = to_handle(hnode);
diff -Nru a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
--- a/drivers/input/misc/pcspkr.c	Sun Sep 15 19:19:52 2002
+++ b/drivers/input/misc/pcspkr.c	Sun Sep 15 19:19:52 2002
@@ -22,8 +22,8 @@
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
 
-static char *pcspkr_name = "PC Speaker";
-static char *pcspkr_phys = "isa0061/input0";
+static char pcspkr_name[] = "PC Speaker";
+static char pcspkr_phys[] = "isa0061/input0";
 static struct input_dev pcspkr_dev;
 
 spinlock_t i8253_beep_lock = SPIN_LOCK_UNLOCKED;
diff -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
--- a/drivers/input/serio/i8042-io.h	Sun Sep 15 19:19:28 2002
+++ b/drivers/input/serio/i8042-io.h	Sun Sep 15 19:19:28 2002
@@ -62,7 +62,7 @@
  * On ix86 platforms touching the i8042 data register region can do really
  * bad things. Because of this the region is always reserved on ix86 boxes.
  */
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
 	if (!request_region(I8042_DATA_REG, 16, "i8042"))
 		return 0;
 #endif
@@ -71,7 +71,7 @@
 
 static inline void i8042_platform_exit(void)
 {
-#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
 	release_region(I8042_DATA_REG, 16);
 #endif
 }
diff -Nru a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
--- a/drivers/input/serio/q40kbd.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/input/serio/q40kbd.c	Sun Sep 15 19:19:29 2002
@@ -47,12 +47,24 @@
 MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 
+
+static int q40kbd_open(struct serio *port)
+{
+	return 0;
+}
+static void q40kbd_close(struct serio *port)
+{
+	return 0;
+}
+
 static struct serio q40kbd_port =
 {
 	.type	= SERIO_8042,
+	.name	= "Q40 kbd port",
+	.phys	= "Q40",
 	.write	= NULL,
-	.name	= "Q40 PS/2 kbd port",
-	.phys	= "isa0060/serio0",
+	.open	= q40kbd_open,
+	.close	= q40kbd_close,
 };
 
 static void q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -70,13 +82,10 @@
 {
 	int maxread = 100;
 
-	/* Get the keyboard controller registers (incomplete decode) */
-	request_region(0x60, 16, "q40kbd");
-
 	/* allocate the IRQ */
 	request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL);
 
-	/* flush any pending input. */
+	/* flush any pending input */
 	while (maxread-- && (IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
 		master_inb(KEYCODE_REG);
 	
@@ -84,15 +93,17 @@
 	master_outb(-1,KEYBOARD_UNLOCK_REG);
 	master_outb(1,KEY_IRQ_ENABLE_REG);
 
-	register_serio_port(&q40kbd_port);
-	printk(KERN_INFO "serio: Q40 PS/2 kbd port irq %d\n", Q40_IRQ_KEYBOARD);
+	serio_register_port(&q40kbd_port);
+	printk(KERN_INFO "serio: Q40 kbd registered\n");
 }
 
 void __exit q40kbd_exit(void)
 {
-	unregister_serio_port(&q40kbd_port);
+	master_outb(0,KEY_IRQ_ENABLE_REG);
+	master_outb(-1,KEYBOARD_UNLOCK_REG);
+
+	serio_unregister_port(&q40kbd_port);
 	free_irq(Q40_IRQ_KEYBOARD, NULL);
-	release_region(0x60, 16);	
 }
 
 module_init(q40kbd_init);
diff -Nru a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
--- a/drivers/input/serio/serport.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/input/serio/serport.c	Sun Sep 15 19:19:30 2002
@@ -1,32 +1,16 @@
 /*
- * $Id: serport_old.c,v 1.10 2002/01/24 19:52:57 vojtech Exp $
+ * Input device TTY line discipline
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
  *
- *  Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
  * This is a module that converts a tty line into a much simpler
  * 'serial io port' abstraction that the input device drivers use.
  */
 
 /*
- * 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.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * 
- *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
  */
 
 #include <asm/uaccess.h>
@@ -41,10 +25,13 @@
 MODULE_DESCRIPTION("Input device TTY line discipline");
 MODULE_LICENSE("GPL");
 
+#define SERPORT_BUSY	1
+
 struct serport {
 	struct tty_struct *tty;
 	wait_queue_head_t wait;
 	struct serio serio;
+	unsigned long flags;
 	char phys[32];
 };
 
@@ -68,20 +55,20 @@
 static void serport_serio_close(struct serio *serio)
 {
 	struct serport *serport = serio->driver;
+
+	serport->serio.type = 0;
 	wake_up_interruptible(&serport->wait);
 }
 
 /*
  * serport_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty. It looks for the Mag, and if found, registers
- * it as a joystick device.
+ * discipline on a tty. It prepares the serio struct.
  */
 
 static int serport_ldisc_open(struct tty_struct *tty)
 {
 	struct serport *serport;
-	char ttyname[64];
-	int i;
+	char name[64];
 
 	MOD_INC_USE_COUNT;
 
@@ -96,11 +83,7 @@
 	serport->tty = tty;
 	tty->disc_data = serport;
 
-	strcpy(ttyname, tty->driver.name);
-	for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++);
-	ttyname[i] = 0;
-
-	sprintf(serport->phys, "%s%d/serio0", ttyname, minor(tty->device) - tty->driver.minor_start);
+	snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name));
 
 	serport->serio.name = serport_name;
 	serport->serio.phys = serport->phys;
@@ -161,29 +144,18 @@
 static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
-	DECLARE_WAITQUEUE(wait, current);
-	char name[32];
+	char name[64];
 
-#ifdef CONFIG_DEVFS_FS
-	sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#else
-	sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#endif
+	if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
+		return -EBUSY;
 
 	serio_register_port(&serport->serio);
-
-	printk(KERN_INFO "serio: Serial port %s\n", name);
-
-	add_wait_queue(&serport->wait, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
-
-	while(serport->serio.type && !signal_pending(current)) schedule();
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&serport->wait, &wait);
-
+	printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
+	wait_event_interruptible(serport->wait, !serport->serio.type);
 	serio_unregister_port(&serport->serio);
 
+	clear_bit(SERPORT_BUSY, &serport->flags);
+
 	return 0;
 }
 
@@ -195,10 +167,8 @@
 {
 	struct serport *serport = (struct serport*) tty->disc_data;
 	
-	switch (cmd) {
-		case SPIOCSTYPE:
-			return get_user(serport->serio.type, (unsigned long *) arg);
-	}
+	if (cmd == SPIOCSTYPE)
+		return get_user(serport->serio.type, (unsigned long *) arg);
 
 	return -EINVAL;
 }
@@ -208,7 +178,6 @@
 	struct serport *sp = (struct serport *) tty->disc_data;
 
 	serio_dev_write_wakeup(&sp->serio);
-
 }
 
 /*
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/md/md.c	Sun Sep 15 19:19:29 2002
@@ -56,11 +56,8 @@
 #include <linux/blk.h>
 
 #define DEBUG 0
-#if DEBUG
-# define dprintk(x...) printk(x)
-#else
-# define dprintk(x...) do { } while(0)
-#endif
+#define dprintk(x...) ((void)(DEBUG && printk(x)))
+
 
 #ifndef MODULE
 static void autostart_arrays (void);
@@ -604,18 +601,6 @@
 	mddev->raid_disks = 0;
 }
 
-static void free_mddev(mddev_t *mddev)
-{
-	if (!mddev) {
-		MD_BUG();
-		return;
-	}
-
-	export_array(mddev);
-	md_size[mdidx(mddev)] = 0;
-	set_capacity(disks[mdidx(mddev)], 0);
-}
-
 #undef BAD_CSUM
 #undef BAD_MAGIC
 #undef OUT_OF_MEM
@@ -1533,7 +1518,6 @@
 {
 	int err = 0;
 	kdev_t dev = mddev_to_kdev(mddev);
-	struct gendisk *disk;
 
 	if (atomic_read(&mddev->active)>1) {
 		printk(STILL_IN_USE, mdidx(mddev));
@@ -1582,21 +1566,25 @@
 		if (ro)
 			set_device_ro(dev, 1);
 	}
-	disk = disks[mdidx(mddev)];
-	disks[mdidx(mddev)] = NULL;
-
-	if (disk) {
-		del_gendisk(disk);
-		kfree(disk->major_name);
-		kfree(disk);
-	}
-
 	/*
 	 * Free resources if final stop
 	 */
 	if (!ro) {
+		struct gendisk *disk;
 		printk(KERN_INFO "md: md%d stopped.\n", mdidx(mddev));
-		free_mddev(mddev);
+
+		export_array(mddev);
+
+		md_size[mdidx(mddev)] = 0;
+		disk = disks[mdidx(mddev)];
+		disks[mdidx(mddev)] = NULL;
+
+		if (disk) {
+			del_gendisk(disk);
+			kfree(disk->major_name);
+			kfree(disk);
+		}
+
 	} else
 		printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev));
 	err = 0;
@@ -2593,7 +2581,7 @@
 void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
 	dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
-		MD_MAJOR,mdidx(mddev),MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev),
+		MD_MAJOR,mdidx(mddev),MAJOR(rdev->bdev->bd_dev),MINOR(rdev->bdev->bd_dev),
 		__builtin_return_address(0),__builtin_return_address(1),
 		__builtin_return_address(2),__builtin_return_address(3));
 
@@ -3149,11 +3137,11 @@
 {
 	mddev_t *mddev = mddev_find(minor(dev));
 	request_queue_t *q = BLK_DEFAULT_QUEUE(MAJOR_NR);
-	if (!mddev || atomic_read(&mddev->active)<2)
-		BUG();
-	if (mddev->pers)
-		q = &mddev->queue;
-	mddev_put(mddev); /* the caller must hold a reference... */
+	if (mddev) {
+		if (mddev->pers)
+			q = &mddev->queue;
+		mddev_put(mddev);
+	}
 	return q;
 }
 
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/md/multipath.c	Sun Sep 15 19:19:37 2002
@@ -37,20 +37,6 @@
 #define	NR_RESERVED_BUFS	32
 
 
-/*
- * The following can be used to debug the driver
- */
-#define MULTIPATH_DEBUG	0
-
-#if MULTIPATH_DEBUG
-#define PRINTK(x...)   printk(x)
-#define inline
-#define __inline__
-#else
-#define PRINTK(x...)  do { } while (0)
-#endif
-
-
 static mdk_personality_t multipath_personality;
 static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
 struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail;
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/md/raid5.c	Sun Sep 15 19:19:29 2002
@@ -49,12 +49,10 @@
 # define CHECK_DEVLOCK()
 #endif
 
+#define PRINTK(x...) ((void)(RAID5_DEBUG && printk(x)))
 #if RAID5_DEBUG
-#define PRINTK(x...) printk(x)
 #define inline
 #define __inline__
-#else
-#define PRINTK(x...) do { } while (0)
 #endif
 
 static void print_raid5_conf (raid5_conf_t *conf);
@@ -933,13 +931,16 @@
 		test_bit(R5_UPTODATE, &dev->flags))
 	       || (failed == 1 && failed_num == sh->pd_idx))
 	    ) {
-	    /* any written block on an uptodate or failed drive can be returned */
+	    /* any written block on an uptodate or failed drive can be returned.
+	     * Note that if we 'wrote' to a failed drive, it will be UPTODATE, but 
+	     * never LOCKED, so we don't need to test 'failed' directly.
+	     */
 	    for (i=disks; i--; )
 		if (sh->dev[i].written) {
 		    dev = &sh->dev[i];
-		    if (!test_bit(R5_Insync, &sh->dev[sh->pd_idx].flags) &&
-			(!test_bit(R5_LOCKED, &dev->flags) && test_bit(R5_UPTODATE, &dev->flags)) ) {
-			/* maybe we can return some write requests */
+		    if (!test_bit(R5_LOCKED, &dev->flags) &&
+			 test_bit(R5_UPTODATE, &dev->flags) ) {
+			/* We can return any write requests */
 			    struct bio *wbi, *wbi2;
 			    PRINTK("Return write for disc %d\n", i);
 			    wbi = dev->written;
@@ -1164,7 +1165,7 @@
 					md_sync_acct(rdev, STRIPE_SECTORS);
 
 				bi->bi_bdev = rdev->bdev;
-				PRINTK("for %ld schedule op %d on disc %d\n", sh->sector, bi->bi_rw, i);
+				PRINTK("for %ld schedule op %ld on disc %d\n", sh->sector, bi->bi_rw, i);
 				atomic_inc(&sh->count);
 				bi->bi_sector = sh->sector;
 				bi->bi_flags = 0;
@@ -1175,7 +1176,7 @@
 				bi->bi_next = NULL;
 				generic_make_request(bi);
 			} else {
-				PRINTK("skip op %d on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector);
+				PRINTK("skip op %ld on disc %d for sector %ld\n", bi->bi_rw, i, sh->sector);
 				clear_bit(R5_LOCKED, &dev->flags);
 				set_bit(STRIPE_HANDLE, &sh->state);
 			}
@@ -1242,8 +1243,8 @@
 		new_sector = raid5_compute_sector(logical_sector,
 						  raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 
-		PRINTK("raid5: make_request, sector %ul logical %ul\n", 
-		       new_sector, logical_sector);
+		PRINTK("raid5: make_request, sector %Lu logical %Lu\n", 
+		       (unsigned long long)new_sector, (unsigned long long)logical_sector);
 
 		sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK));
 		if (sh) {
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/net/3c505.c	Sun Sep 15 19:20:24 2002
@@ -1396,7 +1396,7 @@
 	int timeout;
 	int addr = dev->base_addr;
 	const char *name = dev->name;
-	long flags;
+       unsigned long flags;
 	byte orig_HSR;
 
 	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
diff -Nru a/drivers/net/apne.c b/drivers/net/apne.c
--- a/drivers/net/apne.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/net/apne.c	Sun Sep 15 19:20:24 2002
@@ -288,6 +288,7 @@
     /* Allocate dev->priv and fill in 8390 specific dev fields. */
     if (ethdev_init(dev)) {
 	printk (" unable to get memory for dev->priv.\n");
+	free_irq(IRQ_AMIGA_PORTS, dev);
 	return -ENOMEM;
     }
 
diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
--- a/drivers/net/arcnet/arcnet.c	Sun Sep 15 19:20:00 2002
+++ b/drivers/net/arcnet/arcnet.c	Sun Sep 15 19:20:00 2002
@@ -186,7 +186,7 @@
 void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
 {
 	int i;
-	long flags;
+       unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -212,7 +212,7 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	int i, length;
-	long flags;
+       unsigned long flags;
 	static uint8_t buf[512];
 
 	save_flags(flags);
diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c
--- a/drivers/net/at1700.c	Sun Sep 15 19:19:34 2002
+++ b/drivers/net/at1700.c	Sun Sep 15 19:19:34 2002
@@ -310,7 +310,6 @@
 		&& inb(ioaddr + SAPROM + 2) == 0x0e)
 		is_fmv18x = 1;
 	else {
-		ret = -ENODEV;
 		goto err_out;
 	}
 			
@@ -335,11 +334,10 @@
 			}
 			if (i == 8) {
 				goto err_out;
-				ret = -ENODEV;
 			}
 		} else {
 			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				return -ENODEV;
+				goto err_out;
 			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
 		}
 	}
@@ -810,7 +808,7 @@
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
-	long flags;
+       unsigned long flags;
 	int i;
 
 	if (dev->flags & IFF_PROMISC) {
diff -Nru a/drivers/net/de600.c b/drivers/net/de600.c
--- a/drivers/net/de600.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/net/de600.c	Sun Sep 15 19:19:37 2002
@@ -717,7 +717,7 @@
 adapter_init(struct net_device *dev)
 {
 	int	i;
-	long flags;
+       unsigned long flags;
 
 	save_flags(flags);
 	cli();
diff -Nru a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
--- a/drivers/net/hamradio/scc.c	Sun Sep 15 19:20:20 2002
+++ b/drivers/net/hamradio/scc.c	Sun Sep 15 19:20:20 2002
@@ -2129,7 +2129,7 @@
 
 static void __exit scc_cleanup_driver(void)
 {
-	long flags;
+       unsigned long flags;
 	io_port ctrl;
 	int k;
 	struct scc_channel *scc;
diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c
--- a/drivers/net/ni65.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/net/ni65.c	Sun Sep 15 19:19:29 2002
@@ -1108,7 +1108,7 @@
 	{
 		short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		struct tmd *tmdp;
-		long flags;
+               unsigned long flags;
 
 #ifdef XMT_VIA_SKB
 		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
--- a/drivers/net/pcmcia/3c574_cs.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/net/pcmcia/3c574_cs.c	Sun Sep 15 19:19:29 2002
@@ -1231,7 +1231,7 @@
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		{
 			int saved_window;
-			long flags;
+                       unsigned long flags;
 
 			save_flags(flags);
 			cli();
@@ -1245,7 +1245,7 @@
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		{
 			int saved_window;
-			long flags;
+                       unsigned long flags;
 
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
diff -Nru a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
--- a/drivers/net/pcmcia/aironet4500_cs.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/net/pcmcia/aironet4500_cs.c	Sun Sep 15 19:19:28 2002
@@ -347,7 +347,7 @@
 static void awc_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
-	long flags;
+       unsigned long flags;
 	int i=0;
 
 	DEBUG(0, "awc_detach(0x%p)\n", link);
diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
--- a/drivers/net/pcmcia/fmvj18x_cs.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/net/pcmcia/fmvj18x_cs.c	Sun Sep 15 19:19:29 2002
@@ -1254,7 +1254,7 @@
     ioaddr_t ioaddr = dev->base_addr;
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
     unsigned char mc_filter[8];		 /* Multicast hash filter */
-    long flags;
+    unsigned long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
--- a/drivers/net/pcmcia/smc91c92_cs.c	Sun Sep 15 19:20:00 2002
+++ b/drivers/net/pcmcia/smc91c92_cs.c	Sun Sep 15 19:20:00 2002
@@ -1778,7 +1778,7 @@
 {
     ioaddr_t ioaddr = dev->base_addr;
     u_int multicast_table[ 2 ] = { 0, };
-    long flags;
+    unsigned long flags;
     u_short rx_cfg_setting;
     
     if (dev->flags & IFF_PROMISC) {
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Sun Sep 15 19:19:50 2002
+++ b/drivers/net/tg3.c	Sun Sep 15 19:19:50 2002
@@ -48,12 +48,19 @@
 #define TG3_VLAN_TAG_USED 0
 #endif
 
+#ifdef NETIF_F_TSO
+/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
+#define TG3_DO_TSO	0
+#else
+#define TG3_DO_TSO	0
+#endif
+
 #include "tg3.h"
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.0"
-#define DRV_MODULE_RELDATE	"Jul 19, 2002"
+#define DRV_MODULE_VERSION	"1.1"
+#define DRV_MODULE_RELDATE	"Aug 30, 2002"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -142,6 +149,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
@@ -212,6 +221,7 @@
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
 static void tg3_enable_ints(struct tg3 *tp)
@@ -220,9 +230,11 @@
 	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
 
-	if (tp->hw_status->status & SD_STATUS_UPDATED)
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
 		tw32(GRC_LOCAL_CTRL,
 		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	}
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
 #define PHY_BUSY_LOOPS	5000
@@ -235,6 +247,7 @@
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE,
 		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -247,9 +260,11 @@
 	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
 	
 	tw32(MAC_MI_COM, frame_val);
+	tr32(MAC_MI_COM);
 
 	loops = PHY_BUSY_LOOPS;
 	while (loops-- > 0) {
+		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 
 		if ((frame_val & MI_COM_BUSY) == 0) {
@@ -257,7 +272,6 @@
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
-		udelay(10);
 	}
 
 	ret = -EBUSY;
@@ -268,6 +282,7 @@
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -282,6 +297,7 @@
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE,
 		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -293,16 +309,17 @@
 	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
 	
 	tw32(MAC_MI_COM, frame_val);
+	tr32(MAC_MI_COM);
 
 	loops = PHY_BUSY_LOOPS;
 	while (loops-- > 0) {
+		udelay(10);
 		frame_val = tr32(MAC_MI_COM);
 		if ((frame_val & MI_COM_BUSY) == 0) {
 			udelay(5);
 			frame_val = tr32(MAC_MI_COM);
 			break;
 		}
-		udelay(10);
 	}
 
 	ret = -EBUSY;
@@ -311,6 +328,7 @@
 
 	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
@@ -388,7 +406,9 @@
 				      pm + PCI_PM_CTRL,
 				      power_control);
 		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+		tr32(GRC_LOCAL_CTRL);
+		udelay(100);
+
 		return 0;
 
 	case 1:
@@ -424,6 +444,7 @@
 	}
 
 	tp->link_config.speed = SPEED_10;
+	tp->link_config.duplex = DUPLEX_HALF;
 	tp->link_config.autoneg = AUTONEG_ENABLE;
 	tg3_setup_phy(tp);
 
@@ -435,51 +456,108 @@
 		u32 mac_mode;
 
 		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+		udelay(40);
+
+		mac_mode = MAC_MODE_PORT_MODE_MII;
 
-		mac_mode = MAC_MODE_PORT_MODE_MII |
-			MAC_MODE_LINK_POLARITY;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
+		    !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
+			mac_mode |= MAC_MODE_LINK_POLARITY;
 
 		if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
 		     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)))
 			mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
 
 		tw32(MAC_MODE, mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
+
 		tw32(MAC_RX_MODE, RX_MODE_ENABLE);
+		tr32(MAC_RX_MODE);
+		udelay(10);
 	}
 
 	if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) {
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK));
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_44MHZ_CORE));
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK |
-		      CLOCK_CTRL_44MHZ_CORE));
+		u32 base_val;
+
+		base_val = 0;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
+				     CLOCK_CTRL_TXCLK_DISABLE);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK |
+		     CLOCK_CTRL_44MHZ_CORE);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_44MHZ_CORE);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
 	} else {
-		tw32(TG3PCI_CLOCK_CTRL,
-		     (CLOCK_CTRL_RXCLK_DISABLE |
-		      CLOCK_CTRL_TXCLK_DISABLE |
-		      CLOCK_CTRL_ALTCLK |
-		      CLOCK_CTRL_PWRDOWN_PLL133));
-	}
+		u32 base_val;
 
-	udelay(40);
+		base_val = 0;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+			base_val |= (CLOCK_CTRL_RXCLK_DISABLE |
+				     CLOCK_CTRL_TXCLK_DISABLE);
+
+		tw32(TG3PCI_CLOCK_CTRL, base_val |
+		     CLOCK_CTRL_ALTCLK |
+		     CLOCK_CTRL_PWRDOWN_PLL133);
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+	}
 
-	if ((power_caps & PCI_PM_CAP_PME_D3cold) &&
+	if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) &&
 	    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
-		/* Move to auxilliary power. */
-		tw32(GRC_LOCAL_CTRL,
-		     (GRC_LCLCTRL_GPIO_OE0 |
-		      GRC_LCLCTRL_GPIO_OE1 |
-		      GRC_LCLCTRL_GPIO_OE2 |
-		      GRC_LCLCTRL_GPIO_OUTPUT0 |
-		      GRC_LCLCTRL_GPIO_OUTPUT1));
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		} else {
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1 |
+			      GRC_LCLCTRL_GPIO_OUTPUT2));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+
+			tw32(GRC_LOCAL_CTRL,
+			     (GRC_LCLCTRL_GPIO_OE0 |
+			      GRC_LCLCTRL_GPIO_OE1 |
+			      GRC_LCLCTRL_GPIO_OE2 |
+			      GRC_LCLCTRL_GPIO_OUTPUT0 |
+			      GRC_LCLCTRL_GPIO_OUTPUT1));
+			tr32(GRC_LOCAL_CTRL);
+			udelay(100);
+		}
 	}
 
 	/* Finally, set the new power state. */
@@ -636,8 +714,9 @@
 				new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
 			if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
 				new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
-			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+			if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			    (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+			     tp->pci_chip_rev_id == CHIPREV_ID_5701_B0))
 				new_adv |= (MII_TG3_CTRL_AS_MASTER |
 					    MII_TG3_CTRL_ENABLE_AS_MASTER);
 			tg3_writephy(tp, MII_TG3_CTRL, new_adv);
@@ -787,11 +866,16 @@
 	tw32(MAC_STATUS,
 	     (MAC_STATUS_SYNC_CHANGED |
 	      MAC_STATUS_CFG_CHANGED));
+	tr32(MAC_STATUS);
+	udelay(40);
 
 	tp->mi_mode = MAC_MI_MODE_BASE;
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
 	udelay(40);
 
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+
 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -968,10 +1052,13 @@
 	    tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
 		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
 		tw32(MAC_MI_MODE, tp->mi_mode);
+		tr32(MAC_MI_MODE);
 		udelay(40);
 	}
 
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	if (tp->tg3_flags &
 	    (TG3_FLAG_USE_LINKCHG_REG |
@@ -981,6 +1068,8 @@
 	} else {
 		tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
 	}
+	tr32(MAC_EVENT);
+	udelay(40);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
 	    current_link_up == 1 &&
@@ -991,6 +1080,8 @@
 		tw32(MAC_STATUS,
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED));
+		tr32(MAC_STATUS);
+		udelay(40);
 		tg3_write_mem(tp,
 			      NIC_SRAM_FIRMWARE_MBOX,
 			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
@@ -1152,6 +1243,9 @@
 		tw32(MAC_TX_AUTO_NEG, 0);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
+
 		ret = ANEG_TIMER_ENAB;
 		ap->state = ANEG_STATE_RESTART;
 
@@ -1175,6 +1269,8 @@
 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_ABILITY_DETECT;
 		break;
@@ -1190,6 +1286,8 @@
 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_ACK_DETECT;
 
@@ -1275,6 +1373,8 @@
 		ap->link_time = ap->cur_time;
 		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
 		tw32(MAC_MODE, tp->mac_mode);
+		tr32(MAC_MODE);
+		udelay(40);
 
 		ap->state = ANEG_STATE_IDLE_DETECT;
 		ret = ANEG_TIMER_ENAB;
@@ -1331,6 +1431,7 @@
 	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
 	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
 	udelay(40);
 
 	/* Reset when initting first time or we have a link. */
@@ -1381,6 +1482,8 @@
 		tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
 	else
 		tw32(MAC_EVENT, 0);
+	tr32(MAC_EVENT);
+	udelay(40);
 
 	current_link_up = 0;
 	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
@@ -1398,9 +1501,12 @@
 
 			tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
 			tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
-			udelay(20);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			aninfo.state = ANEG_STATE_UNKNOWN;
 			aninfo.cur_time = 0;
@@ -1416,6 +1522,8 @@
 
 			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
 			tw32(MAC_MODE, tp->mac_mode);
+			tr32(MAC_MODE);
+			udelay(40);
 
 			if (status == ANEG_DONE &&
 			    (aninfo.flags &
@@ -1441,8 +1549,8 @@
 				tw32(MAC_STATUS,
 				     (MAC_STATUS_SYNC_CHANGED |
 				      MAC_STATUS_CFG_CHANGED));
-
-				udelay(20);
+				tr32(MAC_STATUS);
+				udelay(40);
 				if ((tr32(MAC_STATUS) &
 				     (MAC_STATUS_SYNC_CHANGED |
 				      MAC_STATUS_CFG_CHANGED)) == 0)
@@ -1460,6 +1568,8 @@
 
 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	tp->hw_status->status =
 		(SD_STATUS_UPDATED |
@@ -1470,8 +1580,8 @@
 		tw32(MAC_STATUS,
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED));
-
-		udelay(20);
+		tr32(MAC_STATUS);
+		udelay(40);
 		if ((tr32(MAC_STATUS) &
 		     (MAC_STATUS_SYNC_CHANGED |
 		      MAC_STATUS_CFG_CHANGED)) == 0)
@@ -1507,9 +1617,12 @@
 
 	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
 		tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
+		tr32(MAC_MODE);
+		udelay(40);
 		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
-			udelay(1);
 			tw32(MAC_MODE, tp->mac_mode);
+			tr32(MAC_MODE);
+			udelay(40);
 		}
 	}
 
@@ -1551,7 +1664,7 @@
 	u32 sw_idx = tp->tx_cons;
 
 	while (sw_idx != hw_idx) {
-		struct ring_info *ri = &tp->tx_buffers[sw_idx];
+		struct tx_ring_info *ri = &tp->tx_buffers[sw_idx];
 		struct sk_buff *skb = ri->skb;
 		int i;
 
@@ -1881,23 +1994,31 @@
 	tp->rx_rcb_ptr = rx_rcb_ptr;
 	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
 		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE));
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
 
 	/* Refill RX ring(s). */
 	if (work_mask & RXD_OPAQUE_RING_STD) {
 		sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 	if (work_mask & RXD_OPAQUE_RING_JUMBO) {
 		sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 #if TG3_MINI_RING_WORKS
 	if (work_mask & RXD_OPAQUE_RING_MINI) {
 		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
 		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
 			     sw_idx);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
 #endif
 
@@ -1974,6 +2095,9 @@
 		return;
 
 	if (netif_rx_schedule_prep(dev)) {
+		/* NOTE: This write is posted by the readback of
+		 *       the mailbox register done by our caller.
+		 */
 		tw32(TG3PCI_MISC_HOST_CTRL,
 		     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
 		__netif_rx_schedule(dev);
@@ -1988,8 +2112,9 @@
 	struct net_device *dev = dev_id;
 	struct tg3 *tp = dev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
 
-	spin_lock(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 
 	if (sblk->status & SD_STATUS_UPDATED) {
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
@@ -2003,7 +2128,7 @@
 		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 	}
 
-	spin_unlock(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
 }
 
 static void tg3_init_rings(struct tg3 *);
@@ -2055,11 +2180,11 @@
 }
 #endif
 
-static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int);
+static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32);
 
 static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
 				       u32 guilty_entry, int guilty_len,
-				       u32 last_plus_one, u32 *start)
+				       u32 last_plus_one, u32 *start, u32 mss)
 {
 	dma_addr_t new_addr;
 	u32 entry = *start;
@@ -2112,7 +2237,7 @@
 				  PCI_DMA_TODEVICE);
 	tg3_set_txd(tp, entry, new_addr, new_skb->len,
 		    (skb->ip_summed == CHECKSUM_HW) ?
-		    TXD_FLAG_TCPUDP_CSUM : 0, 1);
+		    TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1));
 	*start = NEXT_TX(entry);
 
 	/* Now clean up the sw ring entries. */
@@ -2144,30 +2269,28 @@
 
 static void tg3_set_txd(struct tg3 *tp, int entry,
 			dma_addr_t mapping, int len, u32 flags,
-			int is_end)
+			u32 mss_and_is_end)
 {
-#if TG3_VLAN_TAG_USED
-	u16 vlan_tag = 0;
-#endif
+	int is_end = (mss_and_is_end & 0x1);
+	u32 mss = (mss_and_is_end >> 1);
+	u32 vlan_tag = 0;
 
 	if (is_end)
 		flags |= TXD_FLAG_END;
-#if TG3_VLAN_TAG_USED
 	if (flags & TXD_FLAG_VLAN) {
 		vlan_tag = flags >> 16;
 		flags &= 0xffff;
 	}
-#endif
+	vlan_tag |= (mss << TXD_MSS_SHIFT);
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
 
 		txd->addr_hi = ((u64) mapping >> 32);
 		txd->addr_lo = ((u64) mapping & 0xffffffff);
 		txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-#if TG3_VLAN_TAG_USED
 		txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
-#endif
 	} else {
+		struct tx_ring_info *txr = &tp->tx_buffers[entry];
 		unsigned long txd;
 
 		txd = (tp->regs +
@@ -2183,9 +2306,10 @@
 		writel(((u64) mapping & 0xffffffff),
 		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
 		writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS);
-#if TG3_VLAN_TAG_USED
-		writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
-#endif
+		if (txr->prev_vlan_tag != vlan_tag) {
+			writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
+			txr->prev_vlan_tag = vlan_tag;
+		}
 	}
 }
 
@@ -2203,7 +2327,7 @@
 	struct tg3 *tp = dev->priv;
 	dma_addr_t mapping;
 	unsigned int i;
-	u32 len, entry, base_flags;
+	u32 len, entry, base_flags, mss;
 	int would_hit_hwbug;
 
 	len = (skb->len - skb->data_len);
@@ -2227,6 +2351,13 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_DO_TSO != 0
+	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+			       TXD_FLAG_CPU_POST_DMA);
+#else
+	mss = 0;
+#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -2245,7 +2376,7 @@
 		would_hit_hwbug = entry + 1;
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
-		    (skb_shinfo(skb)->nr_frags == 0));
+		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
 
 	entry = NEXT_TX(entry);
 
@@ -2274,7 +2405,7 @@
 			}
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last));
+				    base_flags, (i == last) | (mss << 1));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2310,7 +2441,7 @@
 		if (tigon3_4gb_hwbug_workaround(tp, skb,
 						entry, len,
 						last_plus_one,
-						&start))
+						&start, mss))
 			goto out_unlock;
 
 		entry = start;
@@ -2323,12 +2454,27 @@
 		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
 			tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
 				      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDHOST_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	} else {
+		/* First, make sure tg3 sees last descriptor fully
+		 * in SRAM.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
+
 		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
 		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
 			tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 				      TG3_64BIT_REG_LOW), entry);
+
+		/* Now post the mailbox write itself.  */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	}
 
 	tp->tx_prod = entry;
@@ -2347,7 +2493,7 @@
 {
 	struct tg3 *tp = dev->priv;
 	dma_addr_t mapping;
-	u32 len, entry, base_flags;
+	u32 len, entry, base_flags, mss;
 
 	len = (skb->len - skb->data_len);
 
@@ -2370,6 +2516,13 @@
 	base_flags = 0;
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_DO_TSO != 0
+	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
+			       TXD_FLAG_CPU_POST_DMA);
+#else
+	mss = 0;
+#endif
 #if TG3_VLAN_TAG_USED
 	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
 		base_flags |= (TXD_FLAG_VLAN |
@@ -2383,7 +2536,7 @@
 	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
-		    (skb_shinfo(skb)->nr_frags == 0));
+		    (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
 
 	entry = NEXT_TX(entry);
 
@@ -2406,7 +2559,7 @@
 			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last));
+				    base_flags, (i == last) | (mss << 1));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2420,9 +2573,24 @@
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDHOST_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	} else {
+		/* First, make sure tg3 sees last descriptor fully
+		 * in SRAM.
+		 */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
+
 		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
 			      TG3_64BIT_REG_LOW), entry);
+
+		/* Now post the mailbox write itself.  */
+		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+			tr32(MAILBOX_SNDNIC_PROD_IDX_0 +
+			     TG3_64BIT_REG_LOW);
 	}
 
 	tp->tx_prod = entry;
@@ -2524,7 +2692,7 @@
 	}
 
 	for (i = 0; i < TG3_TX_RING_SIZE; ) {
-		struct ring_info *txp;
+		struct tx_ring_info *txp;
 		struct sk_buff *skb;
 		int j;
 
@@ -2591,6 +2759,8 @@
 			writel(0, start);
 			start += 4;
 		}
+		for (i = 0; i < TG3_TX_RING_SIZE; i++)
+			tp->tx_buffers[i].prev_vlan_tag = 0;
 	}
 
 	/* Initialize invariants of the rings, we only set this
@@ -2713,12 +2883,13 @@
  */
 static int tg3_alloc_consistent(struct tg3 *tp)
 {
-	tp->rx_std_buffers = kmalloc(sizeof(struct ring_info) *
-				     (TG3_RX_RING_SIZE +
+	tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
+				      (TG3_RX_RING_SIZE +
 #if TG3_MINI_RING_WORKS
-				      TG3_RX_MINI_RING_SIZE +
+				       TG3_RX_MINI_RING_SIZE +
 #endif
-				      TG3_RX_JUMBO_RING_SIZE +
+				       TG3_RX_JUMBO_RING_SIZE)) +
+				     (sizeof(struct tx_ring_info) *
 				      TG3_TX_RING_SIZE),
 				     GFP_KERNEL);
 	if (!tp->rx_std_buffers)
@@ -2729,14 +2900,16 @@
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
 		 TG3_RX_MINI_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE +
-		 TG3_TX_RING_SIZE)));
+		 TG3_RX_JUMBO_RING_SIZE)) +
+	       (sizeof(struct tx_ring_info) *
+		TG3_TX_RING_SIZE));
 #else
 	memset(tp->rx_std_buffers, 0,
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE +
-		 TG3_TX_RING_SIZE)));
+		 TG3_RX_JUMBO_RING_SIZE)) +
+	       (sizeof(struct tx_ring_info) *
+		TG3_TX_RING_SIZE));
 #endif
 
 #if TG3_MINI_RING_WORKS
@@ -2745,7 +2918,8 @@
 #else
 	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
 #endif
-	tp->tx_buffers = &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
+	tp->tx_buffers = (struct tx_ring_info *)
+		&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
 
 	tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES,
 					  &tp->rx_std_mapping);
@@ -2816,13 +2990,13 @@
 	val = tr32(ofs);
 	val &= ~enable_bit;
 	tw32(ofs, val);
+	tr32(ofs);
 
 	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
 		val = tr32(ofs);
-
 		if ((val & enable_bit) == 0)
 			break;
-		udelay(100);
 	}
 
 	if (i == MAX_WAIT_CNT) {
@@ -2844,6 +3018,8 @@
 
 	tp->rx_mode &= ~RX_MODE_ENABLE;
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
 	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
@@ -2863,9 +3039,13 @@
 
 	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
 	tw32(MAC_MODE, tp->mac_mode);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	tp->tx_mode &= ~TX_MODE_ENABLE;
 	tw32(MAC_TX_MODE, tp->tx_mode);
+	tr32(MAC_TX_MODE);
+
 	for (i = 0; i < MAX_WAIT_CNT; i++) {
 		udelay(100);
 		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
@@ -2917,6 +3097,14 @@
 	}
 
 	tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET);
+
+	/* Flush PCI posted writes.  The normal MMIO registers
+	 * are inaccessible at this time so this is the only
+	 * way to make this reliably.  I tried to use indirect
+	 * register read/write but this upset some 5701 variants.
+	 */
+	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
+
 	udelay(40);
 	udelay(40);
 	udelay(40);
@@ -2926,9 +3114,11 @@
 			       tp->misc_host_ctrl);
 
 	/* Set MAX PCI retry to zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
-			       (PCISTATE_ROM_ENABLE |
-				PCISTATE_ROM_RETRY_ENABLE));
+	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+		val |= PCISTATE_RETRY_SAME_DMA;
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
 	pci_restore_state(tp->pdev, tp->pci_cfg_state);
 
@@ -2943,11 +3133,33 @@
 }
 
 /* tp->lock is held. */
+static void tg3_stop_fw(struct tg3 *tp)
+{
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		u32 val;
+		int i;
+
+		tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
+		val = tr32(GRC_RX_CPU_EVENT);
+		val |= (1 << 14);
+		tw32(GRC_RX_CPU_EVENT, val);
+
+		/* Wait for RX cpu to ACK the event.  */
+		for (i = 0; i < 100; i++) {
+			if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
+				break;
+			udelay(1);
+		}
+	}
+}
+
+/* tp->lock is held. */
 static int tg3_halt(struct tg3 *tp)
 {
 	u32 val;
 	int i;
 
+	tg3_stop_fw(tp);
 	tg3_abort_hw(tp);
 	tg3_chip_reset(tp);
 	tg3_write_mem(tp,
@@ -2967,6 +3179,17 @@
 		return -ENODEV;
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+		if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+				      DRV_STATE_WOL);
+		else
+			tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+				      DRV_STATE_UNLOAD);
+	} else
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_SUSPEND);
+
 	return 0;
 }
 
@@ -2985,7 +3208,7 @@
 #define TG3_FW_BSS_ADDR		0x08000a70
 #define TG3_FW_BSS_LEN		0x10
 
-static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
+static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
 	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
 	0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
 	0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
@@ -3079,7 +3302,7 @@
 	0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
 };
 
-static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
+static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
 	0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
 	0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
@@ -3088,7 +3311,7 @@
 };
 
 #if 0 /* All zeros, dont eat up space with it. */
-u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
+u32 tg3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
 	0x00000000, 0x00000000, 0x00000000, 0x00000000
 };
@@ -3112,6 +3335,7 @@
 				break;
 		tw32(offset + CPU_STATE, 0xffffffff);
 		tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+		tr32(offset + CPU_MODE);
 		udelay(10);
 	} else {
 		for (i = 0; i < 10000; i++) {
@@ -3119,6 +3343,7 @@
 				break;
 			tw32(offset + CPU_STATE, 0xffffffff);
 			tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+			tr32(offset + CPU_MODE);
 			udelay(10);
 		}
 	}
@@ -3133,51 +3358,89 @@
 	return 0;
 }
 
+struct fw_info {
+	unsigned int text_base;
+	unsigned int text_len;
+	u32 *text_data;
+	unsigned int rodata_base;
+	unsigned int rodata_len;
+	u32 *rodata_data;
+	unsigned int data_base;
+	unsigned int data_len;
+	u32 *data_data;
+};
+
 /* tp->lock is held. */
 static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,
-				 int cpu_scratch_size)
+				 int cpu_scratch_size, struct fw_info *info)
 {
 	int err, i;
+	u32 orig_tg3_flags = tp->tg3_flags;
+
+	/* Force use of PCI config space for indirect register
+	 * write calls.
+	 */
+	tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
 
 	err = tg3_reset_cpu(tp, cpu_base);
 	if (err)
-		return err;
+		goto out;
 
 	for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
 		tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0);
 	tw32(cpu_base + CPU_STATE, 0xffffffff);
 	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
-	for (i = 0; i < (TG3_FW_TEXT_LEN / sizeof(u32)); i++)
+	for (i = 0; i < (info->text_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_TEXT_ADDR & 0xffff) +
+					      (info->text_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 t3FwText[i]);
-	for (i = 0; i < (TG3_FW_RODATA_LEN / sizeof(u32)); i++)
+					 (info->text_data ?
+					  info->text_data[i] : 0));
+	for (i = 0; i < (info->rodata_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_RODATA_ADDR & 0xffff) +
+					      (info->rodata_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 t3FwRodata[i]);
-	for (i = 0; i < (TG3_FW_DATA_LEN / sizeof(u32)); i++)
+					 (info->rodata_data ?
+					  info->rodata_data[i] : 0));
+	for (i = 0; i < (info->data_len / sizeof(u32)); i++)
 		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
-					      (TG3_FW_DATA_ADDR & 0xffff) +
+					      (info->data_base & 0xffff) +
 					      (i * sizeof(u32))),
-					 0);
+					 (info->data_data ?
+					  info->data_data[i] : 0));
 
-	return 0;
+	err = 0;
+
+out:
+	tp->tg3_flags = orig_tg3_flags;
+	return err;
 }
 
 /* tp->lock is held. */
 static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
 {
+	struct fw_info info;
 	int err, i;
 
+	info.text_base = TG3_FW_TEXT_ADDR;
+	info.text_len = TG3_FW_TEXT_LEN;
+	info.text_data = &tg3FwText[0];
+	info.rodata_base = TG3_FW_RODATA_ADDR;
+	info.rodata_len = TG3_FW_RODATA_LEN;
+	info.rodata_data = &tg3FwRodata[0];
+	info.data_base = TG3_FW_DATA_ADDR;
+	info.data_len = TG3_FW_DATA_LEN;
+	info.data_data = NULL;
+
 	err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
-				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE);
+				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
+				    &info);
 	if (err)
 		return err;
 
 	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
-				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE);
+				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+				    &info);
 	if (err)
 		return err;
 
@@ -3215,6 +3478,336 @@
 	return 0;
 }
 
+#if TG3_DO_TSO != 0
+
+#define TG3_TSO_FW_RELEASE_MAJOR	0x1
+#define TG3_TSO_FW_RELASE_MINOR		0x8
+#define TG3_TSO_FW_RELEASE_FIX		0x0
+#define TG3_TSO_FW_START_ADDR		0x08000000
+#define TG3_TSO_FW_TEXT_ADDR		0x08000000
+#define TG3_TSO_FW_TEXT_LEN		0x1650
+#define TG3_TSO_FW_RODATA_ADDR		0x08001650
+#define TG3_TSO_FW_RODATA_LEN		0x30
+#define TG3_TSO_FW_DATA_ADDR		0x080016a0
+#define TG3_TSO_FW_DATA_LEN		0x20
+#define TG3_TSO_FW_SBSS_ADDR		0x080016c0
+#define TG3_TSO_FW_SBSS_LEN		0x14
+#define TG3_TSO_FW_BSS_ADDR		0x080016e0
+#define TG3_TSO_FW_BSS_LEN		0x8fc
+
+static u32 tg3TsoFwText[] = {
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
+	0x37bd4000, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000010, 0x00000000,
+	0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c1bc000,
+	0xafbf0018, 0x0e000058, 0xaf60680c, 0x3c040800, 0x24841650, 0x03602821,
+	0x24060001, 0x24070004, 0xafa00010, 0x0e00006c, 0xafa00014, 0x8f625c50,
+	0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, 0x2402ffff,
+	0x0e000098, 0xaf625404, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000,
+	0x00000000, 0x00000000, 0x24030b60, 0x24050fff, 0xac000b50, 0x00002021,
+	0xac640000, 0x24630004, 0x0065102b, 0x1440fffc, 0x24840001, 0x24030b60,
+	0x0065102b, 0x10400011, 0x00002021, 0x24090b54, 0x3c06dead, 0x34c6beef,
+	0x24080b58, 0x24070b5c, 0x8c620000, 0x50440006, 0x24630004, 0xad260000,
+	0x8c620000, 0xace40000, 0xad020000, 0x24630004, 0x0065102b, 0x1440fff6,
+	0x24840001, 0x03e00008, 0x00000000, 0x27bdfff8, 0x18800009, 0x00002821,
+	0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a,
+	0x1440fff9, 0x00000000, 0x03e00008, 0x27bd0008, 0x3c020800, 0x34423000,
+	0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac2216c4,
+	0x24020040, 0x3c010800, 0xac2216c8, 0x3c010800, 0xac2016c0, 0xac600000,
+	0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
+	0x00804821, 0x8faa0010, 0x3c020800, 0x8c4216c0, 0x3c040800, 0x8c8416c8,
+	0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac2316c0, 0x14400003,
+	0x00004021, 0x3c010800, 0xac2016c0, 0x3c020800, 0x8c4216c0, 0x3c030800,
+	0x8c6316c4, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
+	0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c4216c0,
+	0x3c030800, 0x8c6316c4, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008,
+	0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
+	0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x0e0000b6,
+	0xafb00010, 0x24110001, 0x8f706820, 0x32020100, 0x10400003, 0x00000000,
+	0x0e000127, 0x00000000, 0x8f706820, 0x32022000, 0x10400004, 0x32020001,
+	0x0e00025a, 0x24040001, 0x32020001, 0x10400003, 0x00000000, 0x0e0000e6,
+	0x00000000, 0x0a00009e, 0xaf715028, 0x8fbf0018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841660, 0x00002821,
+	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
+	0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8, 0x3c010800, 0xac2016fc,
+	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
+	0x3c010800, 0xac201718, 0x3c010800, 0xac20171c, 0x8f624434, 0x3c010800,
+	0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec, 0x8f624410, 0x3c010800,
+	0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800, 0xac201fc0, 0x3c010800,
+	0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800, 0xac2216f0, 0x8fbf0018,
+	0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x2484166c, 0x00002821,
+	0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014,
+	0x3c040800, 0x24841660, 0x00002821, 0x00003021, 0x00003821, 0xafa00010,
+	0x0e00006c, 0xafa00014, 0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8,
+	0x3c010800, 0xac2016fc, 0x3c010800, 0xac201700, 0x3c010800, 0xac201704,
+	0x3c010800, 0xac20170c, 0x3c010800, 0xac201718, 0x3c010800, 0xac20171c,
+	0x8f624434, 0x3c010800, 0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec,
+	0x8f624410, 0x3c010800, 0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800,
+	0xac201fc0, 0x3c010800, 0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800,
+	0xac2216f0, 0x0e000120, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020,
+	0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008,
+	0xaf636820, 0x27bdffd0, 0x3c0300ff, 0xafbf002c, 0xafb60028, 0xafb50024,
+	0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f665c5c,
+	0x3c040800, 0x2484171c, 0x8c820000, 0x3463fff8, 0x14460005, 0x00c38824,
+	0x3c020800, 0x904216f8, 0x14400115, 0x00000000, 0x00111902, 0x306300ff,
+	0x30c20003, 0x000211c0, 0x00623825, 0x00e02821, 0x00061602, 0xac860000,
+	0x3c030800, 0x906316f8, 0x3044000f, 0x1460002b, 0x00804021, 0x24020001,
+	0x3c010800, 0xa02216f8, 0x00071100, 0x00821025, 0x3c010800, 0xac2016fc,
+	0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c,
+	0x3c010800, 0xac201718, 0x3c010800, 0xac201710, 0x3c010800, 0xac201714,
+	0x3c010800, 0xa4221fb8, 0x9623000c, 0x30628000, 0x10400008, 0x30627fff,
+	0x2442003e, 0x3c010800, 0xa42216f6, 0x24020001, 0x3c010800, 0x0a00016e,
+	0xac221fd4, 0x24620036, 0x3c010800, 0xa42216f6, 0x3c010800, 0xac201fd4,
+	0x3c010800, 0xac201fd0, 0x3c010800, 0x0a000176, 0xac201fd8, 0x9622000c,
+	0x3c010800, 0xa4221fcc, 0x3c040800, 0x248416fc, 0x8c820000, 0x00021100,
+	0x3c010800, 0x00220821, 0xac311728, 0x8c820000, 0x00021100, 0x3c010800,
+	0x00220821, 0xac26172c, 0x8c820000, 0x24a30001, 0x306701ff, 0x00021100,
+	0x3c010800, 0x00220821, 0xac271730, 0x8c820000, 0x00021100, 0x3c010800,
+	0x00220821, 0xac281734, 0x96230008, 0x3c020800, 0x8c42170c, 0x00432821,
+	0x3c010800, 0xac25170c, 0x9622000a, 0x30420004, 0x14400019, 0x00071100,
+	0x3c02c000, 0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x1440fffc,
+	0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440001e, 0x00000000,
+	0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800,
+	0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000, 0x0a0001c1, 0x00000000,
+	0x3c030800, 0x8c6316e0, 0x3c040800, 0x948416f4, 0x01021025, 0x3c010800,
+	0xa4221fba, 0x24020001, 0x3c010800, 0xac221718, 0x24630001, 0x0085202a,
+	0x3c010800, 0x10800003, 0xac2316e0, 0x3c010800, 0xa42516f4, 0x3c030800,
+	0x246316fc, 0x8c620000, 0x24420001, 0xac620000, 0x28420080, 0x14400005,
+	0x24020001, 0x0e0002df, 0x24040002, 0x0a000250, 0x00000000, 0x3c030800,
+	0x906316f8, 0x1462007c, 0x24020003, 0x3c160800, 0x96d616f6, 0x3c050800,
+	0x8ca5170c, 0x32c4ffff, 0x00a4102a, 0x14400078, 0x00000000, 0x3c020800,
+	0x8c421718, 0x10400005, 0x32c2ffff, 0x14a40003, 0x00000000, 0x3c010800,
+	0xac231fd0, 0x10400062, 0x00009021, 0x0040a021, 0x3c150800, 0x26b51700,
+	0x26b30010, 0x8ea20000, 0x00028100, 0x3c110800, 0x02308821, 0x0e0002e1,
+	0x8e311728, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a, 0x31020040,
+	0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018, 0x31021000,
+	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x3c030800,
+	0x00701821, 0x8c631730, 0x3c020800, 0x00501021, 0x8c421734, 0x00031d00,
+	0x00021400, 0x00621825, 0xacc30014, 0x8ea30004, 0x96220008, 0x00432023,
+	0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002, 0x02d22823,
+	0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000, 0x8e220000,
+	0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004, 0xa4c5000e,
+	0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a, 0x14400005,
+	0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, 0xacc00008,
+	0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001, 0x34e70010,
+	0x24020905, 0xa4c2000c, 0x0a000233, 0x34e70020, 0xa4c2000c, 0x30e2ffff,
+	0xacc20010, 0x3c020800, 0x8c421fd0, 0x10400003, 0x3c024b65, 0x0a00023d,
+	0x34427654, 0x3c02b49a, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021,
+	0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002, 0x3c010800,
+	0x0a000250, 0xa02216f8, 0x8ea208bc, 0x24420001, 0x0a000250, 0xaea208bc,
+	0x14620003, 0x00000000, 0x0e000450, 0x00000000, 0x8fbf002c, 0x8fb60028,
+	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0030, 0x27bdffd8, 0xafb3001c, 0x00809821, 0xafbf0020,
+	0xafb20018, 0xafb10014, 0xafb00010, 0x8f725c9c, 0x3c0200ff, 0x3442fff8,
+	0x3c040800, 0x24841714, 0x02428824, 0x9623000e, 0x8c820000, 0x00431021,
+	0xac820000, 0x8e220010, 0x30420020, 0x14400011, 0x00000000, 0x0e0002f7,
+	0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002,
+	0x10400061, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040005c,
+	0x00000000, 0x0a000278, 0x00000000, 0x8e220008, 0x00021c02, 0x000321c0,
+	0x3042ffff, 0x3c030800, 0x906316f8, 0x000229c0, 0x24020002, 0x14620003,
+	0x3c034b65, 0x0a000290, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002,
+	0x24100002, 0x24100001, 0x0e000300, 0x02003021, 0x24020003, 0x3c010800,
+	0xa02216f8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c631fd0,
+	0x10620006, 0x00000000, 0x3c020800, 0x94421fb8, 0x00021400, 0x0a0002cd,
+	0xae220014, 0x3c040800, 0x24841fba, 0x94820000, 0x00021400, 0xae220014,
+	0x3c020800, 0x8c42171c, 0x3c03c000, 0x3c010800, 0xa02016f8, 0x00431025,
+	0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f762,
+	0x8c820000, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa,
+	0x00000000, 0x3c020800, 0x244216e4, 0x8c430000, 0x24630001, 0xac430000,
+	0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, 0x00009821, 0x8f630c14,
+	0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800, 0xac2216b4,
+	0x2c620002, 0x1040fff7, 0x00009821, 0x3c024000, 0x02421825, 0xaf635c9c,
+	0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x12600003, 0x00000000,
+	0x0e000450, 0x00000000, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+	0x8fb00010, 0x03e00008, 0x27bd0028, 0x0a0002df, 0x00000000, 0x8f634450,
+	0x3c040800, 0x248416e8, 0x8c820000, 0x00031c02, 0x0043102b, 0x14400007,
+	0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc,
+	0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000,
+	0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38,
+	0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000,
+	0x27bdffe0, 0x00805021, 0x14c00017, 0x254c0008, 0x3c020800, 0x8c421fd4,
+	0x1040000a, 0x2402003e, 0x3c010800, 0xa4221fb0, 0x24020016, 0x3c010800,
+	0xa4221fb2, 0x2402002a, 0x3c010800, 0x0a00031a, 0xa4221fb4, 0x95420014,
+	0x3c010800, 0xa4221fb0, 0x8d430010, 0x00031402, 0x3c010800, 0xa4221fb2,
+	0x3c010800, 0xa4231fb4, 0x3c040800, 0x94841fb4, 0x3c030800, 0x94631fb2,
+	0x958d0006, 0x3c020800, 0x94421fb0, 0x00832023, 0x01a27023, 0x3065ffff,
+	0x24a20028, 0x01824021, 0x3082ffff, 0x14c0001a, 0x01025821, 0x9562000c,
+	0x3042003f, 0x3c010800, 0xa4221fb6, 0x95620004, 0x95630006, 0x3c010800,
+	0xac201fc4, 0x3c010800, 0xac201fc8, 0x00021400, 0x00431025, 0x3c010800,
+	0xac221720, 0x95020004, 0x3c010800, 0xa4221724, 0x95030002, 0x01a51023,
+	0x0043102a, 0x10400010, 0x24020001, 0x3c010800, 0x0a00034e, 0xac221fd8,
+	0x3c030800, 0x8c631fc8, 0x3c020800, 0x94421724, 0x00431021, 0xa5020004,
+	0x3c020800, 0x94421720, 0xa5620004, 0x3c020800, 0x8c421720, 0xa5620006,
+	0x3c020800, 0x8c421fd0, 0x3c070800, 0x8ce71fc4, 0x3c050800, 0x144000c7,
+	0x8ca51fc8, 0x3c020800, 0x94421724, 0x00451821, 0x3063ffff, 0x0062182b,
+	0x24020002, 0x10c2000d, 0x00a32823, 0x3c020800, 0x94421fb6, 0x30420009,
+	0x10400008, 0x00000000, 0x9562000c, 0x3042fff6, 0xa562000c, 0x3c020800,
+	0x94421fb6, 0x30420009, 0x00e23823, 0x3c020800, 0x8c421fd8, 0x1040004b,
+	0x24020002, 0x01003021, 0x3c020800, 0x94421fb2, 0x00003821, 0xa500000a,
+	0x01a21023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008, 0x00002821,
+	0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a, 0x1440fffb,
+	0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c, 0x00003821,
+	0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb, 0x24c60002,
+	0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021, 0x3082ffff,
+	0xa4c00010, 0x00621821, 0x00021042, 0x18400010, 0x00a32821, 0x00404021,
+	0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f, 0x14400006, 0x24e70001,
+	0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024, 0x25460008, 0x00e8102a,
+	0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00051c02, 0xa0c00001,
+	0x94c20000, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x0a000415, 0x30a5ffff, 0x14c20063, 0x00000000, 0x3c090800,
+	0x95291fb2, 0x95030002, 0x01a91023, 0x1062005d, 0x01003021, 0x00003821,
+	0x00002821, 0x01a91023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008,
+	0xa500000a, 0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a,
+	0x1440fffb, 0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c,
+	0x00003821, 0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb,
+	0x24c60002, 0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021,
+	0x3082ffff, 0xa4c00010, 0x3c040800, 0x94841fb4, 0x00621821, 0x00a32821,
+	0x00051c02, 0x30a2ffff, 0x00622821, 0x00051c02, 0x3c020800, 0x94421fb0,
+	0x00a34021, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043, 0x18400010,
+	0x00002821, 0x00402021, 0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f,
+	0x14400006, 0x24e70001, 0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024,
+	0x25460008, 0x00e4102a, 0x1440fff3, 0x00000000, 0x3c020800, 0x94421fcc,
+	0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x3102ffff, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402,
+	0x00a22821, 0x00a02021, 0x00051027, 0xa5620010, 0xad800014, 0x0a000435,
+	0xad800000, 0x8d830010, 0x00602021, 0x10a00007, 0x00034c02, 0x01252821,
+	0x00051402, 0x30a3ffff, 0x00432821, 0x00051402, 0x00a24821, 0x00091027,
+	0xa502000a, 0x3c030800, 0x94631fb4, 0x3082ffff, 0x01a21021, 0x00432823,
+	0x00a72821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821,
+	0x00a02021, 0x00051027, 0xa5620010, 0x3082ffff, 0x00091c00, 0x00431025,
+	0xad820010, 0x3c020800, 0x8c421fd4, 0x10400002, 0x25a2fff2, 0xa5820034,
+	0x3c020800, 0x8c421fc8, 0x3c030800, 0x8c631720, 0x24420001, 0x3c010800,
+	0xac221fc8, 0x3c020800, 0x8c421fc4, 0x31c4ffff, 0x00641821, 0x3c010800,
+	0xac231720, 0x00441021, 0x3c010800, 0xac221fc4, 0x03e00008, 0x27bd0020,
+	0x27bdffc8, 0x3c040800, 0x248416f8, 0xafbf0034, 0xafbe0030, 0xafb7002c,
+	0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014,
+	0xafb00010, 0x90830000, 0x24020003, 0x146200f4, 0x00000000, 0x3c020800,
+	0x8c421710, 0x3c030800, 0x8c63170c, 0x3c1e0800, 0x97de16f6, 0x0043102a,
+	0x104000eb, 0x3c168000, 0x249708c4, 0x33d5ffff, 0x24920018, 0x3c020800,
+	0x8c421718, 0x104000e4, 0x00000000, 0x3c140800, 0x96941fb0, 0x3282ffff,
+	0x104000d6, 0x00008021, 0x00409821, 0x00008821, 0x8f634450, 0x3c020800,
+	0x8c4216e8, 0x00031c02, 0x0043102b, 0x14400008, 0x00000000, 0x3c040800,
+	0x8c8416ec, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x00000000,
+	0xaf764444, 0x8f624444, 0x00561024, 0x10400006, 0x00000000, 0x3c038000,
+	0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff,
+	0x10c0005f, 0x00000000, 0x3c090800, 0x01314821, 0x8d291728, 0x9528000a,
+	0x31020040, 0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018,
+	0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825,
+	0x31020080, 0x54400001, 0x34e70010, 0x3c020800, 0x00511021, 0x8c421730,
+	0x3c030800, 0x00711821, 0x8c631734, 0x00021500, 0x00031c00, 0x00431025,
+	0xacc20014, 0x95240008, 0x3202ffff, 0x00821021, 0x0262102a, 0x14400002,
+	0x02902823, 0x00802821, 0x8d220000, 0x02058021, 0xacc20000, 0x8d220004,
+	0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff, 0xac800008, 0xa485000e,
+	0xac820010, 0x24020305, 0x0e000560, 0xa482000c, 0x3202ffff, 0x0053102b,
+	0x1440ffaf, 0x3202ffff, 0x0a00054c, 0x00000000, 0x8e420000, 0x8e43fffc,
+	0x0043102a, 0x10400084, 0x00000000, 0x8e45fff0, 0x8f644450, 0x3c030800,
+	0x8c6316e8, 0x00051100, 0x3c090800, 0x01224821, 0x8d291728, 0x00041402,
+	0x0062182b, 0x14600008, 0x00000000, 0x3c030800, 0x8c6316ec, 0x8f624450,
+	0x00021402, 0x0062102b, 0x1040fffc, 0x00000000, 0xaf764444, 0x8f624444,
+	0x00561024, 0x10400006, 0x00000000, 0x3c038000, 0x8f624444, 0x00431024,
+	0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff, 0x14c00005, 0x00000000,
+	0x8ee20000, 0x24420001, 0x0a000554, 0xaee20000, 0x9528000a, 0x31020040,
+	0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018, 0x31021000,
+	0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x00051900,
+	0x3c020800, 0x00431021, 0x8c421730, 0x3c010800, 0x00230821, 0x8c231734,
+	0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x3c030800, 0x8c631704,
+	0x95220008, 0x00432023, 0x3202ffff, 0x3083ffff, 0x00431021, 0x02a2102a,
+	0x14400002, 0x03d02823, 0x00802821, 0x8e420000, 0x30a4ffff, 0x00441021,
+	0xae420000, 0xa4c5000e, 0x8d220000, 0xacc20000, 0x8d220004, 0x8e43fff4,
+	0x00431021, 0xacc20004, 0x8e43fff4, 0x95220008, 0x00641821, 0x0062102a,
+	0x14400006, 0x02058021, 0x8e42fff0, 0xae40fff4, 0x24420001, 0x0a000530,
+	0xae42fff0, 0xae43fff4, 0xacc00008, 0x3202ffff, 0x10550003, 0x31020004,
+	0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x34e70020,
+	0x24020905, 0xa4c2000c, 0x30e2ffff, 0xacc20010, 0x3c030800, 0x8c63170c,
+	0x3c020800, 0x8c421710, 0x54620004, 0x3c02b49a, 0x3c024b65, 0x0a000548,
+	0x34427654, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021, 0x3202ffff,
+	0x0055102b, 0x1440ff7e, 0x00000000, 0x8e420000, 0x8e43fffc, 0x0043102a,
+	0x1440ff1a, 0x00000000, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028,
+	0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+	0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f624450,
+	0x8f634410, 0x0a00056f, 0x00808021, 0x8f626820, 0x30422000, 0x10400003,
+	0x00000000, 0x0e00025a, 0x00002021, 0x8f624450, 0x8f634410, 0x3042ffff,
+	0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002,
+	0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f,
+	0x24420001, 0x3c010800, 0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000,
+	0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, 0x00000000, 0x8f626820,
+	0x30422000, 0x1040fff8, 0x00000000, 0x0e00025a, 0x00002021, 0x0a000582,
+	0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000,
+	0x00000000
+};
+
+u32 tg3TsoFwRodata[] = {
+	0x4d61696e, 0x43707542, 0x00000000, 0x00000000, 0x74637073, 0x6567496e,
+	0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000
+};
+
+#if 0 /* All zeros, dont eat up space with it. */
+u32 tg3TsoFwData[] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000
+};
+#endif
+
+/* tp->lock is held. */
+static int tg3_load_tso_firmware(struct tg3 *tp)
+{
+	struct fw_info info;
+	int err, i;
+
+	info.text_base = TG3_TSO_FW_TEXT_ADDR;
+	info.text_len = TG3_TSO_FW_TEXT_LEN;
+	info.text_data = &tg3TsoFwText[0];
+	info.rodata_base = TG3_TSO_FW_RODATA_ADDR;
+	info.rodata_len = TG3_TSO_FW_RODATA_LEN;
+	info.rodata_data = &tg3TsoFwRodata[0];
+	info.data_base = TG3_TSO_FW_DATA_ADDR;
+	info.data_len = TG3_TSO_FW_DATA_LEN;
+	info.data_data = NULL;
+
+	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
+				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
+				    &info);
+	if (err)
+		return err;
+
+	/* Now startup only the TX cpu. */
+	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+
+	/* Flush posted writes. */
+	tr32(TX_CPU_BASE + CPU_PC);
+	for (i = 0; i < 5; i++) {
+		if (tr32(TX_CPU_BASE + CPU_PC) == TG3_TSO_FW_TEXT_ADDR)
+			break;
+		tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+		tw32(TX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+		tw32(TX_CPU_BASE + CPU_PC,    TG3_TSO_FW_TEXT_ADDR);
+
+		/* Flush posted writes. */
+		tr32(TX_CPU_BASE + CPU_PC);
+
+		udelay(1000);
+	}
+	if (i >= 5) {
+		printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s "
+		       "to set TX CPU PC, is %08x should be %08x\n",
+		       tp->dev->name, tr32(TX_CPU_BASE + CPU_PC),
+		       TG3_TSO_FW_TEXT_ADDR);
+		return -ENODEV;
+	}
+	tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(TX_CPU_BASE + CPU_MODE,  0x00000000);
+
+	/* Flush posted writes. */
+	tr32(TX_CPU_BASE + CPU_MODE);
+
+	return 0;
+}
+
+#endif /* TG3_DO_TSO != 0 */
+
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp)
 {
@@ -3294,6 +3887,8 @@
 
 	tg3_disable_ints(tp);
 
+	tg3_stop_fw(tp);
+
 	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
 		err = tg3_abort_hw(tp);
 		if (err)
@@ -3311,6 +3906,8 @@
 		tw32(MAC_MODE, tp->mac_mode);
 	} else
 		tw32(MAC_MODE, 0);
+	tr32(MAC_MODE);
+	udelay(40);
 
 	/* Wait for firmware initialization to complete. */
 	for (i = 0; i < 100000; i++) {
@@ -3326,6 +3923,13 @@
 		return -ENODEV;
 	}
 
+	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_START);
+	else
+		tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
+			      DRV_STATE_SUSPEND);
+
 	/* This works around an issue with Athlon chipsets on
 	 * B3 tigon3 silicon.  This bit has no effect on any
 	 * other revision.
@@ -3333,6 +3937,14 @@
 	val = tr32(TG3PCI_CLOCK_CTRL);
 	val |= CLOCK_CTRL_DELAY_PCI_GRANT;
 	tw32(TG3PCI_CLOCK_CTRL, val);
+	tr32(TG3PCI_CLOCK_CTRL);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+		val = tr32(TG3PCI_PCISTATE);
+		val |= PCISTATE_RETRY_SAME_DMA;
+		tw32(TG3PCI_PCISTATE, val);
+	}
 
 	/* Clear statistics/status block in chip, and status block in ram. */
 	for (i = NIC_SRAM_STATS_BLK;
@@ -3371,7 +3983,10 @@
 
 	/* Initialize MBUF/DESC pool. */
 	tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
-	tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
+	else
+		tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
 	tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
 	tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
 
@@ -3491,6 +4106,8 @@
 	tp->tx_cons = 0;
 	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
 	tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW);
 
 	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
 		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
@@ -3512,6 +4129,8 @@
 
 	tp->rx_rcb_ptr = 0;
 	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
 
 	tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB,
 		       tp->rx_rcb_mapping,
@@ -3522,10 +4141,14 @@
 	tp->rx_std_ptr = tp->rx_pending;
 	tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_std_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
 #if TG3_MINI_RING_WORKS
 	tp->rx_mini_ptr = tp->rx_mini_pending;
 	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_mini_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
 #endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
@@ -3534,6 +4157,8 @@
 		tp->rx_jumbo_ptr = 0;
 	tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
 		     tp->rx_jumbo_ptr);
+	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+		tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 
 	/* Initialize MAC address and backoff seed. */
 	__tg3_set_mac_addr(tp);
@@ -3601,25 +4226,53 @@
 	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
 		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
 	tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
+	tr32(MAC_MODE);
+	udelay(40);
 
-	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_GPIO_OE1 |
-		GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_AUTO_SEEPROM;
+	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+				       GRC_LCLCTRL_GPIO_OUTPUT1);
 	tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+	tr32(GRC_LOCAL_CTRL);
+	udelay(100);
 
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
+	tr32(MAILBOX_INTERRUPT_0);
 
 	tw32(DMAC_MODE, DMAC_MODE_ENABLE);
+	tr32(DMAC_MODE);
+	udelay(40);
 
 	tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
 			  WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
 			  WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
 			  WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
 			  WDMAC_MODE_LNGREAD_ENAB));
-	tw32(RDMAC_MODE, (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
-			  RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
-			  RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
-			  RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
-			  RDMAC_MODE_LNGREAD_ENAB));
+	tr32(WDMAC_MODE);
+	udelay(40);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+		val = tr32(TG3PCI_X_CAPS);
+		val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
+		val |= (PCIX_CAPS_MAX_BURST_5704 << PCIX_CAPS_BURST_SHIFT);
+		if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+			val |= (tp->split_mode_max_reqs <<
+				PCIX_CAPS_SPLIT_SHIFT);
+		tw32(TG3PCI_X_CAPS, val);
+	}
+
+	val = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+	       RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+	       RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+	       RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+	       RDMAC_MODE_LNGREAD_ENAB);
+	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
+		val |= RDMAC_MODE_SPLIT_ENABLE;
+	tw32(RDMAC_MODE, val);
+	tr32(RDMAC_MODE);
+	udelay(40);
 
 	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
 	tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
@@ -3637,10 +4290,21 @@
 			return err;
 	}
 
+#if TG3_DO_TSO != 0
+	err = tg3_load_tso_firmware(tp);
+	if (err)
+		return err;
+#endif
+
 	tp->tx_mode = TX_MODE_ENABLE;
 	tw32(MAC_TX_MODE, tp->tx_mode);
+	tr32(MAC_TX_MODE);
+	udelay(100);
+
 	tp->rx_mode = RX_MODE_ENABLE;
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	if (tp->link_config.phy_is_low_power) {
 		tp->link_config.phy_is_low_power = 0;
@@ -3651,11 +4315,17 @@
 
 	tp->mi_mode = MAC_MI_MODE_BASE;
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
+	udelay(40);
+
 	tw32(MAC_LED_CTRL, 0);
 	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
 	tw32(MAC_RX_MODE, RX_MODE_RESET);
+	tr32(MAC_RX_MODE);
 	udelay(10);
 	tw32(MAC_RX_MODE, tp->rx_mode);
+	tr32(MAC_RX_MODE);
+	udelay(10);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
 		tw32(MAC_SERDES_CFG, 0x616000);
@@ -3738,7 +4408,7 @@
 		tw32(GRC_LOCAL_CTRL,
 		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
 	} else {
-		tw32(HOSTCC_MODE,
+		tw32(HOSTCC_MODE, tp->coalesce_mode |
 		     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
 	}
 
@@ -3781,8 +4451,11 @@
 				tw32(MAC_MODE,
 				     (tp->mac_mode &
 				      ~MAC_MODE_PORT_MODE_MASK));
+				tr32(MAC_MODE);
 				udelay(40);
 				tw32(MAC_MODE, tp->mac_mode);
+				tr32(MAC_MODE);
+				udelay(40);
 				tg3_setup_phy(tp);
 			}
 		}
@@ -3790,6 +4463,21 @@
 		tp->timer_counter = tp->timer_multiplier;
 	}
 
+	/* Heartbeat is only sent once every 120 seconds.  */
+	if (!--tp->asf_counter) {
+		if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+			u32 val;
+
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3);
+			val = tr32(GRC_RX_CPU_EVENT);
+			val |= (1 << 14);
+			tw32(GRC_RX_CPU_EVENT, val);
+		}
+		tp->asf_counter = tp->asf_multiplier;
+	}
+
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
@@ -3838,6 +4526,7 @@
 	} else {
 		tp->timer_offset = HZ / 10;
 		tp->timer_counter = tp->timer_multiplier = 10;
+		tp->asf_counter = tp->asf_multiplier = (10 * 120);
 
 		init_timer(&tp->timer);
 		tp->timer.expires = jiffies + tp->timer_offset;
@@ -4272,10 +4961,10 @@
 static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all)
 {
 	/* accept or reject all multicast frames */
-	tw32 (MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
-	tw32 (MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
+	tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
 }
 
 static void __tg3_set_rx_mode(struct net_device *dev)
@@ -4283,7 +4972,17 @@
 	struct tg3 *tp = dev->priv;
 	u32 rx_mode;
 
-	rx_mode = tp->rx_mode & ~RX_MODE_PROMISC;
+	rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
+				  RX_MODE_KEEP_VLAN_TAG);
+#if TG3_VLAN_TAG_USED
+	if (!tp->vlgrp)
+		rx_mode |= RX_MODE_KEEP_VLAN_TAG;
+#else
+	/* By definition, VLAN is disabled always in this
+	 * case.
+	 */
+	rx_mode |= RX_MODE_KEEP_VLAN_TAG;
+#endif
 
 	if (dev->flags & IFF_PROMISC) {
 		/* Promiscuous mode. */
@@ -4313,15 +5012,17 @@
 			mc_filter[regidx] |= (1 << bit);
 		}
 
-		tw32 (MAC_HASH_REG_0, mc_filter[0]);
-		tw32 (MAC_HASH_REG_1, mc_filter[1]);
-		tw32 (MAC_HASH_REG_2, mc_filter[2]);
-		tw32 (MAC_HASH_REG_3, mc_filter[3]);
+		tw32(MAC_HASH_REG_0, mc_filter[0]);
+		tw32(MAC_HASH_REG_1, mc_filter[1]);
+		tw32(MAC_HASH_REG_2, mc_filter[2]);
+		tw32(MAC_HASH_REG_3, mc_filter[3]);
 	}
 
 	if (rx_mode != tp->rx_mode) {
 		tp->rx_mode = rx_mode;
-		tw32 (MAC_RX_MODE, rx_mode);
+		tw32(MAC_RX_MODE, rx_mode);
+		tr32(MAC_RX_MODE);
+		udelay(10);
 	}
 }
 
@@ -4837,7 +5538,12 @@
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
+
 	tp->vlgrp = grp;
+
+	/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
+	__tg3_set_rx_mode(dev);
+
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 }
@@ -4872,6 +5578,7 @@
 	/* Enable seeprom accesses. */
 	tw32(GRC_LOCAL_CTRL,
 	     tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
+	tr32(GRC_LOCAL_CTRL);
 	udelay(100);
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
@@ -5079,11 +5786,14 @@
 			eeprom_led_mode = led_mode_auto;
 			break;
 		};
-	}
+		if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
+		     tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) &&
+		    (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
+			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 
-	err = tg3_phy_reset(tp, 0);
-	if (err)
-		return err;
+		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
+			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+	}
 
 	/* Now read the physical PHY_ID from the chip and verify
 	 * that it is sane.  If it doesn't look good, we fall back
@@ -5114,30 +5824,24 @@
 		}
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
-	}
+	err = tg3_phy_reset(tp, 1);
+	if (err)
+		return err;
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
-		tp->tg3_flags |= TG3_FLAG_PHY_RESET_ON_INIT;
-
-	if (tp->tg3_flags & TG3_FLAG_PHY_RESET_ON_INIT) {
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
 		u32 mii_tg3_ctrl;
-
-		err = tg3_phy_reset(tp, 1);
-		if (err)
-			return err;
-
-		/* These chips, when reset, only advertise 10Mb capabilities.
-		 * Fix that.
+		
+		/* These chips, when reset, only advertise 10Mb
+		 * capabilities.  Fix that.
 		 */
 		err  = tg3_writephy(tp, MII_ADVERTISE,
 				    (ADVERTISE_CSMA |
-				     ADVERTISE_10HALF | ADVERTISE_10FULL |
-				     ADVERTISE_100HALF | ADVERTISE_100FULL));
+				     ADVERTISE_PAUSE_CAP |
+				     ADVERTISE_10HALF |
+				     ADVERTISE_10FULL |
+				     ADVERTISE_100HALF |
+				     ADVERTISE_100FULL));
 		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
 				MII_TG3_CTRL_ADV_1000_FULL |
 				MII_TG3_CTRL_AS_MASTER |
@@ -5150,6 +5854,22 @@
 				    (BMCR_ANRESTART | BMCR_ANENABLE));
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		tg3_writephy(tp, 0x1c, 0x8d68);
+		tg3_writephy(tp, 0x1c, 0x8d68);
+	}
+
+	/* Enable Ethernet@WireSpeed */
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
+	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
+
 	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
 		err = tg3_init_5401phy_dsp(tp);
 	}
@@ -5247,6 +5967,20 @@
 	u16 pci_cmd;
 	int err;
 
+	/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
+	 * reordering to the mailbox registers done by the host
+	 * controller can cause major troubles.  We read back from
+	 * every mailbox register write to force the writes to be
+	 * posted to the chip in order.
+	 */
+	if (pci_find_device(PCI_VENDOR_ID_INTEL,
+			    PCI_DEVICE_ID_INTEL_82801AA_8, NULL) ||
+	    pci_find_device(PCI_VENDOR_ID_INTEL,
+			    PCI_DEVICE_ID_INTEL_82801AB_8, NULL) ||
+	    pci_find_device(PCI_VENDOR_ID_AMD,
+			    PCI_DEVICE_ID_AMD_FE_GATE_700C, NULL))
+		tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
+
 	/* Force memory write invalidate off.  If we leave it on,
 	 * then on 5700_BX chips we have to enable a workaround.
 	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
@@ -5258,12 +5992,24 @@
 	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
 	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 
+	/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
+	 * has the register indirect write enable bit set before
+	 * we try to access any of the MMIO registers.  It is also
+	 * critical that the PCI-X hw workaround situation is decided
+	 * before that as well.
+	 */
 	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
 			      &misc_ctrl_reg);
 
 	tp->pci_chip_rev_id = (misc_ctrl_reg >>
 			       MISC_HOST_CTRL_CHIPREV_SHIFT);
 
+	/* Initialize misc host control in PCI block. */
+	tp->misc_host_ctrl |= (misc_ctrl_reg &
+			       MISC_HOST_CTRL_CHIPREV);
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
 	pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
 			      &cacheline_sz_reg);
 
@@ -5377,14 +6123,9 @@
 	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
 		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
-	/* Initialize misc host control in PCI block. */
-	tp->misc_host_ctrl |= (misc_ctrl_reg &
-			       MISC_HOST_CTRL_CHIPREV);
-	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-			       tp->misc_host_ctrl);
-
 	/* Initialize MAC MI mode, polling disabled. */
 	tw32(MAC_MI_MODE, tp->mi_mode);
+	tr32(MAC_MI_MODE);
 	udelay(40);
 
 	/* Initialize data/descriptor byte/word swapping. */
@@ -5439,9 +6180,16 @@
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 &&
 	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1)
 		return -ENODEV;
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
+		tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
+		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
+	}
+
 	/* ROFL, you should see Broadcom's driver code implementing
 	 * this, stuff like "if (a || b)" where a and b are always
 	 * mutually exclusive.  DaveM finds like 6 bugs today, hello!
@@ -5520,13 +6268,23 @@
 	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
 		tp->rx_offset = 0;
 
+	/* By default, disable wake-on-lan.  User can change this
+	 * using ETHTOOL_SWOL.
+	 */
+	tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+
 	return err;
 }
 
 static int __devinit tg3_get_device_address(struct tg3 *tp)
 {
 	struct net_device *dev = tp->dev;
-	u32 hi, lo;
+	u32 hi, lo, mac_offset;
+
+	if (PCI_FUNC(tp->pdev->devfn) == 0)
+		mac_offset = 0x7c;
+	else
+		mac_offset = 0xcc;
 
 	/* First try to get it from MAC address mailbox. */
 	tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
@@ -5541,8 +6299,8 @@
 		dev->dev_addr[5] = (lo >>  0) & 0xff;
 	}
 	/* Next, try NVRAM. */
-	else if (!tg3_nvram_read(tp, 0x7c, &hi) &&
-		 !tg3_nvram_read(tp, 0x80, &lo)) {
+	else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
+		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
 		dev->dev_addr[0] = ((hi >> 16) & 0xff);
 		dev->dev_addr[1] = ((hi >> 24) & 0xff);
 		dev->dev_addr[2] = ((lo >>  0) & 0xff);
@@ -5593,11 +6351,21 @@
 	if (to_device) {
 		test_desc.cqid_sqid = (13 << 8) | 2;
 		tw32(RDMAC_MODE, RDMAC_MODE_RESET);
+		tr32(RDMAC_MODE);
+		udelay(40);
+
 		tw32(RDMAC_MODE, RDMAC_MODE_ENABLE);
+		tr32(RDMAC_MODE);
+		udelay(40);
 	} else {
 		test_desc.cqid_sqid = (16 << 8) | 7;
 		tw32(WDMAC_MODE, WDMAC_MODE_RESET);
+		tr32(WDMAC_MODE);
+		udelay(40);
+
 		tw32(WDMAC_MODE, WDMAC_MODE_ENABLE);
+		tr32(WDMAC_MODE);
+		udelay(40);
 	}
 	test_desc.flags = 0x00000004;
 
@@ -5660,16 +6428,26 @@
 			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
 			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
 	} else {
-		tp->dma_rwctrl =
-			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
-			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
-			(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
-			(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
-			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x00 << DMA_RWCTRL_MIN_DMA_SHIFT);
+		else
+			tp->dma_rwctrl =
+				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
 
 		/* Wheee, some more chip bugs... */
 		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)
+		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 ||
+		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 ||
+		    tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
 			tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
 	}
 
@@ -5844,6 +6622,7 @@
 	case PHY_ID_BCM5411:	return "5411";
 	case PHY_ID_BCM5701:	return "5701";
 	case PHY_ID_BCM5703:	return "5703";
+	case PHY_ID_BCM5704:	return "5704";
 	case PHY_ID_BCM8002:	return "8002";
 	case PHY_ID_SERDES:	return "serdes";
 	default:		return "unknown";
@@ -5924,6 +6703,9 @@
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 	dev->vlan_rx_register = tg3_vlan_rx_register;
 	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
+#endif
+#if TG3_DO_TSO != 0
+	dev->features |= NETIF_F_TSO;
 #endif
 
 	tp = dev->priv;
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Sun Sep 15 19:19:29 2002
+++ b/drivers/net/tg3.h	Sun Sep 15 19:19:29 2002
@@ -58,6 +58,11 @@
 #define TG3PCI_MAX_LAT			0x0000003f
 #define TG3PCI_X_CAPS			0x00000040
 #define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
+#define  PCIX_CAPS_SPLIT_MASK		 0x00700000
+#define  PCIX_CAPS_SPLIT_SHIFT		 20
+#define  PCIX_CAPS_BURST_MASK		 0x000c0000
+#define  PCIX_CAPS_BURST_SHIFT		 18
+#define  PCIX_CAPS_MAX_BURST_5704	 2
 #define TG3PCI_PM_CAP_PTR		0x00000041
 #define TG3PCI_X_COMMAND		0x00000042
 #define TG3PCI_X_STATUS			0x00000044
@@ -109,10 +114,13 @@
 #define  CHIPREV_ID_5703_A0		 0x1000
 #define  CHIPREV_ID_5703_A1		 0x1001
 #define  CHIPREV_ID_5703_A2		 0x1002
+#define  CHIPREV_ID_5703_A3		 0x1003
+#define  CHIPREV_ID_5704_A0		 0x2000
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
 #define   ASIC_REV_5703			 0x01
+#define   ASIC_REV_5704			 0x02
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -165,6 +173,7 @@
 #define  PCISTATE_ROM_ENABLE		 0x00000020
 #define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
 #define  PCISTATE_FLAT_VIEW		 0x00000100
+#define  PCISTATE_RETRY_SAME_DMA	 0x00002000
 #define TG3PCI_CLOCK_CTRL		0x00000074
 #define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
 #define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
@@ -843,6 +852,8 @@
 #define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
 #define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
 #define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
+#define  RDMAC_MODE_SPLIT_RESET		 0x00001000
 #define RDMAC_STATUS			0x00004804
 #define  RDMAC_STATUS_TGTABORT		 0x00000004
 #define  RDMAC_STATUS_MSTABORT		 0x00000008
@@ -1126,6 +1137,8 @@
 #define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
 #define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
 #define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
+#define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
 #define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
 #define GRC_LOCAL_CTRL			0x00006808
 #define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
@@ -1248,14 +1261,19 @@
 #define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
 
 #define NIC_SRAM_DATA_CFG			0x00000b58
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x0000000c
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000004
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000008
-#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x0000000c
 #define  NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000010
-#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000020
+#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000008
+#define  NIC_SRAM_DATA_CFG_LED_OUTPUT		 0x00000008
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000010
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000020
+#define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
+#define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
+#define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
 
 #define NIC_SRAM_DATA_PHY_ID		0x00000b74
 #define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
@@ -1292,7 +1310,8 @@
 #define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
 #define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
 #define NIC_SRAM_MBUF_POOL_BASE		0x00008000
-#define  NIC_SRAM_MBUF_POOL_SIZE	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00018000
 
 /* Currently this is fixed. */
 #define PHY_ADDR		0x01
@@ -1410,6 +1429,7 @@
 
 	u32				vlan_tag;
 #define TXD_VLAN_TAG_SHIFT		0
+#define TXD_MSS_SHIFT			16
 };
 
 #define TXD_ADDR			0x00UL /* 64-bit */
@@ -1660,6 +1680,12 @@
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+struct tx_ring_info {
+	struct sk_buff			*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	u32				prev_vlan_tag;
+};
+
 struct tg3_config_info {
 	u32				flags;
 };
@@ -1737,11 +1763,13 @@
 #define TG3_FLAG_RX_CHECKSUMS		0x00000004
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
 #define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
+#define TG3_FLAG_ENABLE_ASF		0x00000020
 #define TG3_FLAG_POLL_SERDES		0x00000080
-#define TG3_FLAG_PHY_RESET_ON_INIT	0x00000100
+#define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
 #define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
 #define TG3_FLAG_WOL_SPEED_100MB	0x00000400
-#define TG3_FLAG_WOL_ENABLE		0x00001000
+#define TG3_FLAG_WOL_ENABLE		0x00000800
+#define TG3_FLAG_EEPROM_WRITE_PROT	0x00001000
 #define TG3_FLAG_NVRAM			0x00002000
 #define TG3_FLAG_NVRAM_BUFFERED		0x00004000
 #define TG3_FLAG_RX_PAUSE		0x00008000
@@ -1759,14 +1787,20 @@
 #define TG3_FLAG_PAUSE_TX		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
 #define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
+#define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 
 	u32				msg_enable;
 
+	u32				split_mode_max_reqs;
+#define SPLIT_MODE_5704_MAX_REQ		3
+
 	struct timer_list		timer;
 	u16				timer_counter;
 	u16				timer_multiplier;
 	u32				timer_offset;
+	u16				asf_counter;
+	u16				asf_multiplier;
 
 	struct tg3_link_config		link_config;
 	struct tg3_bufmgr_config	bufmgr_config;
@@ -1807,6 +1841,7 @@
 #define PHY_ID_BCM5411			0x60008070
 #define PHY_ID_BCM5701			0x60008110
 #define PHY_ID_BCM5703			0x60008160
+#define PHY_ID_BCM5704			0x60008190
 #define PHY_ID_BCM8002			0x60010140
 #define PHY_ID_SERDES			0xfeedbee0
 #define PHY_ID_INVALID			0xffffffff
@@ -1826,7 +1861,7 @@
 #define KNOWN_PHY_ID(X)		\
 	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
 	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
-	 (X) == PHY_ID_BCM5703 ||			   \
+	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
 	unsigned long			regs;
@@ -1853,7 +1888,7 @@
 
 	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
 	struct tg3_tx_buffer_desc	*tx_ring;
-	struct ring_info		*tx_buffers;
+	struct tx_ring_info		*tx_buffers;
 	dma_addr_t			tx_desc_mapping;
 
 	struct tg3_hw_status		*hw_status;
diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile	Sun Sep 15 19:20:23 2002
+++ b/drivers/pci/Makefile	Sun Sep 15 19:20:23 2002
@@ -6,10 +6,8 @@
 			probe.o proc.o search.o compat.o
 
 obj-y		+= access.o probe.o pci.o pool.o quirks.o \
-			compat.o names.o pci-driver.o search.o
+			compat.o names.o pci-driver.o search.o hotplug.o
 obj-$(CONFIG_PM)  += power.o
-obj-$(CONFIG_HOTPLUG)  += hotplug.o
-
 obj-$(CONFIG_PROC_FS) += proc.o
 
 ifndef CONFIG_SPARC64
diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
--- a/drivers/pci/hotplug.c	Sun Sep 15 19:20:23 2002
+++ b/drivers/pci/hotplug.c	Sun Sep 15 19:20:23 2002
@@ -7,8 +7,8 @@
 #define TRUE	(!FALSE)
 #endif
 
-static void
-run_sbin_hotplug(struct pci_dev *pdev, int insert)
+#ifdef CONFIG_HOTPLUG
+static void run_sbin_hotplug(struct pci_dev *pdev, int insert)
 {
 	int i;
 	char *argv[3], *envp[8];
@@ -45,13 +45,18 @@
 
 	call_usermodehelper (argv [0], argv, envp);
 }
+#else
+static void run_sbin_hotplug(struct pci_dev *pdev, int insert) { }
+#endif
 
 /**
- * pci_insert_device - insert a hotplug device
+ * pci_insert_device - insert a pci device
  * @dev: the device to insert
  * @bus: where to insert it
  *
- * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ * Link the device to both the global PCI device chain and the 
+ * per-bus list of devices, add the /proc entry, and notify
+ * userspace (/sbin/hotplug).
  */
 void
 pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
@@ -78,11 +83,11 @@
 }
 
 /**
- * pci_remove_device - remove a hotplug device
+ * pci_remove_device - remove a pci device
  * @dev: the device to remove
  *
- * Delete the device structure from the device lists and 
- * notify userspace (/sbin/hotplug).
+ * Delete the device structure from the device lists,
+ * remove the /proc entry, and notify userspace (/sbin/hotplug).
  */
 void
 pci_remove_device(struct pci_dev *dev)
@@ -94,10 +99,11 @@
 #ifdef CONFIG_PROC_FS
 	pci_proc_detach_device(dev);
 #endif
-
 	/* notify userspace of hotplug device removal */
 	run_sbin_hotplug(dev, FALSE);
 }
 
+#ifdef CONFIG_HOTPLUG
 EXPORT_SYMBOL(pci_insert_device);
 EXPORT_SYMBOL(pci_remove_device);
+#endif
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/pci/pci.c	Sun Sep 15 19:19:29 2002
@@ -240,25 +240,41 @@
 }
 
 /**
- * pci_enable_device - Initialize device before it's used by a driver.
+ * pci_enable_device_bars - Initialize some of a device for use
  * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
  *
  *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
+ *  to enable selected I/O and memory resources. Wake up the device if it 
+ *  was suspended. Beware, this function can fail.
  */
+ 
 int
-pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
 {
 	int err;
 
 	pci_set_power_state(dev, 0);
-	if ((err = pcibios_enable_device(dev)) < 0)
+	if ((err = pcibios_enable_device(dev, bars)) < 0)
 		return err;
 	return 0;
 }
 
 /**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	return pci_enable_device_bars(dev, 0x3F);
+}
+
+/**
  * pci_disable_device - Disable PCI device after use
  * @dev: PCI device to be disabled
  *
@@ -345,6 +361,69 @@
 }
 
 /**
+ *	pci_release_region - Release a PCI bar
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_region
+ *	@bar: BAR to release
+ *
+ *	Releases the PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_region.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_region(struct pci_dev *pdev, int bar)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return;
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		release_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		release_mem_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+}
+
+/**
+ *	pci_request_region - Reserved PCI I/O and memory resource
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@bar: BAR to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark the PCI region associated with PCI device @pdev BR @bar as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return 0;
+		
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+		if (!request_region(pci_resource_start(pdev, bar),
+			    pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+		if (!request_mem_region(pci_resource_start(pdev, bar),
+				        pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+		bar + 1, /* PCI BAR # */
+		pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+		pdev->slot_name);
+	return -EBUSY;
+}
+
+
+/**
  *	pci_release_regions - Release reserved PCI I/O and memory resources
  *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
  *
@@ -352,22 +431,13 @@
  *	successful call to pci_request_regions.  Call this function only
  *	after all use of the PCI regions has ceased.
  */
+
 void pci_release_regions(struct pci_dev *pdev)
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
-			release_region(pci_resource_start(pdev, i),
-				       pci_resource_len(pdev, i));
-
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
-			release_mem_region(pci_resource_start(pdev, i),
-					   pci_resource_len(pdev, i));
-	}
+	for (i = 0; i < 6; i++)
+		pci_release_region(pdev, i);
 }
 
 /**
@@ -387,23 +457,9 @@
 {
 	int i;
 	
-	for (i = 0; i < 6; i++) {
-		if (pci_resource_len(pdev, i) == 0)
-			continue;
-
-		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
-			if (!request_region(pci_resource_start(pdev, i),
-					    pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-		
-		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
-			if (!request_mem_region(pci_resource_start(pdev, i),
-					        pci_resource_len(pdev, i), res_name))
-				goto err_out;
-		}
-	}
-	
+	for (i = 0; i < 6; i++)
+		if(pci_request_region(pdev, i, res_name))
+			goto err_out;
 	return 0;
 
 err_out:
@@ -412,7 +468,9 @@
 		i + 1, /* PCI BAR # */
 		pci_resource_len(pdev, i), pci_resource_start(pdev, i),
 		pdev->slot_name);
-	pci_release_regions(pdev);
+	while(--i >= 0)
+		pci_release_region(pdev, i);
+		
 	return -EBUSY;
 }
 
@@ -589,6 +647,8 @@
 EXPORT_SYMBOL(pci_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_release_region);
+EXPORT_SYMBOL(pci_request_region);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Sun Sep 15 19:19:50 2002
+++ b/drivers/pci/pci.ids	Sun Sep 15 19:19:50 2002
@@ -5053,6 +5053,7 @@
 		14e4 000b  BCM5703 1000BaseTX
 		14e4 8009  BCM5703 1000BaseTX
 		14e4 800a  BCM5703 1000BaseTX
+	1648  NetXtreme BCM5704 Gigabit Ethernet
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/pci/probe.c	Sun Sep 15 19:19:29 2002
@@ -479,10 +479,10 @@
 
 		/*
 		 * Link the device to both the global PCI device chain and
-		 * the per-bus list of devices.
+		 * the per-bus list of devices and call /sbin/hotplug if we
+		 * should.
 		 */
-		list_add_tail(&dev->global_list, &pci_devices);
-		list_add_tail(&dev->bus_list, &bus->devices);
+		pci_insert_device (dev, bus);
 
 		/* Fix up broken headers */
 		pci_fixup_device(PCI_FIXUP_HEADER, dev);
@@ -594,4 +594,5 @@
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
+EXPORT_SYMBOL(pci_scan_bus);
 #endif
diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c	Sun Sep 15 19:19:50 2002
+++ b/drivers/pci/proc.c	Sun Sep 15 19:19:50 2002
@@ -18,6 +18,8 @@
 
 #define PCI_CFG_SPACE_SIZE 256
 
+static int proc_initialized;	/* = 0 */
+
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
@@ -410,6 +412,9 @@
 	struct proc_dir_entry *de, *e;
 	char name[16];
 
+	if (!proc_initialized)
+		return -EACCES;
+
 	if (!(de = bus->procdir)) {
 		sprintf(name, "%02x", bus->number);
 		de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir);
@@ -446,6 +451,9 @@
 {
 	struct proc_dir_entry *de = bus->procdir;
 
+	if (!proc_initialized)
+		return -EACCES;
+
 	if (!de) {
 		char name[16];
 		sprintf(name, "%02x", bus->number);
@@ -595,6 +603,7 @@
 		entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
 		if (entry)
 			entry->proc_fops = &proc_bus_pci_dev_operations;
+		proc_initialized = 1;
 		pci_for_each_dev(dev) {
 			pci_proc_attach_device(dev);
 		}
diff -Nru a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
--- a/drivers/pnp/pnpbios_core.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/pnp/pnpbios_core.c	Sun Sep 15 19:19:28 2002
@@ -1299,7 +1299,7 @@
 {
 #ifdef CONFIG_HOTPLUG	
 	init_completion(&unload_sem);
-	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
+	if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0)
 		unloading = 0;
 #endif		
 	return 0;
diff -Nru a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
--- a/drivers/s390/net/iucv.h	Sun Sep 15 19:19:46 2002
+++ b/drivers/s390/net/iucv.h	Sun Sep 15 19:19:46 2002
@@ -446,7 +446,7 @@
  *        buflen - Length of reply buffer.                              
  * Output: residual_buffer - Address of buffer updated by the number 
  *                    of bytes you have moved.              
- *         residual_length - Contains on the the following values
+ *         residual_length - Contains one of the following values:
  *		If the answer buffer is the same length as the reply, this field
  *		 contains zero.
  *		If the answer buffer is longer than the reply, this field contains
@@ -480,7 +480,7 @@
  *        buffer - Address of array of reply buffers.                     
  *        buflen - Total length of reply buffers.                         
  * Output: residual_buffer - Address of buffer which IUCV is currently working on.
- *         residual_length - Contains on the the following values
+ *         residual_length - Contains one of the following values:
  *              If the answer buffer is the same length as the reply, this field
  *               contains zero.
  *              If the answer buffer is longer than the reply, this field contains
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c	Sun Sep 15 19:19:39 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c	Sun Sep 15 19:19:39 2002
@@ -4274,7 +4274,7 @@
 	/*
 	 * DMA tag for our command fifos and other data in system memory
 	 * the card's sequencer must be able to access.  For initiator
-	 * roles, we need to allocate space for the the qinfifo and qoutfifo.
+	 * roles, we need to allocate space for the qinfifo and qoutfifo.
 	 * The qinfifo and qoutfifo are composed of 256 1 byte elements. 
 	 * When providing for the target mode role, we must additionally
 	 * provide space for the incoming target command fifo and an extra
@@ -6791,7 +6791,7 @@
 		panic("ahc_update_scsiid called on non-multitid unit\n");
 
 	/*
-	 * Since we will rely on the the TARGID mask
+	 * Since we will rely on the TARGID mask
 	 * for selection enables, ensure that OID
 	 * in SCSIID is not set to some other ID
 	 * that we don't want to allow selections on.
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Sun Sep 15 19:19:56 2002
+++ b/drivers/scsi/ide-scsi.c	Sun Sep 15 19:19:56 2002
@@ -33,6 +33,7 @@
 #define IDESCSI_VERSION "0.9"
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -61,8 +62,8 @@
 	int actually_transferred;		/* Bytes actually transferred */
 	int buffer_size;			/* Size of our data buffer */
 	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	struct scatterlist *sg;			/* Scatter gather table */
 	int b_count;				/* Bytes transferred from current entry */
 	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
@@ -95,6 +96,7 @@
 	unsigned long flags;			/* Status/Action flags */
 	unsigned long transform;		/* SCSI cmd translation layer */
 	unsigned long log;			/* log flags */
+	int id;
 } idescsi_scsi_t;
 
 /*
@@ -107,22 +109,16 @@
  */
 #define IDESCSI_PC_RQ			90
 
-/*
- *	Bits of the interrupt reason register.
- */
-#define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */
-#define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */
-
 static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 
 /*
@@ -202,8 +198,8 @@
 			c[2] = sc[2];
 			new_len = sc[4] + 4;
 			c[8] = new_len;
-			c[9] = sc[5];
 			c[7] = new_len >> 8;
+			c[9] = sc[5];
 			if (c[0] == MODE_SELECT_10) {
 				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
 				atapi_buf[2] = scsi_buf[1];	/* Medium type */
@@ -264,7 +260,7 @@
 	printk("]\n");
 }
 
-static int idescsi_end_request (ide_drive_t *drive, int uptodate)
+static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
@@ -275,7 +271,7 @@
 	unsigned long flags;
 
 	if (!(rq->flags & REQ_SPECIAL)) {
-		ide_end_request(drive, uptodate);
+		ide_end_request(drive, uptodate, nrsecs);
 		return 0;
 	}
 	ide_end_drive_cmd (drive, 0, 0);
@@ -303,8 +299,9 @@
 	spin_lock_irqsave(host->host_lock, flags);
 	pc->done(pc->scsi_cmd);
 	spin_unlock_irqrestore(host->host_lock, flags);
-	idescsi_free_bio (rq->bio);
-	kfree(pc); kfree(rq);
+	idescsi_free_bio(rq->bio);
+	kfree(pc);
+	kfree(rq);
 	scsi->pc = NULL;
 	return 0;
 }
@@ -320,10 +317,13 @@
 static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	byte status, ireason;
-	int bcount;
 	idescsi_pc_t *pc=scsi->pc;
 	struct request *rq = pc->rq;
+	atapi_bcount_t bcount;
+	atapi_status_t status;
+	atapi_ireason_t ireason;
+	atapi_feature_t feature;
+
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
@@ -335,32 +335,38 @@
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+		(void) HWIF(drive)->ide_dma_end(drive);
 	}
 
-	status = GET_STAT();						/* Clear the interrupt */
+	feature.all = 0;
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
+	if (!status.b.drq) {
+		/* No more interrupts */
 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
 			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 		local_irq_enable();
-		if (status & ERR_STAT)
+		if (status.b.check)
 			rq->errors++;
-		idescsi_end_request (drive, 1);
+		idescsi_end_request (drive, 1, 0);
 		return ide_stopped;
 	}
-	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
-	ireason = IN_BYTE (IDE_IREASON_REG);
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
 
-	if (ireason & IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+	if (ireason.b.cod) {
+		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
 		return ide_do_reset (drive);
 	}
-	if (ireason & IDESCSI_IREASON_IO) {
-		temp = pc->actually_transferred + bcount;
-		if ( temp > pc->request_transfer) {
+	if (ireason.b.io) {
+		temp = pc->actually_transferred + bcount.all;
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
+				printk(KERN_ERR "ide-scsi: The scsi wants to "
+					"send us more data than expected "
+					"- discarding data\n");
 				temp = pc->buffer_size - pc->actually_transferred;
 				if (temp) {
 					clear_bit(PC_WRITING, &pc->flags);
@@ -368,11 +374,11 @@
 						idescsi_input_buffers(drive, pc, temp);
 					else
 						atapi_input_bytes(drive, pc->current_position, temp);
-					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
+					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
 				}
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
-				idescsi_discard_data (drive,bcount - temp);
+				idescsi_discard_data(drive, bcount.all - temp);
 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 				return ide_started;
 			}
@@ -381,44 +387,51 @@
 #endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
-	if (ireason & IDESCSI_IREASON_IO) {
+	if (ireason.b.io) {
 		clear_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_input_buffers (drive, pc, bcount);
+			idescsi_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
 	} else {
 		set_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_output_buffers (drive, pc, bcount);
+			idescsi_output_buffers (drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
 	}
-	pc->actually_transferred+=bcount;				/* Update the current position */
-	pc->current_position+=bcount;
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
 
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
 
-static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive)
+static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
-	byte ireason;
+	atapi_ireason_t ireason;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-scsi: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason = IN_BYTE (IDE_IREASON_REG);
-	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
 		return ide_do_reset (drive);
 	}
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+	/* Send the actual packet */
+	atapi_output_bytes(drive, scsi->pc->c, 12);
 	return ide_started;
 }
 
@@ -428,36 +441,46 @@
 static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	int bcount;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	struct request *rq = pc->rq;
-	int dma_ok = 0;
 
 	scsi->pc=pc;							/* Set the current packet command */
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
-	if (drive->using_dma && rq->bio)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+	if (drive->using_dma && rq->bio) {
+		if (test_bit(PC_WRITING, &pc->flags))
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		else
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+	}
 
-	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_DRIVE(drive);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
-	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
-
-	if (dma_ok) {
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+
+	if (feature.b.dma) {
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+	}
+	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &idescsi_transfer_pc,
+				get_timeout(pc), NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idescsi_transfer_pc (drive);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idescsi_transfer_pc(drive);
 	}
 }
 
@@ -475,11 +498,17 @@
 		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
 	}
 	blk_dump_rq_flags(rq, "ide-scsi: unsup command");
-	idescsi_end_request (drive, 0);
+	idescsi_end_request (drive, 0, 0);
 	return ide_stopped;
 }
 
-static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
+static int idescsi_do_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	/* need to figure out how to parse scsi-atapi media type */
+	return -ENOTTY;
+}
+
+static int idescsi_ide_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -517,6 +546,7 @@
 	drive->ready_stat = 0;
 	memset (scsi, 0, sizeof (idescsi_scsi_t));
 	scsi->drive = drive;
+	scsi->id = id;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
 		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
@@ -531,14 +561,14 @@
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
 	drive->driver_data = NULL;
-	kfree (scsi);
+	kfree(scsi);
 	return 0;
 }
 
-static int idescsi_reinit(ide_drive_t *drive);
+static int idescsi_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -551,14 +581,14 @@
 	busy:			0,
 	supports_dma:		1,
 	supports_dsc_overlap:	0,
-	reinit:			idescsi_reinit,
+	attach:			idescsi_attach,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
 	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
-	ioctl:			NULL,
-	open:			idescsi_open,
+	ioctl:			idescsi_do_ioctl,
+	open:			idescsi_ide_open,
 	release:		idescsi_ide_release,
 	media_change:		NULL,
 	revalidate:		NULL,
@@ -569,7 +599,7 @@
 	drives:			LIST_HEAD_INIT(idescsi_driver.drives),
 };
 
-static int idescsi_reinit(ide_drive_t *drive)
+static int idescsi_attach(ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi;
 	int id;
diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
--- a/drivers/serial/sunsu.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/serial/sunsu.c	Sun Sep 15 19:19:29 2002
@@ -34,6 +34,7 @@
 #include <linux/serio.h>
 #endif
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -1018,6 +1019,8 @@
 
 	if (!up->port_node || !up->su_type)
 		return;
+
+	up->port.iotype = SERIAL_IO_MEM;
 
 	/*
 	 * First we look for Ebus-bases su's
diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
--- a/drivers/serial/sunzilog.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/serial/sunzilog.c	Sun Sep 15 19:20:24 2002
@@ -382,13 +382,6 @@
 			sun_do_break();
 			return;
 		}
-#ifndef CONFIG_SPARC64
-		/* Look for kgdb 'stop' character.  */
-		if (ZS_IS_KGDB(up) && (ch == '\003')) {
-			breakpoint();
-			return;
-		}
-#endif
 
 		/* A real serial line, record the character and status.  */
 		*tty->flip.char_buf_ptr = ch;
@@ -1152,11 +1145,11 @@
 static struct zilog_layout * __init get_zs_sun4cmd(int chip)
 {
 	struct linux_prom_irqs irq_info[2];
-	unsigned long mapped_addr;
-	int zsnode, chipid, cpunode;
+	unsigned long mapped_addr = 0;
+	int zsnode, chipid, cpunode, bbnode;
 
 	if (sparc_cpu_model == sun4d) {
-		int bbnode, walk, no;
+		int walk, no;
 
 		zsnode = 0;
 		bbnode = 0;
@@ -1249,7 +1242,7 @@
 		} else if (zilog_irq != irq_info[0].pri) {
 			prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n",
 				    chip);
-			promt_halt();
+			prom_halt();
 		}
 		break;
 	}
@@ -1290,7 +1283,7 @@
 		zilog_irq = 12;
 		res.end = (res.start + (8 - 1));
 		res.flags = IORESOURCE_IO;
-		return sbus_ioremap(&res, 0, 8, "SunZilog");
+		return (struct zilog_layout *) sbus_ioremap(&res, 0, 8, "SunZilog");
 	}
 
 	return get_zs_sun4cmd(chip);
@@ -1649,13 +1642,10 @@
 	/* Sun4 Zilog setup is hard coded, no probing to do.  */
 	if (sparc_cpu_model == sun4) {
 		NUM_SUNZILOG = 2;
-		goto no_probe;
-	}
-
-	node = prom_getchild(prom_root_node);
-	if (sparc_cpu_model == sun4d) {
+	} else if (sparc_cpu_model == sun4d) {
 		int bbnode;
 
+		node = prom_getchild(prom_root_node);
 		NUM_SUNZILOG = 0;
 		while (node &&
 		       (node = prom_searchsiblings(node, "cpu-unit"))) {
@@ -1664,7 +1654,6 @@
 				NUM_SUNZILOG += 2;
 			node = prom_getsibling(node);
 		}
-		goto no_probe;
 	} else if (sparc_cpu_model == sun4u) {
 		int central_node;
 
@@ -1675,26 +1664,27 @@
 		if (central_node != 0 && central_node != -1)
 			node = prom_searchsiblings(prom_getchild(central_node), "fhc");
 		else
-			node = prom_searchsiblings(node, "sbus");
+			node = prom_searchsiblings(prom_getchild(prom_root_node), "sbus");
 		if (node != 0 && node != -1)
 			node = prom_getchild(node);
 		if (node == 0 || node == -1)
 			return -ENODEV;
+
+		node = prom_searchsiblings(node, "zs");
+		if (!node)
+			return -ENODEV;
+		
+		NUM_SUNZILOG = 2;
 	} else {
+		node = prom_getchild(prom_root_node);
 		node = prom_searchsiblings(node, "obio");
 		if (node)
 			node = prom_getchild(node);
+		if (!node)
+			return -ENODEV;
+
 		NUM_SUNZILOG = 2;
-		goto no_probe;
 	}
-
-	node = prom_searchsiblings(node, "zs");
-	if (!node)
-		return -ENODEV;
-		
-	NUM_SUNZILOG = 2;
-
-no_probe:
 
 	sunzilog_alloc_tables();
 
diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
--- a/drivers/usb/class/usb-midi.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/usb/class/usb-midi.c	Sun Sep 15 19:19:28 2002
@@ -368,7 +368,7 @@
 {
 	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
 	unsigned char *data = urb->transfer_buffer;
-	int i, l, wake;
+	int i, j, wake;
 	unsigned long int flags;
 
 	if ( !ep->urbSubmitted ) {
@@ -379,14 +379,14 @@
 		wake = 0;
 		spin_lock_irqsave( &ep->lock, flags );
 
-		for(l = 0; l < urb->actual_length; l += 4) {
-			int cin = (data[l]>>0)&0xf;
-			int cab = (data[l]>>4)&0xf;
+		for(j = 0; j < urb->actual_length; j += 4) {
+			int cin = (data[j]>>0)&0xf;
+			int cab = (data[j]>>4)&0xf;
 			struct usb_mididev *cable = ep->cables[cab];
 			if ( cable ) {
 				int len = cin_to_len[cin]; /** length of MIDI data **/
 				for (i = 0; i < len; i++) {
-					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
 					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
 					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
 						cable->min.bufRemains += 1;
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Sun Sep 15 19:19:51 2002
+++ b/drivers/usb/core/hcd.c	Sun Sep 15 19:19:51 2002
@@ -1020,6 +1020,16 @@
 	if (status)
 		return status;
 
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which now controls it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
+	 */
+	urb = usb_get_urb (urb);
+	if (urb->dev == hcd->self.root_hub) {
+		urb->transfer_flags |= URB_NO_DMA_MAP;
+		return rh_urb_enqueue (hcd, urb);
+	}
+
 	/* lower level hcd code should use *_dma exclusively */
 	if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
 		if (usb_pipecontrol (urb->pipe))
@@ -1038,16 +1048,7 @@
 					    : PCI_DMA_TODEVICE);
 	}
 
-	/* increment urb's reference count as part of giving it to the HCD
-	 * (which now controls it).  HCD guarantees that it either returns
-	 * an error or calls giveback(), but not both.
-	 */
-	urb = usb_get_urb (urb);
-	if (urb->dev == hcd->self.root_hub)
-		status = rh_urb_enqueue (hcd, urb);
-	else
-		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	return status;
+	return hcd->driver->urb_enqueue (hcd, urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/core/inode.c	Sun Sep 15 19:19:29 2002
@@ -27,7 +27,6 @@
 
 /*****************************************************************************/
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -561,35 +560,57 @@
 static int create_special_files (void)
 {
 	struct dentry *parent;
-	int retval;
+	int retval = 0;
 
 	/* create the devices special file */
 	retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount);
-	if (retval)
-		return retval;
+	if (retval) {
+		err ("Unable to get usbdevfs mount");
+		goto exit;
+	}
+
 	retval = get_mount (&usb_fs_type, &usbfs_mount);
 	if (retval) {
-		put_mount (&usbfs_mount);
-		return retval;
+		err ("Unable to get usbfs mount");
+		goto error_clean_usbdevfs_mount;
 	}
+
 	parent = usbfs_mount->mnt_sb->s_root;
-	devices_usbfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent,
+	devices_usbfs_dentry = fs_create_file ("devices",
+					       listmode | S_IFREG, parent,
 					       NULL, &usbdevfs_devices_fops,
 					       listuid, listgid);
 	if (devices_usbfs_dentry == NULL) {
 		err ("Unable to create devices usbfs file");
-		return -ENODEV;
+		retval = -ENODEV;
+		goto error_clean_mounts;
 	}
+
 	parent = usbdevfs_mount->mnt_sb->s_root;
-	devices_usbdevfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent,
+	devices_usbdevfs_dentry = fs_create_file ("devices",
+						  listmode | S_IFREG, parent,
 						  NULL, &usbdevfs_devices_fops,
 						  listuid, listgid);
 	if (devices_usbdevfs_dentry == NULL) {
 		err ("Unable to create devices usbfs file");
-		return -ENODEV;
+		retval = -ENODEV;
+		goto error_remove_file;
 	}
 
-	return 0;
+	goto exit;
+	
+error_remove_file:
+	fs_remove_file (devices_usbfs_dentry);
+	devices_usbfs_dentry = NULL;
+
+error_clean_mounts:
+	put_mount (&usbfs_mount);
+
+error_clean_usbdevfs_mount:
+	put_mount (&usbdevfs_mount);	
+
+exit:
+	return retval;
 }
 
 static void remove_special_files (void)
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/host/ehci-dbg.c	Sun Sep 15 19:19:29 2002
@@ -57,7 +57,7 @@
 			strcat(buf, tmp);
 		}
 		dbg ("%s: %s portroute %s", 
-			ehci->hcd.self.bus_name, label,
+			hcd_to_bus (&ehci->hcd)->bus_name, label,
 			buf);
 	}
 }
@@ -122,7 +122,8 @@
 	}
 }
 
-static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
+static int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
 {
 	return snprintf (buf, len,
 		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
@@ -140,7 +141,8 @@
 		);
 }
 
-static int dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
+static int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
 {
 	return snprintf (buf, len,
 		"%s%sintrenable %02x%s%s%s%s%s%s",
@@ -213,19 +215,19 @@
 
 static inline int __attribute__((__unused__))
 dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
-{}
+{ return 0; }
 
 static inline int __attribute__((__unused__))
 dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
-{}
+{ return 0; }
 
 static inline int __attribute__((__unused__))
 dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
-{}
+{ return 0; }
 
 static inline int __attribute__((__unused__))
 dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
-{}
+{ return 0; }
 
 #endif	/* DEBUG */
 
@@ -248,7 +250,16 @@
 	dbg ("%s", _buf); \
 }
 
-#ifdef DEBUG
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ehci_hcd *bus) { }
+static inline void remove_debug_files (struct ehci_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in driverfs */
 
 #define speed_char(info1) ({ char tmp; \
 		switch (info1 & (3 << 12)) { \
@@ -258,6 +269,49 @@
 		default: tmp = '?'; break; \
 		}; tmp; })
 
+static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
+{
+	u32			scratch;
+	struct list_head	*entry;
+	struct ehci_qtd		*td;
+	unsigned		temp;
+	unsigned		size = *sizep;
+	char			*next = *nextp;
+
+	scratch = cpu_to_le32p (&qh->hw_info1);
+	temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x",
+			qh, scratch & 0x007f,
+			speed_char (scratch),
+			(scratch >> 8) & 0x000f,
+			scratch, cpu_to_le32p (&qh->hw_info2));
+	size -= temp;
+	next += temp;
+
+	list_for_each (entry, &qh->qtd_list) {
+		td = list_entry (entry, struct ehci_qtd,
+				qtd_list);
+		scratch = cpu_to_le32p (&td->hw_token);
+		temp = snprintf (next, size,
+				"\n\ttd/%p %s len=%d %08x urb %p",
+				td, ({ char *tmp;
+				 switch ((scratch>>8)&0x03) {
+				 case 0: tmp = "out"; break;
+				 case 1: tmp = "in"; break;
+				 case 2: tmp = "setup"; break;
+				 default: tmp = "?"; break;
+				 } tmp;}),
+				(scratch >> 16) & 0x7fff,
+				scratch,
+				td->urb);
+		size -= temp;
+		next += temp;
+	}
+
+	temp = snprintf (next, size, "\n");
+	*sizep = size - temp;
+	*nextp = next + temp;
+}
+
 static ssize_t
 show_async (struct device *dev, char *buf, size_t count, loff_t off)
 {
@@ -284,49 +338,21 @@
 	if (ehci->async) {
 		qh = ehci->async;
 		do {
-			u32			scratch;
-			struct list_head	*entry;
-			struct ehci_qtd		*td;
-
-			scratch = cpu_to_le32p (&qh->hw_info1);
-			temp = snprintf (next, size, "qh %p dev%d %cs ep%d",
-					qh, scratch & 0x007f,
-					speed_char (scratch),
-					(scratch >> 8) & 0x000f);
-			size -= temp;
-			next += temp;
-
-			list_for_each (entry, &qh->qtd_list) {
-				td = list_entry (entry, struct ehci_qtd,
-						qtd_list);
-				scratch = cpu_to_le32p (&td->hw_token);
-				temp = snprintf (next, size,
-						", td %p len=%d tok %04x %s",
-						td, scratch >> 16,
-						scratch & 0xffff,
-						({ char *tmp;
-						 switch ((scratch>>8)&0x03) {
-						 case 0: tmp = "out"; break;
-						 case 1: tmp = "in"; break;
-						 case 2: tmp = "setup"; break;
-						 default: tmp = "?"; break;
-						 } tmp;})
-						);
-				size -= temp;
-				next += temp;
-			}
-
-			temp = snprintf (next, size, "\n");
-			size -= temp;
-			next += temp;
-
+			qh_lines (qh, &next, &size);
 		} while ((qh = qh->qh_next.qh) != ehci->async);
 	}
+	if (ehci->reclaim) {
+		temp = snprintf (next, size, "\nreclaim =\n");
+		size -= temp;
+		next += temp;
+
+		qh_lines (ehci->reclaim, &next, &size);
+	}
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 	return count - size;
 }
-static DEVICE_ATTR (async, S_IRUSR, show_async, NULL);
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
 
 #define DBG_SCHED_LIMIT 64
 
@@ -373,7 +399,7 @@
 		do {
 			switch (tag) {
 			case Q_TYPE_QH:
-				temp = snprintf (next, size, " intr-%d %p",
+				temp = snprintf (next, size, " qh%d/%p",
 						p.qh->period, p.qh);
 				size -= temp;
 				next += temp;
@@ -387,12 +413,14 @@
 							&p.qh->hw_info1);
 
 					temp = snprintf (next, size,
-						" (%cs dev%d ep%d)",
+						" (%cs dev%d ep%d [%d/%d] %d)",
 						speed_char (scratch),
 						scratch & 0x007f,
-						(scratch >> 8) & 0x000f);
+						(scratch >> 8) & 0x000f,
+						p.qh->usecs, p.qh->c_usecs,
+						scratch >> 16);
 
-					/* FIXME TDs too */
+					/* FIXME TD info too */
 
 					if (seen_count < DBG_SCHED_LIMIT)
 						seen [seen_count++].qh = p.qh;
@@ -434,7 +462,7 @@
 
 	return count - size;
 }
-static DEVICE_ATTR (periodic, S_IRUSR, show_periodic, NULL);
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
 
 #undef DBG_SCHED_LIMIT
 
@@ -522,7 +550,7 @@
 
 	return count - size;
 }
-static DEVICE_ATTR (registers, S_IRUSR, show_registers, NULL);
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
 
 static inline void create_debug_files (struct ehci_hcd *bus)
 {
@@ -538,14 +566,5 @@
 	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers);
 }
 
-#else /* DEBUG */
-
-static inline void create_debug_files (struct ehci_hcd *bus)
-{
-}
-
-static inline void remove_debug_files (struct ehci_hcd *bus)
-{
-}
+#endif /* STUB_DEBUG_FILES */
 
-#endif /* DEBUG */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Sun Sep 15 19:19:57 2002
+++ b/drivers/usb/host/ehci-hcd.c	Sun Sep 15 19:19:57 2002
@@ -38,7 +38,13 @@
 #endif
 
 #include <linux/usb.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+#include "../hcd.h"
+#else
 #include "../core/hcd.h"
+#endif
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -87,7 +93,7 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-Aug-06"
+#define DRIVER_VERSION "2002-Aug-28"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -104,6 +110,9 @@
 #define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
 #define	EHCI_TUNE_MULT_TT	1
 
+#define EHCI_WATCHDOG_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_ASYNC_JIFFIES	(HZ/3)		/* async idle timeout */
+
 /* Initial IRQ latency:  lower than default */
 static int log2_irq_thresh = 0;		// 0 to 6
 MODULE_PARM (log2_irq_thresh, "i");
@@ -182,7 +191,7 @@
 	dbg_cmd (ehci, "reset", command);
 	writel (command, &ehci->regs->command);
 	ehci->hcd.state = USB_STATE_HALT;
-	return handshake (&ehci->regs->command, CMD_RESET, 0, 050);
+	return handshake (&ehci->regs->command, CMD_RESET, 0, 250);
 }
 
 /* idle the controller (from running) */
@@ -232,6 +241,24 @@
 
 static void ehci_tasklet (unsigned long param);
 
+static void ehci_irq (struct usb_hcd *hcd);
+
+static void ehci_watchdog (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	/* guard against lost IAA, which wedges everything */
+	ehci_irq (&ehci->hcd);
+ 	/* unlink the last qh after it's idled a while */
+ 	if (ehci->async_idle) {
+ 		start_unlink_async (ehci, ehci->async);
+ 		ehci->async_idle = 0;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
 /* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
  * off the controller (maybe it can boot from highspeed USB disks).
  */
@@ -267,6 +294,7 @@
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	struct usb_device	*udev;
+	struct usb_bus		*bus;
 	int			retval;
 	u32			hcc_params;
 	u8                      tempbyte;
@@ -346,6 +374,7 @@
 	 *
 	 * NOTE:  layered drivers can't yet tell when we enable that,
 	 * so they can't pass this info along (like NETIF_F_HIGHDMA)
+	 * (or like Scsi_Host.highmem_io) ... usb_bus.flags?
 	 */
 	if (HCC_64BIT_ADDR (hcc_params)) {
 		writel (0, &ehci->regs->segment);
@@ -372,16 +401,19 @@
 	ehci->tasklet.func = ehci_tasklet;
 	ehci->tasklet.data = (unsigned long) ehci;
 
+	init_timer (&ehci->watchdog);
+	ehci->watchdog.function = ehci_watchdog;
+	ehci->watchdog.data = (unsigned long) ehci;
+
 	/* wire up the root hub */
-	hcd->self.root_hub = udev = usb_alloc_dev (NULL, &hcd->self);
+	bus = hcd_to_bus (hcd);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
 	if (!udev) {
 done2:
 		ehci_mem_cleanup (ehci);
 		return -ENOMEM;
 	}
 
-	create_debug_files (ehci);
-
 	/*
 	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
 	 * are explicitly handed to companion controller(s), so no TT is
@@ -394,7 +426,7 @@
         /* PCI Serial Bus Release Number is at 0x60 offset */
 	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
 	temp = readw (&ehci->caps->hci_version);
-	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
+	info ("USB %x.%x support enabled, EHCI rev %x.%02x",
 	      ((tempbyte & 0xf0)>>4),
 	      (tempbyte & 0x0f),
 	       temp >> 8,
@@ -409,16 +441,22 @@
 	 */
 	usb_connect (udev);
 	udev->speed = USB_SPEED_HIGH;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+	if (usb_new_device (udev) != 0) {
+#else
 	if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) {
+#endif
 		if (hcd->state == USB_STATE_RUNNING)
 			ehci_ready (ehci);
 		ehci_reset (ehci);
-		hcd->self.root_hub = 0;
+		bus->root_hub = 0;
 		usb_free_dev (udev); 
 		retval = -ENODEV;
 		goto done2;
 	}
 
+	create_debug_files (ehci);
+
 	return 0;
 }
 
@@ -428,13 +466,20 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 
-	dbg ("%s: stop", hcd->self.bus_name);
+	dbg ("%s: stop", hcd_to_bus (hcd)->bus_name);
 
 	/* no more interrupts ... */
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
+	if (in_interrupt ())		/* should not happen!! */
+		err ("stopped %s!", RUN_CONTEXT);
+	else
+		del_timer_sync (&ehci->watchdog);
 	ehci_reset (ehci);
 
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+
 	remove_debug_files (ehci);
 
 	/* root hub is shut down separately (first, when possible) */
@@ -463,7 +508,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: suspend to %d", hcd->self.bus_name, state);
+	dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -480,7 +525,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_OWNER) != 0)
 			continue;
-dbg ("%s: suspend port %d", hcd->self.bus_name, i);
+dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
 		temp |= PORT_SUSPEND;
 		writel (temp, &ehci->regs->port_status [i]);
 	}
@@ -502,7 +547,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: resume", hcd->self.bus_name);
+	dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -522,7 +567,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_SUSPEND) != 0)
 			continue;
-dbg ("%s: resume port %d", hcd->self.bus_name, i);
+dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
 		temp |= PORT_RESUME;
 		writel (temp, &ehci->regs->port_status [i]);
 		readl (&ehci->regs->command);	/* unblock posted writes */
@@ -546,12 +591,21 @@
 static void ehci_tasklet (unsigned long param)
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+	unsigned long		flags;
+
+	// FIXME don't pass flags; on sparc they aren't really flags.
+	// qh_completions can just leave irqs blocked,
+	// then have scan_async() allow IRQs if it's very busy 
+
+	spin_lock_irqsave (&ehci->lock, flags);
 
 	if (ehci->reclaim_ready)
-		end_unlink_async (ehci);
-	scan_async (ehci);
+		flags = end_unlink_async (ehci, flags);
+	flags = scan_async (ehci, flags);
 	if (ehci->next_uframe != -1)
-		scan_periodic (ehci);
+		flags = scan_periodic (ehci, flags);
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -564,7 +618,7 @@
 
 	/* e.g. cardbus physical eject */
 	if (status == ~(u32) 0) {
-		dbg ("%s: device removed!", hcd->self.bus_name);
+		dbg ("%s: device removed!", hcd_to_bus (hcd)->bus_name);
 		goto dead;
 	}
 
@@ -597,7 +651,7 @@
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
 		err ("%s: fatal error, state %x",
-			hcd->self.bus_name, hcd->state);
+			hcd_to_bus (hcd)->bus_name, hcd->state);
 dead:
 		ehci_reset (ehci);
 		/* generic layer kills/unlinks all urbs, then
@@ -673,7 +727,7 @@
 	unsigned long		flags;
 
 	dbg ("%s urb_dequeue %p qh %p state %d",
-		hcd->self.bus_name, urb, qh, qh->qh_state);
+		hcd_to_bus (hcd)->bus_name, urb, qh, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
@@ -681,7 +735,13 @@
 	default:
 		spin_lock_irqsave (&ehci->lock, flags);
 		if (ehci->reclaim) {
-			dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			dbg ("dq %p: reclaim = %p, %s",
+				qh, ehci->reclaim, RUN_CONTEXT);
+			if (qh == ehci->reclaim) {
+				/* unlinking qh for another queued urb? */
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				return 0;
+			}
 			if (in_interrupt ()) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
 				return -EAGAIN;
@@ -702,19 +762,19 @@
 		break;
 
 	case PIPE_INTERRUPT:
+		spin_lock_irqsave (&ehci->lock, flags);
 		if (qh->qh_state == QH_STATE_LINKED) {
 			/* messy, can spin or block a microframe ... */
-			intr_deschedule (ehci, qh, 1);
+			flags = intr_deschedule (ehci, qh, 1, flags);
 			/* qh_state == IDLE */
 		}
-		qh_completions (ehci, qh);
+		flags = qh_completions (ehci, qh, flags);
 
 		/* reschedule QH iff another request is queued */
 		if (!list_empty (&qh->qtd_list)
 				&& HCD_IS_RUNNING (ehci->hcd.state)) {
 			int status;
 
-			spin_lock_irqsave (&ehci->lock, flags);
 			status = qh_schedule (ehci, qh);
 			spin_unlock_irqrestore (&ehci->lock, flags);
 
@@ -726,7 +786,7 @@
 			}
 			return status;
 		}
-
+		spin_unlock_irqrestore (&ehci->lock, flags);
 		break;
 
 	case PIPE_ISOCHRONOUS:
@@ -754,7 +814,8 @@
 	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
+	dbg ("%s: free_config devnum %d",
+		hcd_to_bus (hcd)->bus_name, udev->devnum);
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < 32; i++) {
@@ -775,7 +836,8 @@
 				why = 0;
 			if (why) {
 				err ("dev %s-%s ep %d-%s error: %s",
-					hcd->self.bus_name, udev->devpath,
+					hcd_to_bus (hcd)->bus_name,
+					udev->devpath,
 					i & 0xf, (i & 0x10) ? "IN" : "OUT",
 					why);
 				BUG ();
@@ -805,8 +867,7 @@
 				start_unlink_async (ehci, qh);
 			while (qh->qh_state != QH_STATE_IDLE
 					&& ehci->hcd.state != USB_STATE_HALT) {
-				spin_unlock_irqrestore (&ehci->lock,
-					flags);
+				spin_unlock_irqrestore (&ehci->lock, flags);
 				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
--- a/drivers/usb/host/ehci-hub.c	Sun Sep 15 19:19:37 2002
+++ b/drivers/usb/host/ehci-hub.c	Sun Sep 15 19:19:37 2002
@@ -41,14 +41,17 @@
 	/* if reset finished and it's still not enabled -- handoff */
 	if (!(port_status & PORT_PE)) {
 		dbg ("%s port %d full speed, give to companion, 0x%x",
-			ehci->hcd.self.bus_name, index + 1, port_status);
+			hcd_to_bus (&ehci->hcd)->bus_name,
+			index + 1, port_status);
 
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		writel (port_status, &ehci->regs->port_status [index]);
 
 	} else
-		dbg ("%s port %d high speed", ehci->hcd.self.bus_name, index + 1);
+		dbg ("%s port %d high speed",
+			hcd_to_bus (&ehci->hcd)->bus_name,
+			index + 1);
 
 	return port_status;
 }
@@ -310,11 +313,13 @@
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
 					&& PORT_USB11 (temp)) {
 				dbg ("%s port %d low speed, give to companion",
-					hcd->self.bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
 				vdbg ("%s port %d reset",
-					hcd->self.bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_RESET;
 				temp &= ~PORT_PE;
 
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/host/ehci-q.c	Sun Sep 15 19:19:29 2002
@@ -26,8 +26,7 @@
  * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
  * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
  * buffers needed for the larger number).  We use one QH per endpoint, queue
- * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
- * A scheduled interrupt qh always (for now) has one qtd, one urb.
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
  *
  * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
  * interrupts) needs careful scheduling.  Performance improvements can be
@@ -161,9 +160,10 @@
 
 /* urb->lock ignored from here on (hcd is done with urb) */
 
-static void ehci_urb_done (
+static unsigned long ehci_urb_done (
 	struct ehci_hcd		*ehci,
-	struct urb		*urb
+	struct urb		*urb,
+	unsigned long		flags
 ) {
 #ifdef	INTR_AUTOMAGIC
 	struct urb		*resubmit = 0;
@@ -177,7 +177,7 @@
 		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
 
 			/* ... update hc-wide periodic stats (for usbfs) */
-			ehci->hcd.self.bandwidth_int_reqs--;
+			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
 
 #ifdef	INTR_AUTOMAGIC
 			if (!((urb->status == -ENOENT)
@@ -199,6 +199,8 @@
 			urb->status = 0;
 	}
 
+	/* complete() can reenter this HCD */
+	spin_unlock_irqrestore (&ehci->lock, flags);
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
 
 #ifdef	INTR_AUTOMAGIC
@@ -212,34 +214,32 @@
 		int	status;
 
 		resubmit->dev = dev;
-		status = usb_submit_urb (resubmit, SLAB_KERNEL);
+		status = SUBMIT_URB (resubmit, SLAB_KERNEL);
 		if (status != 0)
 			err ("can't resubmit interrupt urb %p: status %d",
 					resubmit, status);
 		usb_put_urb (resubmit);
 	}
 #endif
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	return flags;
 }
 
 
 /*
- * Process completed qtds for a qh, issuing completions if needed.
- * Frees qtds, unmaps buf, returns URB to driver.
- * Races up to qh->hw_current; returns number of urb completions.
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current, returns irqsave flags (maybe modified).
  */
-static void
-qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static unsigned long
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, unsigned long flags)
 {
 	struct ehci_qtd		*qtd, *last;
 	struct list_head	*next, *qtd_list = &qh->qtd_list;
 	int			unlink = 0, halted = 0;
-	unsigned long		flags;
 
-	spin_lock_irqsave (&ehci->lock, flags);
-	if (unlikely (list_empty (qtd_list))) {
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		return;
-	}
+	if (unlikely (list_empty (qtd_list)))
+		return flags;
 
 	/* scan QTDs till end of list, or we reach an active one */
 	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
@@ -252,12 +252,8 @@
 
 		/* clean up any state from previous QTD ...*/
 		if (last) {
-			if (likely (last->urb != urb)) {
-				/* complete() can reenter this HCD */
-				spin_unlock_irqrestore (&ehci->lock, flags);
-				ehci_urb_done (ehci, last->urb);
-				spin_lock_irqsave (&ehci->lock, flags);
-			}
+			if (likely (last->urb != urb))
+				flags = ehci_urb_done (ehci, last->urb, flags);
 
 			/* qh overlays can have HC's old cached copies of
 			 * next qtd ptrs, if an URB was queued afterwards.
@@ -283,6 +279,14 @@
 			|| (ehci->hcd.state == USB_STATE_HALT)
 			|| (qh->qh_state == QH_STATE_IDLE);
 
+		// FIXME Remove the automagic unlink mode.
+		// Drivers can now clean up safely; it's their job.
+		//
+		// FIXME Removing it should fix the short read scenarios
+		// with "huge" urb data (more than one 16+KByte td) with
+		// the short read someplace other than the last data TD.
+		// Except the control case: 'retrigger' status ACKs.
+
 		/* fault: unlink the rest, since this qtd saw an error? */
 		if (unlikely ((token & QTD_STS_HALT) != 0)) {
 			unlink = 1;
@@ -341,18 +345,19 @@
 #endif
 	}
 
-	/* patch up list head? */
+	/* last urb's completion might still need calling */
+	if (likely (last != 0)) {
+		flags = ehci_urb_done (ehci, last->urb, flags);
+		ehci_qtd_free (ehci, last);
+	}
+
+	/* reactivate queue after error and driver's cleanup */
 	if (unlikely (halted && !list_empty (qtd_list))) {
 		qh_update (qh, list_entry (qtd_list->next,
 				struct ehci_qtd, qtd_list));
 	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
 
-	/* last urb's completion might still need calling */
-	if (likely (last != 0)) {
-		ehci_urb_done (ehci, last->urb);
-		ehci_qtd_free (ehci, last);
-	}
+	return flags;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -367,31 +372,12 @@
 	struct list_head	*qtd_list
 ) {
 	struct list_head	*entry, *temp;
-	int			unmapped = 0;
 
 	list_for_each_safe (entry, temp, qtd_list) {
 		struct ehci_qtd	*qtd;
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		list_del (&qtd->qtd_list);
-		if (unmapped != 2) {
-			int	direction;
-			size_t	size;
-
-			/* for ctrl unmap twice: SETUP and DATA;
-			 * else (bulk, intr) just once: DATA
-			 */
-			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
-				direction = PCI_DMA_TODEVICE;
-				size = sizeof (struct usb_ctrlrequest);
-			} else {
-				direction = usb_pipein (urb->pipe)
-					? PCI_DMA_FROMDEVICE
-					: PCI_DMA_TODEVICE;
-				size = qtd->urb->transfer_buffer_length;
-				unmapped++;
-			}
-		}
 		ehci_qtd_free (ehci, qtd);
 	}
 }
@@ -409,7 +395,7 @@
 	struct ehci_qtd		*qtd, *qtd_prev;
 	dma_addr_t		buf;
 	int			len, maxpacket;
-	int			is_input;
+	int			is_input, status_patch = 0;
 	u32			token;
 
 	/*
@@ -440,6 +426,9 @@
 		qtd->urb = urb;
 		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
 		list_add_tail (&qtd->qtd_list, head);
+
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			status_patch = 1;
 	} 
 
 	/*
@@ -517,6 +506,19 @@
 		}
 	}
 
+	/* if we're permitting a short control read, we want the hardware to
+	 * just continue after short data and send the status ack.  it can do
+	 * that on the last data packet (typically the only one).  for other
+	 * packets, software fixup is needed (in qh_completions).
+	 */
+	if (status_patch) {
+		struct ehci_qtd		*prev;
+
+		prev = list_entry (qtd->qtd_list.prev,
+				struct ehci_qtd, qtd_list);
+		prev->hw_alt_next = QTD_NEXT (qtd->qtd_dma);
+	}
+
 	/* by default, enable interrupt on urb completion */
 	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
 		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
@@ -670,10 +672,9 @@
 			info2 |= hb_mult (maxp) << 30;
 		}
 		break;
-#ifdef DEBUG
 	default:
-		BUG ();
-#endif
+ 		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ 		return 0;
 	}
 
 	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
@@ -735,6 +736,8 @@
 	}
 	qh->qh_state = QH_STATE_LINKED;
 	/* qtd completions reported later by interrupt */
+
+	ehci->async_idle = 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -855,11 +858,12 @@
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
 	dev = (struct hcd_dev *)urb->dev->hcpriv;
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
+	if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
 		epnum |= 0x10;
 
 	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
+		hcd_to_bus (&ehci->hcd)->bus_name,
+		urb, urb->transfer_buffer_length,
 		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
 		qtd, dev ? dev->ep [epnum] : (void *)~0);
 
@@ -886,25 +890,28 @@
 /* the async qh for the qtds being reclaimed are now unlinked from the HC */
 /* caller must not own ehci->lock */
 
-static void end_unlink_async (struct ehci_hcd *ehci)
+static unsigned long
+end_unlink_async (struct ehci_hcd *ehci, unsigned long flags)
 {
 	struct ehci_qh		*qh = ehci->reclaim;
 
+	del_timer (&ehci->watchdog);
+
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_next.qh = 0;
 	qh_put (ehci, qh);			// refcount from reclaim 
 	ehci->reclaim = 0;
 	ehci->reclaim_ready = 0;
 
-	qh_completions (ehci, qh);
+	flags = qh_completions (ehci, qh, flags);
 
-	// unlink any urb should now unlink all following urbs, so that
-	// relinking only happens for urbs before the unlinked ones.
 	if (!list_empty (&qh->qtd_list)
 			&& HCD_IS_RUNNING (ehci->hcd.state))
 		qh_link_async (ehci, qh);
 	else
 		qh_put (ehci, qh);		// refcount from async list
+
+	return flags;
 }
 
 
@@ -937,9 +944,11 @@
 	if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
 		/* can't get here without STS_ASS set */
 		if (ehci->hcd.state != USB_STATE_HALT) {
-			if (cmd & CMD_PSE)
+			if (cmd & CMD_PSE) {
 				writel (cmd & ~CMD_ASE, &ehci->regs->command);
-			else
+				(void) handshake (&ehci->regs->status,
+						  STS_ASS, 0, 150);
+			} else
 				ehci_ready (ehci);
 		}
 		qh->qh_next.qh = ehci->async = 0;
@@ -958,10 +967,6 @@
 	prev = ehci->async;
 	while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
 		prev = prev->qh_next.qh;
-#ifdef DEBUG
-	if (prev->qh_next.qh != qh)
-		BUG ();
-#endif
 
 	if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
 		ehci->async = prev;
@@ -975,16 +980,17 @@
 	cmd |= CMD_IAAD;
 	writel (cmd, &ehci->regs->command);
 	/* posted write need not be known to HC yet ... */
+
+	mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES);
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void scan_async (struct ehci_hcd *ehci)
+static unsigned long
+scan_async (struct ehci_hcd *ehci, unsigned long flags)
 {
 	struct ehci_qh		*qh;
-	unsigned long		flags;
 
-	spin_lock_irqsave (&ehci->lock, flags);
 rescan:
 	qh = ehci->async;
 	if (likely (qh != 0)) {
@@ -993,26 +999,25 @@
 			if (!list_empty (&qh->qtd_list)) {
 				// dbg_qh ("scan_async", ehci, qh);
 				qh = qh_get (qh);
-				spin_unlock_irqrestore (&ehci->lock, flags);
 
 				/* concurrent unlink could happen here */
-				qh_completions (ehci, qh);
-
-				spin_lock_irqsave (&ehci->lock, flags);
+				flags = qh_completions (ehci, qh, flags);
 				qh_put (ehci, qh);
 			}
 
 			/* unlink idle entries, reducing HC PCI usage as
-			 * well as HCD schedule-scanning costs
+			 * well as HCD schedule-scanning costs.  removing
+			 * the last qh is deferred, since it's costly.
 			 */
 			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
 				if (qh->qh_next.qh != qh) {
 					// dbg ("irq/empty");
 					start_unlink_async (ehci, qh);
-				} else {
-					// FIXME:  arrange to stop
-					// after it's been idle a while.
-					// stop/restart isn't free...
+				} else if (!timer_pending (&ehci->watchdog)) {
+					/* can't use IAA for last entry */
+					ehci->async_idle = 1;
+					mod_timer (&ehci->watchdog,
+						jiffies + EHCI_ASYNC_JIFFIES);
 				}
 			}
 			qh = qh->qh_next.qh;
@@ -1020,6 +1025,5 @@
 				goto rescan;
 		} while (qh != ehci->async);
 	}
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	return flags;
 }
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Sun Sep 15 19:19:30 2002
+++ b/drivers/usb/host/ehci-sched.c	Sun Sep 15 19:19:30 2002
@@ -222,17 +222,15 @@
 
 // FIXME microframe periods not yet handled
 
-static void intr_deschedule (
+static unsigned long intr_deschedule (
 	struct ehci_hcd	*ehci,
 	struct ehci_qh	*qh,
-	int		wait
+	int		wait,
+	unsigned long	flags
 ) {
-	unsigned long	flags;
 	int		status;
 	unsigned	frame = qh->start;
 
-	spin_lock_irqsave (&ehci->lock, flags);
-
 	do {
 		periodic_unlink (ehci, frame, qh);
 		qh_put (ehci, qh);
@@ -251,8 +249,6 @@
 		vdbg ("periodic schedule still enabled");
 	}
 
-	spin_unlock_irqrestore (&ehci->lock, flags);
-
 	/*
 	 * If the hc may be looking at this qh, then delay a uframe
 	 * (yeech!) to be sure it's done.
@@ -260,8 +256,10 @@
 	 */
 	if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
 		if (wait) {
+			spin_unlock_irqrestore (&ehci->lock, flags);
 			udelay (125);
 			qh->hw_next = EHCI_LIST_END;
+			spin_lock_irqsave (&ehci->lock, flags);
 		} else {
 			/* we may not be IDLE yet, but if the qh is empty
 			 * the race is very short.  then if qh also isn't
@@ -275,12 +273,13 @@
 	qh->qh_state = QH_STATE_IDLE;
 
 	/* update per-qh bandwidth utilization (for usbfs) */
-	ehci->hcd.self.bandwidth_allocated -= 
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= 
 		(qh->usecs + qh->c_usecs) / qh->period;
 
 	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
 		qh, qh->period, frame,
 		atomic_read (&qh->refcount), ehci->periodic_sched);
+	return flags;
 }
 
 static int check_period (
@@ -436,7 +435,7 @@
 	} while (frame < ehci->periodic_size);
 
 	/* update per-qh bandwidth for usbfs */
-	ehci->hcd.self.bandwidth_allocated += 
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated += 
 		(qh->usecs + qh->c_usecs) / qh->period;
 
 	/* maybe enable periodic schedule processing */
@@ -486,7 +485,7 @@
 	BUG_ON (qh == 0);
 
 	/* ... update usbfs periodic stats */
-	ehci->hcd.self.bandwidth_int_reqs++;
+	hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++;
 
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -513,12 +512,10 @@
 	}
 	
 	/* handle any completions */
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	qh_completions (ehci, qh);
-	spin_lock_irqsave (&ehci->lock, flags);
+	flags = qh_completions (ehci, qh, flags);
 
 	if (unlikely (list_empty (&qh->qtd_list)))
-		intr_deschedule (ehci, qh, 0);
+		flags = intr_deschedule (ehci, qh, 0, flags);
 
 	return flags;
 }
@@ -974,130 +971,20 @@
 /*
  * "Split ISO TDs" ... used for USB 1.1 devices going through
  * the TTs in USB 2.0 hubs.
+ *
+ * FIXME not yet implemented
  */
 
-static void
-sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
-{
-	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
-}
-
-static struct ehci_sitd *
-sitd_make (
-	struct ehci_hcd	*ehci,
-	struct urb	*urb,
-	unsigned	index,		// urb->iso_frame_desc [index]
-	unsigned	uframe,		// scheduled start
-	dma_addr_t	dma,		// mapped transfer buffer
-	int		mem_flags
-) {
-	struct ehci_sitd	*sitd;
-	unsigned		length;
-
-	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
-	if (!sitd)
-		return sitd;
-	sitd->urb = urb;
-	length = urb->iso_frame_desc [index].length;
-	dma += urb->iso_frame_desc [index].offset;
-
-#if 0
-	// FIXME:  do the rest!
-#else
-	sitd_free (ehci, sitd);
-	return 0;
-#endif
-
-}
-
-static void
-sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
-{
-	u32		ptr;
-
-	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd
-	if (ehci->pshadow [frame].ptr) {
-		if (!sitd->sitd_next.ptr) {
-			sitd->sitd_next = ehci->pshadow [frame];
-			sitd->hw_next = ehci->periodic [frame];
-		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
-			dbg ("frame %d sitd link goof", frame);
-			BUG ();
-		}
-	}
-	ehci->pshadow [frame].sitd = sitd;
-	ehci->periodic [frame] = ptr;
-}
-
-static unsigned long
-sitd_complete (
-	struct ehci_hcd *ehci,
-	struct ehci_sitd	*sitd,
-	unsigned long		flags
-) {
-	// FIXME -- implement!
-
-	dbg ("NYI -- sitd_complete");
-	return flags;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
-{
-	// struct ehci_sitd	*first_sitd = 0;
-	unsigned		frame_index;
-	dma_addr_t		dma;
-
-	dbg ("NYI -- sitd_submit");
-
-	// FIXME -- implement!
-
-	// FIXME:  setup one big dma mapping
-	dma = 0;
-
-	for (frame_index = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		struct ehci_sitd	*sitd;
-		unsigned		uframe;
-
-		// FIXME:  use real arguments, schedule this!
-		uframe = -1;
-
-		sitd = sitd_make (ehci, urb, frame_index,
-				uframe, dma, mem_flags);
-
-		if (sitd) {
-    /*
-			if (first_sitd)
-				list_add_tail (&sitd->sitd_list,
-						&first_sitd->sitd_list);
-			else
-				first_sitd = sitd;
-    */
-		} else {
-			// FIXME:  clean everything up
-		}
-	}
-
-	// if we have a first sitd, then
-		// store them all into the periodic schedule!
-		// urb->hcpriv = first sitd in sitd_list
-
-	return -ENOSYS;
-}
 #endif /* have_split_iso */
 
 /*-------------------------------------------------------------------------*/
 
-static void scan_periodic (struct ehci_hcd *ehci)
+static unsigned long
+scan_periodic (struct ehci_hcd *ehci, unsigned long flags)
 {
 	unsigned	frame, clock, now_uframe, mod;
-	unsigned long	flags;
 
 	mod = ehci->periodic_size << 3;
-	spin_lock_irqsave (&ehci->lock, flags);
 
 	/*
 	 * When running, scan from last scan point up to "now"
@@ -1237,5 +1124,5 @@
 		} else
 			frame = (frame + 1) % ehci->periodic_size;
 	} 
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	return flags;
 }
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Sun Sep 15 19:20:20 2002
+++ b/drivers/usb/host/ehci.h	Sun Sep 15 19:20:20 2002
@@ -39,7 +39,8 @@
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
-	int			reclaim_ready;
+	int			reclaim_ready : 1,
+				async_idle : 1;
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
@@ -69,6 +70,8 @@
 	struct pci_pool		*qtd_pool;	/* one or more per qh */
 	struct pci_pool		*itd_pool;	/* itd per iso urb */
 	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+
+	struct timer_list	watchdog;
 };
 
 /* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
@@ -388,5 +391,28 @@
 	dma_addr_t		fstn_dma;
 	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
 } __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
+#define STUB_DEBUG_FILES
+
+#else	/* LINUX_VERSION_CODE */
+
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+	{ return &hcd->self; }
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+#endif	/* LINUX_VERSION_CODE */
+
+/*-------------------------------------------------------------------------*/
 
 #endif /* __LINUX_EHCI_HCD_H */
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Sun Sep 15 19:20:23 2002
+++ b/drivers/usb/host/ohci-dbg.c	Sun Sep 15 19:20:23 2002
@@ -72,37 +72,6 @@
 #endif
 }
 
-static inline struct ed *
-dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
-
-/* print non-empty branches of the periodic ed tree */
-static void __attribute__ ((unused))
-ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
-{
-	int i, j;
-	u32 *ed_p;
-	int printed = 0;
-
-	for (i= 0; i < 32; i++) {
-		j = 5;
-		ed_p = &(ohci->hcca->int_table [i]);
-		if (*ed_p == 0)
-			continue;
-		printed = 1;
-		printk (KERN_DEBUG "%s, ohci %s frame %2d:",
-				label, ohci->hcd.self.bus_name, i);
-		while (*ed_p != 0 && j--) {
-			struct ed *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-			printk (" %p/%08x;", ed, ed->hwINFO);
-			ed_p = &ed->hwNextED;
-		}
-		printk ("\n");
-	}
-	if (!printed)
-		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
-				label, ohci->hcd.self.bus_name);
-}
-
 static void ohci_dump_intr_mask (char *label, __u32 mask)
 {
 	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
@@ -239,7 +208,8 @@
 	if (verbose)
 		ohci_dump_periodic (controller, "hcca");
 #endif
-	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	if (controller->hcca)
+		dbg ("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub (controller, 1);
 }
 
@@ -316,8 +286,9 @@
 	case ED_IN: type = "-IN"; break;
 	/* else from TDs ... control */
 	}
-	dbg ("  info %08x MAX=%d%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
-		0x0fff & (le32_to_cpu (tmp) >> 16),
+	dbg ("  info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
+		0x03ff & (le32_to_cpu (tmp) >> 16),
+		(tmp & ED_DEQUEUE) ? " DQ" : "",
 		(tmp & ED_ISO) ? " ISO" : "",
 		(tmp & ED_SKIP) ? " SKIP" : "",
 		(tmp & ED_LOWSPEED) ? " LOW" : "",
@@ -344,5 +315,222 @@
 	}
 }
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,32)
+#	define DRIVERFS_DEBUG_FILES
 #endif
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DRIVERFS_DEBUG_FILES
+
+static ssize_t
+show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
+{
+	unsigned		temp, size = count;
+
+	if (!ed)
+		return 0;
+
+	/* print first --> last */
+	while (ed->ed_prev)
+		ed = ed->ed_prev;
+
+	/* dump a snapshot of the bulk or control schedule */
+	while (ed) {
+		u32			info = ed->hwINFO;
+		u32			scratch = cpu_to_le32p (&ed->hwINFO);
+		struct list_head	*entry;
+		struct td		*td;
+
+		temp = snprintf (buf, size,
+			"ed/%p %cs dev%d ep%d-%s max %d %08x%s%s %s",
+			ed,
+			(info & ED_LOWSPEED) ? 'l' : 'f',
+			scratch & 0x7f,
+			(scratch >> 7) & 0xf,
+			(info & ED_IN) ? "in" : "out",
+			0x03ff & (scratch >> 16),
+			scratch,
+			(info & ED_SKIP) ? " s" : "",
+			(ed->hwHeadP & ED_H) ? " H" : "",
+			(ed->hwHeadP & ED_C) ? data1 : data0);
+		size -= temp;
+		buf += temp;
+
+		list_for_each (entry, &ed->td_list) {
+			u32		cbp, be;
+
+			td = list_entry (entry, struct td, td_list);
+			scratch = cpu_to_le32p (&td->hwINFO);
+			cbp = le32_to_cpup (&td->hwCBP);
+			be = le32_to_cpup (&td->hwBE);
+			temp = snprintf (buf, size,
+					"\n\ttd %p %s %d cc=%x urb %p (%08x)",
+					td,
+					({ char *pid;
+					switch (scratch & TD_DP) {
+					case TD_DP_SETUP: pid = "setup"; break;
+					case TD_DP_IN: pid = "in"; break;
+					case TD_DP_OUT: pid = "out"; break;
+					default: pid = "(?)"; break;
+					 } pid;}),
+					cbp ? (be + 1 - cbp) : 0,
+					TD_CC_GET (scratch), td->urb, scratch);
+			size -= temp;
+			buf += temp;
+		}
+
+		temp = snprintf (buf, size, "\n");
+		size -= temp;
+		buf += temp;
+
+		ed = ed->ed_next;
+	}
+	return count - size;
+}
+
+static ssize_t
+show_async (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ohci_hcd		*ohci;
+	size_t			temp;
+	unsigned long		flags;
+
+	if (off != 0)
+		return 0;
+	pdev = container_of (dev, struct pci_dev, dev);
+	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+
+	/* display control and bulk lists together, for simplicity */
+	spin_lock_irqsave (&ohci->lock, flags);
+	temp = show_list (ohci, buf, count, ohci->ed_controltail);
+	count = show_list (ohci, buf + temp, count - temp, ohci->ed_bulktail);
+	spin_unlock_irqrestore (&ohci->lock, flags);
+
+	return temp + count;
+}
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ohci_hcd		*ohci;
+	struct ed		**seen, *ed;
+	unsigned long		flags;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i;
+
+	if (off != 0)
+		return 0;
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	temp = snprintf (next, size, "size = %d\n", NUM_INTS);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule (and load) */
+	spin_lock_irqsave (&ohci->lock, flags);
+	for (i = 0; i < NUM_INTS; i++) {
+		if (!(ed = ohci->periodic [i]))
+			continue;
+
+		temp = snprintf (next, size, "%2d [%3d]:", i, ohci->load [i]);
+		size -= temp;
+		next += temp;
+
+		do {
+			temp = snprintf (next, size, " ed%d/%p",
+				ed->interval, ed);
+			size -= temp;
+			next += temp;
+			for (temp = 0; temp < seen_count; temp++) {
+				if (seen [temp] == ed)
+					break;
+			}
+
+			/* show more info the first time around */
+			if (temp == seen_count) {
+				u32	info = ed->hwINFO;
+				u32	scratch = cpu_to_le32p (&ed->hwINFO);
+
+				temp = snprintf (next, size,
+					" (%cs dev%d%s ep%d-%s"
+					" max %d %08x%s%s)",
+					(info & ED_LOWSPEED) ? 'l' : 'f',
+					scratch & 0x7f,
+					(info & ED_ISO) ? " iso" : "",
+					(scratch >> 7) & 0xf,
+					(info & ED_IN) ? "in" : "out",
+					0x03ff & (scratch >> 16),
+					scratch,
+					(info & ED_SKIP) ? " s" : "",
+					(ed->hwHeadP & ED_H) ? " H" : "");
+				size -= temp;
+				next += temp;
+
+				// FIXME some TD info too
+
+				if (seen_count < DBG_SCHED_LIMIT)
+					seen [seen_count++] = ed;
+
+				ed = ed->ed_next;
+
+			} else {
+				/* we've seen it and what's after */
+				temp = 0;
+				ed = 0;
+			}
+
+		} while (ed);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ohci->lock, flags);
+	kfree (seen);
+
+	return count - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static inline void create_debug_files (struct ohci_hcd *bus)
+{
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	// registers
+	dbg ("%s: created debug files", bus->hcd.self.bus_name);
+}
+
+static inline void remove_debug_files (struct ohci_hcd *bus)
+{
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+}
+
+#else /* empty stubs for creating those files */
+
+static inline void create_debug_files (struct ohci_hcd *bus) { }
+static inline void remove_debug_files (struct ohci_hcd *bus) { }
+
+#endif /* DRIVERFS_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/host/ohci-hcd.c	Sun Sep 15 19:19:29 2002
@@ -17,6 +17,8 @@
  *
  * History:
  * 
+ * 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
+ * 	bandwidth accounting; if debugging, show schedules in driverfs
  * 2002/07/19 fixes to management of ED and schedule state.
  * 2002/06/09 SA-1111 support (Christopher Hoover)
  * 2002/06/01 remember frame when HC won't see EDs any more; use that info
@@ -66,7 +68,6 @@
  * v1.0 1999/04/27 initial release
  *
  * This file is licenced under the GPL.
- * $Id: ohci-hcd.c,v 1.9 2002/03/27 20:41:57 dbrownell Exp $
  */
  
 #include <linux/config.h>
@@ -107,8 +108,8 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "2002-Jul-19"
-#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
+#define DRIVER_VERSION "2002-Sep-03"
+#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
 /*-------------------------------------------------------------------------*/
@@ -152,7 +153,6 @@
 	unsigned int	pipe = urb->pipe;
 	int		i, size = 0;
 	unsigned long	flags;
-	int		bustime = 0;
 	int		retval = 0;
 	
 #ifdef OHCI_VERBOSE_DEBUG
@@ -230,43 +230,32 @@
 		}
 	}	
 
-// FIXME:  much of this switch should be generic, move to hcd code ...
-// ... and what's not generic can't really be handled this way.
-// need to consider periodicity for both types!
-
-	/* allocate and claim bandwidth if needed; ISO
-	 * needs start frame index if it was't provided.
-	 */
-	switch (usb_pipetype (pipe)) {
-		case PIPE_ISOCHRONOUS:
-			if (urb->transfer_flags & USB_ISO_ASAP) { 
-				urb->start_frame = ((ed->state != ED_IDLE)
-					? (ed->intriso.last_iso + 1)
-					: (le16_to_cpu (ohci->hcca->frame_no)
-						+ 10)) & 0xffff;
-			}
-			/* FALLTHROUGH */
-		case PIPE_INTERRUPT:
-			if (urb->bandwidth == 0) {
-				bustime = usb_check_bandwidth (urb->dev, urb);
-			}
-			if (bustime < 0) {
-				retval = bustime;
-				goto fail;
-			}
-			usb_claim_bandwidth (urb->dev, urb,
-				bustime, usb_pipeisoc (urb->pipe));
-	}
+	/* schedule the ed if needed */
+	if (ed->state == ED_IDLE) {
+		retval = ed_schedule (ohci, ed);
+		if (retval < 0)
+			goto fail;
+		if (ed->type == PIPE_ISOCHRONOUS) {
+			u16	frame = le16_to_cpu (ohci->hcca->frame_no);
 
-	urb->hcpriv = urb_priv;
+			/* delay a few frames before the first TD */
+			frame += max_t (u16, 8, ed->interval);
+			frame &= ~(ed->interval - 1);
+			frame |= ed->branch;
+			urb->start_frame = frame;
 
-	/* schedule the ed if needed */
-	if (ed->state == ED_IDLE)
-		ed_schedule (ohci, ed);
+			/* yes, only USB_ISO_ASAP is supported, and
+			 * urb->start_frame is never used as input.
+			 */
+		}
+	} else if (ed->type == PIPE_ISOCHRONOUS)
+		urb->start_frame = ed->last_iso + ed->interval;
 
 	/* fill the TDs and link them to the ed; and
 	 * enable that part of the schedule, if needed
+	 * and update count of queued periodic urbs
 	 */
+	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
 fail:
@@ -530,13 +519,15 @@
 	usb_connect (udev);
 	udev->speed = USB_SPEED_FULL;
 	if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
-		usb_free_dev (udev); 
+		usb_free_dev (udev);
+		ohci->hcd.self.root_hub = NULL;
 		disable (ohci);
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
 		writel (ohci->hc_control, &ohci->regs->control);
 		return -ENODEV;
 	}
 
+	create_debug_files (ohci);
 	return 0;
 }
 
@@ -571,7 +562,8 @@
 
 	if (ints & OHCI_INTR_UE) {
 		disable (ohci);
-		err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name);
+		err ("OHCI Unrecoverable Error, %s disabled",
+				hcd->self.bus_name);
 		// e.g. due to PCI Master/Target Abort
 
 #ifdef	DEBUG
@@ -620,10 +612,14 @@
 	if (!ohci->disabled)
 		hc_reset (ohci);
 	
+	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
-
-	pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
-		ohci->hcca, ohci->hcca_dma);
+	if (ohci->hcca) {
+		pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
+					ohci->hcca, ohci->hcca_dma);
+		ohci->hcca = NULL;
+		ohci->hcca_dma = 0;
+	}
 }
 
 /*-------------------------------------------------------------------------*/
@@ -646,14 +642,13 @@
 		usb_disconnect (&ohci->hcd.self.root_hub);
 	
 	/* empty the interrupt branches */
-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load [i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
 	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
 	
 	/* no EDs to remove */
 	ohci->ed_rm_list = NULL;
 
 	/* empty control and bulk lists */	 
-	ohci->ed_isotail     = NULL;
 	ohci->ed_controltail = NULL;
 	ohci->ed_bulktail    = NULL;
 
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c	Sun Sep 15 19:19:57 2002
+++ b/drivers/usb/host/ohci-mem.c	Sun Sep 15 19:19:57 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
  */
 
 /*-------------------------------------------------------------------------*/
@@ -52,13 +51,6 @@
 	return scan->virt;
 }
 
-static struct ed *
-dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma)
-{
-	return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),
-				      ed_dma);
-}
-
 static struct td *
 dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
 {
@@ -98,13 +90,6 @@
 }
 
 static inline int
-hash_add_ed (struct ohci_hcd *hc, struct ed *ed, int mem_flags)
-{
-	return hash_add_ed_td (&(hc->ed_hash [ED_HASH_FUNC (ed->dma)]),
-			ed, ed->dma, mem_flags);
-}
-
-static inline int
 hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags)
 {
 	return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]),
@@ -139,12 +124,6 @@
 }
 
 static inline void
-hash_free_ed (struct ohci_hcd *hc, struct ed * ed)
-{
-	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
-}
-
-static inline void
 hash_free_td (struct ohci_hcd *hc, struct td * td)
 {
 	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
@@ -223,11 +202,6 @@
 		memset (ed, 0, sizeof (*ed));
 		INIT_LIST_HEAD (&ed->td_list);
 		ed->dma = dma;
-		/* hash it for later reverse mapping */
-		if (!hash_add_ed (hc, ed, mem_flags)) {
-			pci_pool_free (hc->ed_cache, ed, dma);
-			return NULL;
-		}
 	}
 	return ed;
 }
@@ -235,7 +209,6 @@
 static void
 ed_free (struct ohci_hcd *hc, struct ed *ed)
 {
-	hash_free_ed (hc, ed);
 	pci_pool_free (hc->ed_cache, ed, ed->dma);
 }
 
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/usb/host/ohci-q.c	Sun Sep 15 19:20:24 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
  */
 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
@@ -52,6 +51,15 @@
 		urb->status = 0;
 	spin_unlock_irqrestore (&urb->lock, flags);
 
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		ohci->hcd.self.bandwidth_isoc_reqs--;
+		break;
+	case PIPE_INTERRUPT:
+		ohci->hcd.self.bandwidth_int_reqs--;
+		break;
+	}
+
 #ifdef OHCI_VERBOSE_DEBUG
 	urb_print (urb, "RET", usb_pipeout (urb->pipe));
 #endif
@@ -111,67 +119,111 @@
  * ED handling functions
  *-------------------------------------------------------------------------*/  
 
-/* search for the right branch to insert an interrupt ed into the int tree 
- * do some load balancing;
- * returns the branch
- * FIXME allow for failure, when there's no bandwidth left;
- * and consider iso loads too
+/* search for the right schedule branch to use for a periodic ed.
+ * does some load balancing; returns the branch, or negative errno.
  */
-static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
+static int balance (struct ohci_hcd *ohci, int interval, int load)
 {
-	int	i, branch = 0;
+	int	i, branch = -ENOSPC;
 
-	/* search for the least loaded interrupt endpoint branch */
-	for (i = 0; i < NUM_INTS ; i++) 
-		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+	/* iso periods can be huge; iso tds specify frame numbers */
+	if (interval > NUM_INTS)
+		interval = NUM_INTS;
+
+	/* search for the least loaded schedule branch of that period
+	 * that has enough bandwidth left unreserved.
+	 */
+	for (i = 0; i < interval ; i++) {
+		if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
+#ifdef CONFIG_USB_BANDWIDTH
+			int	j;
+
+			/* usb 1.1 says 90% of one frame */
+			for (j = i; j < NUM_INTS; j += interval) {
+				if ((ohci->load [j] + load) > 900)
+					break;
+			}
+			if (j < NUM_INTS)
+				continue;
+#endif
 			branch = i; 
-
-	branch = branch % interval;
-	for (i = branch; i < NUM_INTS; i += interval)
-		ohci->ohci_int_load [i] += load;
-
+		}
+	}
 	return branch;
 }
 
 /*-------------------------------------------------------------------------*/
 
-/* the int tree is a binary tree 
- * in order to process it sequentially the indexes of the branches have
- * to be mapped the mapping reverses the bits of a word of num_bits length
+/* both iso and interrupt requests have periods; this routine puts them
+ * into the schedule tree in the apppropriate place.  most iso devices use
+ * 1msec periods, but that's not required.
  */
-static int ep_rev (int num_bits, int word)
+static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
 {
-	int			i, wout = 0;
+	unsigned	i;
 
-	for (i = 0; i < num_bits; i++)
-		wout |= (( (word >> i) & 1) << (num_bits - i - 1));
-	return wout;
+	dbg ("%s: link %sed %p branch %d [%dus.], interval %d",
+		ohci->hcd.self.bus_name,
+		(ed->hwINFO & ED_ISO) ? "iso " : "",
+		ed, ed->branch, ed->load, ed->interval);
+
+	for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+		struct ed	**prev = &ohci->periodic [i];
+		u32		*prev_p = &ohci->hcca->int_table [i];
+		struct ed	*here = *prev;
+
+		/* sorting each branch by period (slow before fast)
+		 * lets us share the faster parts of the tree.
+		 * (plus maybe: put interrupt eds before iso)
+		 */
+		while (here && ed != here) {
+			if (ed->interval > here->interval)
+				break;
+			prev = &here->ed_next;
+			prev_p = &here->hwNextED;
+			here = *prev;
+		}
+		if (ed != here) {
+			ed->ed_next = here;
+			if (here)
+				ed->hwNextED = *prev_p;
+			wmb ();
+			*prev = ed;
+			*prev_p = cpu_to_le32p (&ed->dma);
+		}
+		ohci->load [i] += ed->load;
+	}
+	ohci->hcd.self.bandwidth_allocated += ed->load / ed->interval;
 }
 
-/*-------------------------------------------------------------------------*/
-
 /* link an ed into one of the HC chains */
 
-static void ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
+static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
 {	 
-	int			int_branch, i;
-	int			inter, interval, load;
-	__u32			*ed_p;
+	int	branch;
 
 	ed->state = ED_OPER;
+	ed->ed_prev = 0;
+	ed->ed_next = 0;
 	ed->hwNextED = 0;
 	wmb ();
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
 	 * work on some TD when CLE/BLE was turned off, and isn't quiesced
 	 * yet.  finish_unlinks() restarts as needed, some upcoming INTR_SF.
+	 *
+	 * control and bulk EDs are doubly linked (ed_next, ed_prev), but
+	 * periodic ones are singly linked (ed_next). that's because the
+	 * periodic schedule encodes a tree like figure 3-5 in the ohci
+	 * spec:  each qh can have several "previous" nodes, and the tree
+	 * doesn't have unused/idle descriptors.
 	 */
-
 	switch (ed->type) {
 	case PIPE_CONTROL:
 		if (ohci->ed_controltail == NULL) {
 			writel (ed->dma, &ohci->regs->ed_controlhead);
 		} else {
+			ohci->ed_controltail->ed_next = ed;
 			ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
 		}
 		ed->ed_prev = ohci->ed_controltail;
@@ -187,6 +239,7 @@
 		if (ohci->ed_bulktail == NULL) {
 			writel (ed->dma, &ohci->regs->ed_bulkhead);
 		} else {
+			ohci->ed_bulktail->ed_next = ed;
 			ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
 		}
 		ed->ed_prev = ohci->ed_bulktail;
@@ -198,74 +251,55 @@
 		ohci->ed_bulktail = ed;
 		break;
 
-	case PIPE_INTERRUPT:
-		load = ed->intriso.intr_info.int_load;
-		interval = ed->interval;
-		int_branch = ep_int_balance (ohci, interval, load);
-		ed->intriso.intr_info.int_branch = int_branch;
-
-		for (i = 0; i < ep_rev (6, interval); i += inter) {
-			inter = 1;
-			for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]); 
-				 (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval >= interval); 
-				ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval);
-			ed->hwNextED = *ed_p; 
-			*ed_p = cpu_to_le32 (ed->dma);
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		branch = balance (ohci, ed->interval, ed->load);
+		if (branch < 0) {
+			dbg ("%s: ERR %d, interval %d msecs, load %d",
+				ohci->hcd.self.bus_name,
+				branch, ed->interval, ed->load);
+			// FIXME if there are TDs queued, fail them!
+			return branch;
 		}
-		wmb ();
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "LINK_INT");
-#endif
-		break;
-
-	case PIPE_ISOCHRONOUS:
-		ed->ed_prev = ohci->ed_isotail;
-		if (ohci->ed_isotail != NULL) {
-			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
-		} else {
-			for ( i = 0; i < NUM_INTS; i += inter) {
-				inter = 1;
-				for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]); 
-					*ed_p != 0; 
-					ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval);
-				*ed_p = cpu_to_le32 (ed->dma);	
-			}	
-		}	
-		wmb ();
-		ohci->ed_isotail = ed;
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "LINK_ISO");
-#endif
-		break;
+		ed->branch = branch;
+		periodic_link (ohci, ed);
 	}	 	
 
 	/* the HC may not see the schedule updates yet, but if it does
 	 * then they'll be properly ordered.
 	 */
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
 /* scan the periodic table to find and unlink this ED */
-static void periodic_unlink (
-	struct ohci_hcd	*ohci,
-	struct ed	*ed,
-	unsigned	index,
-	unsigned	period
-) {
-	for (; index < NUM_INTS; index += period) {
-		__u32	*ed_p = &ohci->hcca->int_table [index];
+static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
+{
+	int	i;
 
-		while (*ed_p != 0) {
-			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-				*ed_p = ed->hwNextED;		
-				break;
-			}
-			ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED);
+	for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
+		struct ed	*temp;
+		struct ed	**prev = &ohci->periodic [i];
+		u32		*prev_p = &ohci->hcca->int_table [i];
+
+		while (*prev && (temp = *prev) != ed) {
+			prev_p = &temp->hwNextED;
+			prev = &temp->ed_next;
+		}
+		if (*prev) {
+			*prev_p = ed->hwNextED;
+			*prev = ed->ed_next;
 		}
+		ohci->load [i] -= ed->load;
 	}	
+	ohci->hcd.self.bandwidth_allocated -= ed->load / ed->interval;
+
+	dbg ("%s: unlink %sed %p branch %d [%dus.], interval %d",
+		ohci->hcd.self.bus_name,
+		(ed->hwINFO & ED_ISO) ? "iso " : "",
+		ed, ed->branch, ed->load, ed->interval);
 }
 
 /* unlink an ed from one of the HC chains. 
@@ -275,8 +309,6 @@
  */
 static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) 
 {
-	int	i;
-
 	ed->hwINFO |= ED_SKIP;
 
 	switch (ed->type) {
@@ -289,13 +321,15 @@
 			writel (le32_to_cpup (&ed->hwNextED),
 				&ohci->regs->ed_controlhead);
 		} else {
+			ed->ed_prev->ed_next = ed->ed_next;
 			ed->ed_prev->hwNextED = ed->hwNextED;
 		}
 		if (ohci->ed_controltail == ed) {
 			ohci->ed_controltail = ed->ed_prev;
+			if (ohci->ed_controltail)
+				ohci->ed_controltail->ed_next = 0;
 		} else {
-			 (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
-			 	->ed_prev = ed->ed_prev;
+			ed->ed_next->ed_prev = ed->ed_prev;
 		}
 		break;
 
@@ -308,50 +342,33 @@
 			writel (le32_to_cpup (&ed->hwNextED),
 				&ohci->regs->ed_bulkhead);
 		} else {
+			ed->ed_prev->ed_next = ed->ed_next;
 			ed->ed_prev->hwNextED = ed->hwNextED;
 		}
 		if (ohci->ed_bulktail == ed) {
 			ohci->ed_bulktail = ed->ed_prev;
+			if (ohci->ed_bulktail)
+				ohci->ed_bulktail->ed_next = 0;
 		} else {
-			 (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
-			 	->ed_prev = ed->ed_prev;
+			ed->ed_next->ed_prev = ed->ed_prev;
 		}
 		break;
 
-	case PIPE_INTERRUPT:
-		periodic_unlink (ohci, ed, ed->intriso.intr_info.int_branch, ed->interval);
-		for (i = ed->intriso.intr_info.int_branch; i < NUM_INTS; i += ed->interval)
-			ohci->ohci_int_load [i] -= ed->intriso.intr_info.int_load;
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "UNLINK_INT");
-#endif
-		break;
-
-	case PIPE_ISOCHRONOUS:
-		if (ohci->ed_isotail == ed)
-			ohci->ed_isotail = ed->ed_prev;
-		if (ed->hwNextED != 0) 
-			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
-		    		->ed_prev = ed->ed_prev;
-
-		if (ed->ed_prev != NULL)
-			ed->ed_prev->hwNextED = ed->hwNextED;
-		else
-			periodic_unlink (ohci, ed, 0, 1);
-#ifdef OHCI_VERBOSE_DEBUG
-		ohci_dump_periodic (ohci, "UNLINK_ISO");
-#endif
+	// case PIPE_INTERRUPT:
+	// case PIPE_ISOCHRONOUS:
+	default:
+		periodic_unlink (ohci, ed);
 		break;
 	}
 
-	/* FIXME Except for a couple of exceptionally clean unlink cases
+	/* NOTE: Except for a couple of exceptionally clean unlink cases
 	 * (like unlinking the only c/b ED, with no TDs) HCs may still be
-	 * caching this (till SOF).
-	 *
-	 * To avoid racing with the hardware, this needs to use ED_UNLINK
-	 * and delay til next INTR_SF.  Merge with start_urb_unlink().
+	 * caching this operational ED (or its address).  Safe unlinking
+	 * involves not marking it ED_IDLE till INTR_SF; we always do that
+	 * if td_list isn't empty.  Otherwise the race is small; but ...
 	 */
-	ed->state = ED_IDLE;
+	if (ed->state == ED_OPER)
+		ed->state = ED_IDLE;
 }
 
 
@@ -369,7 +386,6 @@
 ) {
 	int			is_out = !usb_pipein (pipe);
 	int			type = usb_pipetype (pipe);
-	int			bus_msecs = 0;
 	struct hcd_dev		*dev = (struct hcd_dev *) udev->hcpriv;
 	struct ed		*ed; 
 	unsigned		ep;
@@ -378,9 +394,6 @@
 	ep = usb_pipeendpoint (pipe) << 1;
 	if (type != PIPE_CONTROL && is_out)
 		ep |= 1;
-	if (type == PIPE_INTERRUPT)
-		bus_msecs = usb_calc_bus_time (udev->speed, !is_out, 0,
-			usb_maxpacket (udev, pipe, is_out)) / 1000;
 
 	spin_lock_irqsave (&ohci->lock, flags);
 
@@ -422,23 +435,25 @@
 		info = cpu_to_le32 (info);
 		if (udev->speed == USB_SPEED_LOW)
 			info |= ED_LOWSPEED;
-		/* control transfers store pids in tds */
+		/* only control transfers store pids in tds */
 		if (type != PIPE_CONTROL) {
 			info |= is_out ? ED_OUT : ED_IN;
-			if (type == PIPE_ISOCHRONOUS)
-				info |= ED_ISO;
-			if (type == PIPE_INTERRUPT) {
-				ed->intriso.intr_info.int_load = bus_msecs;
-				if (interval > 32)
+			if (type != PIPE_BULK) {
+				/* periodic transfers... */
+				if (type == PIPE_ISOCHRONOUS)
+					info |= ED_ISO;
+				else if (interval > 32)	/* iso can be bigger */
 					interval = 32;
+				ed->interval = interval;
+				ed->load = usb_calc_bus_time (
+					udev->speed, !is_out,
+					type == PIPE_ISOCHRONOUS,
+					usb_maxpacket (udev, pipe, is_out))
+						/ 1000;
 			}
 		}
 		ed->hwINFO = info;
 
-		/* value ignored except on periodic EDs, where
-		 * we know it's already a power of 2
-		 */
-		ed->interval = interval;
 #ifdef DEBUG
 	/*
 	 * There are two other cases we ought to change hwINFO, both during
@@ -473,8 +488,9 @@
  */
 static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
 {    
-	ed_deschedule (ohci, ed);
+	ed->hwINFO |= ED_DEQUEUE;
 	ed->state = ED_UNLINK;
+	ed_deschedule (ohci, ed);
 
 	/* SF interrupt might get delayed; record the frame counter value that
 	 * indicates when the HC isn't looking at it, so concurrent unlinks
@@ -483,7 +499,9 @@
 	 */
 	ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
 
+	/* rm_list is just singly linked, for simplicity */
 	ed->ed_next = ohci->ed_rm_list;
+	ed->ed_prev = 0;
 	ohci->ed_rm_list = ed;
 
 	/* enable SOF interrupt */
@@ -529,7 +547,6 @@
 
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
-	td_pt->hwNextTD = 0;
 
 	/* fill the old dummy TD */
 	td = urb_priv->td [index] = urb_priv->ed->dummy;
@@ -547,7 +564,7 @@
 	if (is_iso) {
 		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
 		td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
-		td->ed->intriso.last_iso = info & 0xffff;
+		td->ed->last_iso = info & 0xffff;
 	} else {
 		td->hwCBP = cpu_to_le32 (data); 
 	}			
@@ -608,9 +625,11 @@
 	/* Bulk and interrupt are identical except for where in the schedule
 	 * their EDs live.
 	 */
-	// case PIPE_BULK:
-	// case PIPE_INTERRUPT:
-	default:
+	case PIPE_INTERRUPT:
+		/* ... and periodic urbs have extra accounting */
+		ohci->hcd.self.bandwidth_int_reqs++;
+		/* FALLTHROUGH */
+	case PIPE_BULK:
 		info = is_out
 			? TD_T_TOGGLE | TD_CC | TD_DP_OUT
 			: TD_T_TOGGLE | TD_CC | TD_DP_IN;
@@ -676,6 +695,7 @@
 				data + urb->iso_frame_desc [cnt].offset,
 				urb->iso_frame_desc [cnt].length, urb, cnt);
 		}
+		ohci->hcd.self.bandwidth_isoc_reqs++;
 		break;
 	}
 	if (urb_priv->length != cnt)
@@ -707,8 +727,12 @@
 
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
-		else
+		else {
+			/* short reads are always OK for ISO */
+			if (cc == TD_DATAUNDERRUN)
+				cc = TD_CC_NOERROR;
 			dlen = tdPSW & 0x3ff;
+		}
 		urb->actual_length += dlen;
 		urb->iso_frame_desc [td->index].actual_length = dlen;
 		urb->iso_frame_desc [td->index].status = cc_to_error [cc];
@@ -802,6 +826,7 @@
 			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
+#ifdef DEBUG
 					struct urb *urb = td_list->urb;
 
 					/* help for troubleshooting: */
@@ -817,6 +842,7 @@
 						1 + td_list->index,
 						urb_priv->length,
 						cc, cc_to_error [cc]);
+#endif
 					td_list->ed->hwHeadP = 
 			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
 				    & __constant_cpu_to_le32 (TD_MASK))
@@ -872,8 +898,7 @@
 		 * we call a completion since it might have unlinked
 		 * another (earlier) urb
 		 *
-		 * FIXME use td_list to scan, not ed hashtables.
-		 * completely abolish ed hashtables!
+		 * FIXME use td_list to scan, not td hashtables.
 		 */
 rescan_this:
 		completed = 0;
@@ -894,8 +919,7 @@
 				td_done (urb, td);
 				urb_priv->td_cnt++;
 
-				*td_p = td->hwNextTD | (*td_p
-					& __constant_cpu_to_le32 (0x3));
+				*td_p = td->hwNextTD | (*td_p & ~TD_MASK);
 
 				/* URB is done; clean up */
 				if (urb_priv->td_cnt == urb_priv->length) {
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Sun Sep 15 19:20:24 2002
+++ b/drivers/usb/host/ohci.h	Sun Sep 15 19:20:24 2002
@@ -5,7 +5,6 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci.h,v 1.6 2002/03/22 16:04:54 dbrownell Exp $
  */
  
 /*
@@ -18,13 +17,16 @@
 struct ed {
 	/* first fields are hardware-specified, le32 */
 	__u32			hwINFO;       	/* endpoint config bitmap */
+	/* info bits defined by hcd */
+#define ED_DEQUEUE	__constant_cpu_to_le32(1 << 27)
+	/* info bits defined by the hardware */
 #define ED_ISO		__constant_cpu_to_le32(1 << 15)
 #define ED_SKIP		__constant_cpu_to_le32(1 << 14)
 #define ED_LOWSPEED	__constant_cpu_to_le32(1 << 13)
 #define ED_OUT		__constant_cpu_to_le32(0x01 << 11)
 #define ED_IN		__constant_cpu_to_le32(0x02 << 11)
 	__u32			hwTailP;	/* tail of TD list */
-	__u32			hwHeadP;	/* head of TD list */
+	__u32			hwHeadP;	/* head of TD list (hc r/w) */
 #define ED_C		__constant_cpu_to_le32(0x02)	/* toggle carry */
 #define ED_H		__constant_cpu_to_le32(0x01)	/* halted */
 	__u32			hwNextED;	/* next ED in list */
@@ -48,14 +50,12 @@
 #define ED_OPER		0x02		/* IS linked to hc */
 
 	u8			type; 		/* PIPE_{BULK,...} */
-	u16			interval;	/* interrupt, isochronous */
-	union {
-		struct intr_info {		/* interrupt */
-			u8	int_branch;
-			u8	int_load; 
-		} intr_info;
-		u16		last_iso;	/* isochronous */
-	} intriso;
+
+	/* periodic scheduling params (for intr and iso) */
+	u8			branch;
+	u16			interval;
+	u16			load;
+	u16			last_iso;	/* iso only */
 
 	/* HC may see EDs on rm_list until next frame (frame_no == tick) */
 	u16			tick;
@@ -335,10 +335,8 @@
 };
 
 #define TD_HASH_SIZE    64    /* power'o'two */
-#define ED_HASH_SIZE    64    /* power'o'two */
 
 #define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
-#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
 
 
 /*
@@ -373,7 +371,7 @@
 
 	struct ed		*ed_bulktail;		/* last in bulk list */
 	struct ed		*ed_controltail;	/* last in ctrl list */
- 	struct ed		*ed_isotail;		/* last in iso list */
+ 	struct ed		*periodic [NUM_INTS];	/* shadow int_table */
 
 	/*
 	 * memory management for queue data structures
@@ -381,14 +379,13 @@
 	struct pci_pool		*td_cache;
 	struct pci_pool		*ed_cache;
 	struct hash_list_t	td_hash [TD_HASH_SIZE];
-	struct hash_list_t	ed_hash [ED_HASH_SIZE];
 
 	/*
 	 * driver state
 	 */
 	int			disabled;	/* e.g. got a UE, we're hung */
 	int			sleeping;
-	int			ohci_int_load [NUM_INTS];
+	int			load [NUM_INTS];
 	u32 			hc_control;	/* copy of hc control reg */
 
 	unsigned long		flags;		/* for HC bugs */
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Sun Sep 15 19:20:23 2002
+++ b/drivers/usb/host/uhci-hcd.c	Sun Sep 15 19:20:23 2002
@@ -105,12 +105,10 @@
 /* to make sure it doesn't hog all of the bandwidth */
 #define DEPTH_INTERVAL 5
 
-#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
-
 /*
  * Technically, updating td->status here is a race, but it's not really a
  * problem. The worst that can happen is that we set the IOC bit again
- * generating a spurios interrupt. We could fix this by creating another
+ * generating a spurious interrupt. We could fix this by creating another
  * QH and leaving the IOC bit always set, but then we would have to play
  * games with the FSBR code to make sure we get the correct order in all
  * the cases. I don't think it's worth the effort
@@ -148,7 +146,7 @@
 	dma_addr_t dma_handle;
 	struct uhci_td *td;
 
-	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	td = pci_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
 	if (!td)
 		return NULL;
 
@@ -273,7 +271,7 @@
 /*
  * Inserts a td into qh list at the top.
  */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth)
 {
 	struct list_head *tmp, *head;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
@@ -290,7 +288,7 @@
 	td = list_entry(tmp, struct uhci_td, list);
 
 	/* Add the first TD to the QH element pointer */
-	qh->element = cpu_to_le32(td->dma_handle) | (breadth ? 0 : UHCI_PTR_DEPTH);
+	qh->element = cpu_to_le32(td->dma_handle) | breadth;
 
 	ptd = td;
 
@@ -301,7 +299,7 @@
 
 		tmp = tmp->next;
 
-		ptd->link = cpu_to_le32(td->dma_handle) | (breadth ? 0 : UHCI_PTR_DEPTH);
+		ptd->link = cpu_to_le32(td->dma_handle) | breadth;
 
 		ptd = td;
 	}
@@ -311,10 +309,6 @@
 
 static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
 {
-/*
-	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
-		dbg("td %p is still in URB list!", td);
-*/
 	if (!list_empty(&td->list))
 		dbg("td %p is still in list!", td);
 	if (!list_empty(&td->fl_list))
@@ -331,7 +325,7 @@
 	dma_addr_t dma_handle;
 	struct uhci_qh *qh;
 
-	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	qh = pci_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
 	if (!qh)
 		return NULL;
 
@@ -365,43 +359,57 @@
 }
 
 /*
+ * Append this urb's qh after the last qh in skelqh->list
  * MUST be called with uhci->frame_list_lock acquired
+ *
+ * Note that urb_priv.queue_list doesn't have a separate queue head;
+ * it's a ring with every element "live".
  */
 static void _uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
+	struct list_head *tmp;
 	struct uhci_qh *lqh;
 
 	/* Grab the last QH */
 	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
+	/* Patch this endpoint's URBs' QHs to point to the next skelQH:
+	 *    SkelQH --> ... lqh --> NewQH --> NextSkelQH
+	 * Do this first, so the HC always sees the right QH after this one.
+	 */
+	list_for_each (tmp, &urbp->queue_list) {
+		struct urb_priv *turbp =
+			list_entry(tmp, struct urb_priv, queue_list);
+
+		turbp->qh->link = lqh->link;
+	}
+	urbp->qh->link = lqh->link;
+	wmb();				/* Ordering is important */
+
+	/* Patch QHs for previous endpoint's queued URBs?  HC goes
+	 * here next, not to the NextSkelQH it now points to.
+	 *
+	 *    lqh --> td ... --> qh ... --> td --> qh ... --> td
+	 *     |                 |                 |
+	 *     v                 v                 v
+	 *     +<----------------+-----------------+
+	 *     v
+	 *    NewQH --> td ... --> td
+	 *     |
+	 *     v
+	 *    ...
+	 *
+	 * The HC could see (and use!) any of these as we write them.
+	 */
 	if (lqh->urbp) {
-		head = &lqh->urbp->queue_list;
-		tmp = head->next;
-		while (head != tmp) {
+		list_for_each (tmp, &lqh->urbp->queue_list) {
 			struct urb_priv *turbp =
 				list_entry(tmp, struct urb_priv, queue_list);
 
-			tmp = tmp->next;
-
 			turbp->qh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
 		}
 	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp =
-			list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		turbp->qh->link = lqh->link;
-	}
-
-	urbp->qh->link = lqh->link;
-	mb();				/* Ordering is important */
 	lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
 
 	list_add_tail(&urbp->qh->list, &skelqh->list);
@@ -416,6 +424,9 @@
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
+/* start removal of qh from schedule; it finishes next frame.
+ * TDs should be unlinked before this is called.
+ */
 static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
 	unsigned long flags;
@@ -869,12 +880,12 @@
 	urbp->qh = qh;
 	qh->urbp = urbp;
 
-	/* Low speed or small transfers gets a different queue and treatment */
+	/* Low speed transfers get a different queue, and won't hog the bus */
 	if (urb->dev->speed == USB_SPEED_LOW) {
-		uhci_insert_tds_in_qh(qh, urb, 0);
+		uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_DEPTH);
 		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	} else {
-		uhci_insert_tds_in_qh(qh, urb, 1);
+		uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
 		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 		uhci_inc_fsbr(uhci, urb);
 	}
@@ -914,9 +925,9 @@
 	urbp->qh->urbp = urbp;
 
 	/* One TD, who cares about Breadth first? */
-	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
+	uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH);
 
-	/* Low speed or small transfers gets a different queue and treatment */
+	/* Low speed transfers get a different queue */
 	if (urb->dev->speed == USB_SPEED_LOW)
 		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	else
@@ -1242,8 +1253,8 @@
 	urbp->qh = qh;
 	qh->urbp = urbp;
 
-	/* Always assume breadth first */
-	uhci_insert_tds_in_qh(qh, urb, 1);
+	/* Always breadth first */
+	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
 
 	if (eurb)
 		uhci_append_queued_urb(uhci, eurb, urb);
@@ -1487,6 +1498,10 @@
 
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
+	if (ret != -EINPROGRESS) {
+		uhci_destroy_urb_priv (uhci, urb);
+		return ret;
+	}
 	return 0;
 }
 
@@ -1795,8 +1810,7 @@
 
 	spin_lock_irqsave(&urb->lock, flags);
 
-	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
-			urb->status == -ECONNRESET);
+ 	killed = (urb->status == -ENOENT || urb->status == -ECONNRESET);
 	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
 			urb->interval);
 
@@ -1817,9 +1831,7 @@
 	if (resubmit_interrupt)
 		/* Recheck the status. The completion handler may have */
 		/*  unlinked the resubmitting interrupt URB */
-		killed = (urb->status == -ENOENT ||
-			  urb->status == -ECONNABORTED ||
-			  urb->status == -ECONNRESET);
+		killed = (urb->status == -ENOENT || urb->status == -ECONNRESET);
 
 	if (resubmit_interrupt && !killed) {
 		urb->dev = dev;
@@ -2016,19 +2028,12 @@
         uhci->hcd.state = USB_STATE_READY;
 }
 
-#ifdef CONFIG_PROC_FS
-static int uhci_num = 0;
-#endif
-
 /*
  * De-allocate all resources..
  */
 static void release_uhci(struct uhci_hcd *uhci)
 {
 	int i;
-#ifdef CONFIG_PROC_FS
-	char buf[8];
-#endif
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 		if (uhci->skelqh[i]) {
@@ -2053,15 +2058,13 @@
 	}
 
 	if (uhci->fl) {
-		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+		pci_free_consistent(uhci->hcd.pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
 		uhci->fl = NULL;
 	}
 
 #ifdef CONFIG_PROC_FS
 	if (uhci->proc_entry) {
-		sprintf(buf, "hc%d", uhci->num);
-
-		remove_proc_entry(buf, uhci_proc_root);
+		remove_proc_entry(uhci->hcd.self.bus_name, uhci_proc_root);
 		uhci->proc_entry = NULL;
 	}
 #endif
@@ -2086,33 +2089,20 @@
 static int __devinit uhci_start(struct usb_hcd *hcd)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-	struct pci_dev *dev = hcd->pdev;
 	int retval = -EBUSY;
 	int i, port;
+	unsigned io_size;
 	dma_addr_t dma_handle;
+	struct usb_device *udev;
 #ifdef CONFIG_PROC_FS
-	char buf[8];
 	struct proc_dir_entry *ent;
 #endif
 
-	uhci->dev = dev;
-
-	/* Should probably move to core/hcd.c */
-	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
-		err("couldn't set PCI dma mask");
-		retval = -ENODEV;
-		goto err_pci_set_dma_mask;
-	}
-
-	uhci->io_addr = pci_resource_start(dev, hcd->region);
-	uhci->io_size = pci_resource_len(dev, hcd->region);
+	uhci->io_addr = (unsigned) hcd->regs;
+	io_size = pci_resource_len(hcd->pdev, hcd->region);
 
 #ifdef CONFIG_PROC_FS
-	uhci->num = uhci_num++;
-
-	sprintf(buf, "hc%d", uhci->num);
-
-	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
+	ent = create_proc_entry(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
 	if (!ent) {
 		err("couldn't create uhci proc entry");
 		retval = -ENOMEM;
@@ -2148,7 +2138,7 @@
 
 	spin_lock_init(&uhci->frame_list_lock);
 
-	uhci->fl = pci_alloc_consistent(dev, sizeof(*uhci->fl), &dma_handle);
+	uhci->fl = pci_alloc_consistent(hcd->pdev, sizeof(*uhci->fl), &dma_handle);
 	if (!uhci->fl) {
 		err("unable to allocate consistent memory for frame list");
 		goto err_alloc_fl;
@@ -2158,15 +2148,15 @@
 
 	uhci->fl->dma_handle = dma_handle;
 
-	uhci->td_pool = pci_pool_create("uhci_td", dev,
-		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
+	uhci->td_pool = pci_pool_create("uhci_td", hcd->pdev,
+		sizeof(struct uhci_td), 16, 0, GFP_ATOMIC);
 	if (!uhci->td_pool) {
 		err("unable to create td pci_pool");
 		goto err_create_td_pool;
 	}
 
-	uhci->qh_pool = pci_pool_create("uhci_qh", dev,
-		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
+	uhci->qh_pool = pci_pool_create("uhci_qh", hcd->pdev,
+		sizeof(struct uhci_qh), 16, 0, GFP_ATOMIC);
 	if (!uhci->qh_pool) {
 		err("unable to create qh pci_pool");
 		goto err_create_qh_pool;
@@ -2178,7 +2168,7 @@
 	/*  they may have more but give no way to determine how many they */
 	/*  have. However, according to the UHCI spec, Bit 7 is always set */
 	/*  to 1. So we try to use this to our advantage */
-	for (port = 0; port < (uhci->io_size - 0x10) / 2; port++) {
+	for (port = 0; port < (io_size - 0x10) / 2; port++) {
 		unsigned int portstatus;
 
 		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
@@ -2197,13 +2187,13 @@
 
 	uhci->rh_numports = port;
 
-	hcd->self.root_hub = uhci->rh_dev = usb_alloc_dev(NULL, &hcd->self);
-	if (!uhci->rh_dev) {
+	hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self);
+	if (!udev) {
 		err("unable to allocate root hub");
 		goto err_alloc_root_hub;
 	}
 
-	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh_dev);
+	uhci->skeltd[0] = uhci_alloc_td(uhci, udev);
 	if (!uhci->skeltd[0]) {
 		err("unable to allocate TD 0");
 		goto err_alloc_skeltd;
@@ -2216,7 +2206,7 @@
 	for (i = 1; i < 9; i++) {
 		struct uhci_td *td;
 
-		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh_dev);
+		td = uhci->skeltd[i] = uhci_alloc_td(uhci, udev);
 		if (!td) {
 			err("unable to allocate TD %d", i);
 			goto err_alloc_skeltd;
@@ -2227,14 +2217,14 @@
 		td->link = cpu_to_le32(uhci->skeltd[i - 1]->dma_handle);
 	}
 
-	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh_dev);
+	uhci->skel_term_td = uhci_alloc_td(uhci, udev);
 	if (!uhci->skel_term_td) {
 		err("unable to allocate skel TD term");
 		goto err_alloc_skeltd;
 	}
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh_dev);
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
 		if (!uhci->skelqh[i]) {
 			err("unable to allocate QH %d", i);
 			goto err_alloc_skelqh;
@@ -2303,12 +2293,12 @@
 	init_stall_timer(hcd);
 
 	/* disable legacy emulation */
-	pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+	pci_write_config_word(hcd->pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
 
-	usb_connect(uhci->rh_dev);
-        uhci->rh_dev->speed = USB_SPEED_FULL;
+	usb_connect(udev);
+	udev->speed = USB_SPEED_FULL;
 
-	if (usb_register_root_hub(uhci->rh_dev, &dev->dev) != 0) {
+	if (usb_register_root_hub(udev, &hcd->pdev->dev) != 0) {
 		err("unable to start root hub");
 		retval = -ENOMEM;
 		goto err_start_root_hub;
@@ -2322,7 +2312,7 @@
 err_start_root_hub:
 	reset_hc(uhci);
 
-	del_timer(&uhci->stall_timer);
+	del_timer_sync(&uhci->stall_timer);
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 		if (uhci->skelqh[i]) {
@@ -2338,8 +2328,8 @@
 		}
 
 err_alloc_skeltd:
-	usb_free_dev(uhci->rh_dev);
-	uhci->rh_dev = NULL;
+	usb_free_dev(udev);
+	hcd->self.root_hub = NULL;
 
 err_alloc_root_hub:
 	pci_pool_destroy(uhci->qh_pool);
@@ -2350,19 +2340,17 @@
 	uhci->td_pool = NULL;
 
 err_create_td_pool:
-	pci_free_consistent(dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+	pci_free_consistent(hcd->pdev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
 	uhci->fl = NULL;
 
 err_alloc_fl:
 #ifdef CONFIG_PROC_FS
-	remove_proc_entry(buf, uhci_proc_root);
+	remove_proc_entry(hcd->self.bus_name, uhci_proc_root);
 	uhci->proc_entry = NULL;
 
 err_create_proc_entry:
 #endif
 
-err_pci_set_dma_mask:
-
 	return retval;
 }
 
@@ -2370,10 +2358,7 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	if (uhci->rh_dev)
-		usb_disconnect(&uhci->rh_dev);
-
-	del_timer(&uhci->stall_timer);
+	del_timer_sync(&uhci->stall_timer);
 
 	/*
 	 * At this point, we're guaranteed that no new connects can be made
@@ -2402,7 +2387,7 @@
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
-	pci_set_master(uhci->dev);
+	pci_set_master(uhci->hcd.pdev);
 
 	reset_hc(uhci);
 	start_hc(uhci);
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h	Sun Sep 15 19:20:14 2002
+++ b/drivers/usb/host/uhci-hcd.h	Sun Sep 15 19:20:14 2002
@@ -65,6 +65,7 @@
 #define UHCI_PTR_TERM		cpu_to_le32(0x0001)
 #define UHCI_PTR_QH		cpu_to_le32(0x0002)
 #define UHCI_PTR_DEPTH		cpu_to_le32(0x0004)
+#define UHCI_PTR_BREADTH	cpu_to_le32(0x0000)
 
 #define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
@@ -80,6 +81,19 @@
 
 struct urb_priv;
 
+/* One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
+ * used with one URB, and qh->element (updated by the HC) is either:
+ *   - the next unprocessed TD for the URB, or
+ *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
+ *   - the QH for the next URB queued to the same endpoint.
+ *
+ * The other role of a QH is to serve as a "skeleton" framelist entry, so we
+ * can easily splice a QH for some endpoint into the schedule at the right
+ * place.  Then qh->element is UHCI_PTR_TERM.
+ *
+ * In the frame list, qh->link maintains a list of QHs seen by the HC:
+ *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+ */
 struct uhci_qh {
 	/* Hardware fields */
 	__u32 link;			/* Next queue */
@@ -156,6 +170,9 @@
  *
  * Alas, not anymore, we have more than 4 words for software, woops.
  * Everything still works tho, surprise! -jerdfelt
+ *
+ * td->link points to either another TD (not necessarily for the same urb or
+ * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs)
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -172,7 +189,7 @@
 
 	struct list_head list;		/* P: urb->lock */
 
-	int frame;
+	int frame;			/* for iso: what frame? */
 	struct list_head fl_list;	/* P: uhci->frame_list_lock */
 } __attribute__((aligned(16)));
 
@@ -217,6 +234,22 @@
  *
  * To keep with Linus' nomenclature, this is called the QH skeleton. These
  * labels (below) are only signficant to the root hub's QH's
+ *
+ *
+ * NOTE:  That ASCII art doesn't match the current (August 2002) code, in
+ * more ways than just not using QHs for ISO.
+ *
+ * NOTE:  Another way to look at the UHCI schedules is to compare them to what
+ * other host controller interfaces use.  EHCI, OHCI, and UHCI all have tables
+ * of transfers that the controller scans, frame by frame, and which hold the
+ * scheduled periodic transfers.  The key differences are that UHCI
+ *
+ *   (a) puts control and bulk transfers into that same table; the others
+ *       have separate data structures for non-periodic transfers.
+ *   (b) lets QHs be linked from TDs, not just other QHs, since they don't
+ *       hold endpoint data.  this driver chooses to use one QH per URB.
+ *   (c) needs more TDs, since it uses one per packet.  the data toggle
+ *       is stored in those TDs, along with all other endpoint state.
  */
 
 #define UHCI_NUM_SKELTD		10
@@ -275,7 +308,7 @@
 	return 7;				/* int128 for 128-255 ms (Max.) */
 }
 
-#define hcd_to_uhci(hcd_ptr) list_entry(hcd_ptr, struct uhci_hcd, hcd)
+#define hcd_to_uhci(hcd_ptr) container_of(hcd_ptr, struct uhci_hcd, hcd)
 
 /*
  * This describes the full uhci information.
@@ -286,18 +319,13 @@
 struct uhci_hcd {
 	struct usb_hcd hcd;
 
-	struct pci_dev *dev;
-
 #ifdef CONFIG_PROC_FS
 	/* procfs */
-	int num;
 	struct proc_dir_entry *proc_entry;
 #endif
 
 	/* Grabbed from PCI */
-	int irq;
 	unsigned int io_addr;
-	unsigned int io_size;
 
 	struct pci_pool *qh_pool;
 	struct pci_pool *td_pool;
@@ -329,7 +357,6 @@
 	spinlock_t complete_list_lock;
 	struct list_head complete_list;		/* P: uhci->complete_list_lock */
 
-	struct usb_device *rh_dev;		/* Root hub */
 	int rh_numports;
 
 	struct timer_list stall_timer;
diff -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
--- a/drivers/usb/image/hpusbscsi.c	Sun Sep 15 19:20:24 2002
+++ b/drivers/usb/image/hpusbscsi.c	Sun Sep 15 19:20:24 2002
@@ -154,7 +154,13 @@
 static struct usb_device_id hpusbscsi_usb_ids[] = {
 	{USB_DEVICE (0x03f0, 0x0701)},	/* HP 53xx */
 	{USB_DEVICE (0x03f0, 0x0801)},	/* HP 7400 */
-	{USB_DEVICE (0x0638, 0x026a)},	/*Scan Dual II */
+	{USB_DEVICE (0x0638, 0x0268)},  /*iVina 1200U */
+	{USB_DEVICE (0x0638, 0x026a)},  /*Scan Dual II */
+	{USB_DEVICE (0x0638, 0x0A13)},  /*Avision AV600U */
+	{USB_DEVICE (0x0638, 0x0A16)},  /*Avision DS610CU Scancopier */
+	{USB_DEVICE (0x0638, 0x0A18)},  /*Avision AV600U Plus */
+	{USB_DEVICE (0x0638, 0x0A23)},  /*Avision AV220 */
+	{USB_DEVICE (0x0638, 0x0A24)},  /*Avision AV210 */
 	{USB_DEVICE (0x0686, 0x4004)},  /*Minolta Elite II */
 	{}			/* Terminating entry */
 };
diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
--- a/drivers/usb/image/microtek.c	Sun Sep 15 19:19:46 2002
+++ b/drivers/usb/image/microtek.c	Sun Sep 15 19:19:46 2002
@@ -583,13 +583,22 @@
 		return;
 	}
 
-	if ( context->data ) {
+	if (context->srb->cmnd[0] == REQUEST_SENSE) {
 		mts_int_submit_urb(transfer,
 				   context->data_pipe,
-				   context->data,
+				   context->srb->sense_buffer,
 				   context->data_length,
-				   context->srb->use_sg ? mts_do_sg : mts_data_done);
-	} else mts_get_status(transfer);
+				   mts_data_done);
+	} else { if ( context->data ) {
+			mts_int_submit_urb(transfer,
+					   context->data_pipe,
+					   context->data,
+					   context->data_length,
+					   context->srb->use_sg ? mts_do_sg : mts_data_done);
+		} else {
+			mts_get_status(transfer);
+		}
+	}
 
 	return;
 }
@@ -598,7 +607,7 @@
 {
 	struct scatterlist * sg;
 	MTS_INT_INIT();
-	
+
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
 	if (unlikely(transfer->status)) {
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/image/scanner.c	Sun Sep 15 19:19:29 2002
@@ -774,7 +774,7 @@
  		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
  			return -EFAULT;
 
- 		nb = le16_to_cpup(&cmsg.req.wLength);
+ 		nb = cmsg.req.wLength;
 
  		if (nb > sizeof(buf))
  			return -EINVAL;
@@ -789,8 +789,8 @@
 
  		ret = usb_control_msg(dev, pipe, cmsg.req.bRequest,
  				      cmsg.req.bRequestType,
- 				      le16_to_cpup(&cmsg.req.wValue),
- 				      le16_to_cpup(&cmsg.req.wIndex),
+ 				      cmsg.req.wValue,
+ 				      cmsg.req.wIndex,
  				      buf, nb, HZ);
 
  		if (ret < 0) {
diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- a/drivers/usb/input/hid-lgff.c	Sun Sep 15 19:20:14 2002
+++ b/drivers/usb/input/hid-lgff.c	Sun Sep 15 19:20:14 2002
@@ -45,9 +45,6 @@
 
 #define RUN_AT(t) (jiffies + (t))
 
-/* Transmition state */
-#define XMIT_RUNNING 0
-
 /* Effect status */
 #define EFFECT_STARTED 0     /* Effect is going to play after some time
 				(ff_replay.delay) */
diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/media/se401.c	Sun Sep 15 19:19:29 2002
@@ -25,7 +25,7 @@
  * 	- Jeroen Vreeken
  */
 
-static const char version[] = "0.23";
+static const char version[] = "0.24";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -980,6 +980,34 @@
 	return 0;
 }
 
+static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+{
+	int i;
+
+        se401->dev = NULL;
+
+	for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+		usb_unlink_urb(se401->urb[i]);
+		usb_free_urb(se401->urb[i]);
+		se401->urb[i] = NULL;
+		kfree(se401->sbuf[i].data);
+	}
+	for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
+		kfree(se401->scratch[i].data);
+	}
+	if (se401->inturb) {
+		usb_unlink_urb(se401->inturb);
+		usb_free_urb(se401->inturb);
+	}
+        info("%s disconnected", se401->camera_name);
+
+        /* Free the memory */
+	kfree(se401->width);
+	kfree(se401->height);
+	kfree(se401);
+}
+
+
 
 /****************************************************************************
  *
@@ -1015,20 +1043,16 @@
         struct usb_se401 *se401 = (struct usb_se401 *)dev;
 	int i;
 
-	for (i=0; i<SE401_NUMFRAMES; i++)
-		se401->frame[i].grabstate=FRAME_UNUSED;
-	if (se401->streaming)
-		se401_stop_stream(se401);
-
 	rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
-	se401->user=0;
-
         if (se401->removed) {
-		kfree(se401->width);
-		kfree(se401->height);
-                kfree(se401);
-                se401 = NULL;
+		usb_se401_remove_disconnected(se401);
 		info("device unregistered");
+	} else {
+		for (i=0; i<SE401_NUMFRAMES; i++)
+			se401->frame[i].grabstate=FRAME_UNUSED;
+		if (se401->streaming)
+			se401_stop_stream(se401);
+		se401->user=0;
 	}
 	file->private_data = NULL;
 	return 0;
@@ -1302,7 +1326,7 @@
 
 
 /***************************/
-static int se401_init(struct usb_se401 *se401)
+static int se401_init(struct usb_se401 *se401, int button)
 {
         int i=0, rc;
         unsigned char cp[0x40];
@@ -1367,22 +1391,25 @@
 	se401->readcount=0;
 
 	/* Start interrupt transfers for snapshot button */
-	se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
-	if (!se401->inturb) {
-		info("Allocation of inturb failed");
-		return 1;
-	}
-	FILL_INT_URB(se401->inturb, se401->dev,
-	    usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
-	    &se401->button, sizeof(se401->button),
-	    se401_button_irq,
-	    se401,
-	    HZ/10
-	);
-	if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-		info("int urb burned down");
-		return 1;
-	}
+	if (button) {
+		se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+		if (!se401->inturb) {
+			info("Allocation of inturb failed");
+			return 1;
+		}
+		FILL_INT_URB(se401->inturb, se401->dev,
+		    usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+		    &se401->button, sizeof(se401->button),
+		    se401_button_irq,
+		    se401,
+		    HZ/10
+		);
+		if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
+			info("int urb burned down");
+			return 1;
+		}
+	} else
+		se401->inturb=NULL;
 
         /* Flash the led */
         se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
@@ -1399,6 +1426,7 @@
         struct usb_interface_descriptor *interface;
         struct usb_se401 *se401;
         char *camera_name=NULL;
+	int button=1;
 
         /* We don't handle multi-config cameras */
         if (dev->descriptor.bNumConfigurations != 1)
@@ -1422,6 +1450,7 @@
         } else if (dev->descriptor.idVendor == 0x047d &&
 	    dev->descriptor.idProduct == 0x5003) {
 		camera_name="Kensington VideoCAM 67016";
+		button=0;
 	} else
 		return NULL;
 
@@ -1447,7 +1476,7 @@
 
 	info("firmware version: %02x", dev->descriptor.bcdDevice & 255);
 
-        if (se401_init(se401)) {
+        if (se401_init(se401, button)) {
 		kfree(se401);
 		return NULL;
 	}
@@ -1479,45 +1508,18 @@
 	if (!se401->user){
 		usb_se401_remove_disconnected(se401);
 	} else {
-		se401->removed = 1;
-	}
-}
+		se401->frame[0].grabstate = FRAME_ERROR;
+		se401->frame[0].grabstate = FRAME_ERROR;
 
-static inline void usb_se401_remove_disconnected (struct usb_se401 *se401)
-{
-	int i;
-
-        se401->dev = NULL;
-        se401->frame[0].grabstate = FRAME_ERROR;
-        se401->frame[1].grabstate = FRAME_ERROR;
-
-	se401->streaming = 0;
-
-	wake_up_interruptible(&se401->wq);
-
-	for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-		usb_unlink_urb(se401->urb[i]);
-		usb_free_urb(se401->urb[i]);
-		se401->urb[i] = NULL;
-		kfree(se401->sbuf[i].data);
-	}
-	for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
-		kfree(se401->scratch[i].data);
-	}
-	if (se401->inturb) {
-		usb_unlink_urb(se401->inturb);
-		usb_free_urb(se401->inturb);
+		se401->streaming = 0;
+		
+		wake_up_interruptible(&se401->wq);
+		se401->removed = 1;
 	}
-        info("%s disconnected", se401->camera_name);
-
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	destroy_proc_se401_cam(se401);
 #endif
 
-        /* Free the memory */
-	kfree(se401->width);
-	kfree(se401->height);
-	kfree(se401);
 }
 
 static struct usb_driver se401_driver = {
diff -Nru a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h
--- a/drivers/usb/media/se401.h	Sun Sep 15 19:19:30 2002
+++ b/drivers/usb/media/se401.h	Sun Sep 15 19:19:30 2002
@@ -230,7 +230,6 @@
 	int nullpackets;
 };
 
-static inline void usb_se401_remove_disconnected (struct usb_se401 *se401);
 
 
 #endif
diff -Nru a/drivers/usb/misc/Config.in b/drivers/usb/misc/Config.in
--- a/drivers/usb/misc/Config.in	Sun Sep 15 19:20:05 2002
+++ b/drivers/usb/misc/Config.in	Sun Sep 15 19:20:05 2002
@@ -8,4 +8,4 @@
 dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
 dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
 dep_tristate '  USB LCD driver support' CONFIG_USB_LCD $CONFIG_USB
-dep_tristate '  Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB    
+dep_tristate '  Alcatel Speedtouch ADSL USB Modem' CONFIG_USB_SPEEDTOUCH $CONFIG_USB $CONFIG_ATM
diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
--- a/drivers/usb/net/kaweth.c	Sun Sep 15 19:20:05 2002
+++ b/drivers/usb/net/kaweth.c	Sun Sep 15 19:20:05 2002
@@ -464,7 +464,7 @@
 }
 
 static void kaweth_usb_receive(struct urb *);
-static void kaweth_resubmit_rx_urb(struct kaweth_device *, int);
+static int kaweth_resubmit_rx_urb(struct kaweth_device *, int);
 
 /****************************************************************
 	int_callback
@@ -493,7 +493,7 @@
 /****************************************************************
  *     kaweth_resubmit_rx_urb
  ****************************************************************/
-static void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
+static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
 						int mem_flags)
 {
 	int result;
@@ -513,6 +513,8 @@
 	} else {
 		kaweth->suspend_lowmem = 0;
 	}
+	
+	return result;
 }
 
 static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
@@ -567,6 +569,8 @@
                         return;
 		}
 
+		skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+
 		skb->dev = net;
 
 		eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
@@ -590,14 +594,15 @@
 static int kaweth_open(struct net_device *net)
 {
 	struct kaweth_device *kaweth = (struct kaweth_device *)net->priv;
+	int res;
 
 	kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter);
 
 	kaweth_dbg("Opening network device.");
 
-	MOD_INC_USE_COUNT;
-
-	kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
+	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
+	if (res)
+		return -EIO;
 
 	FILL_INT_URB(
 		kaweth->irq_urb,
@@ -609,7 +614,11 @@
 		kaweth,
 		HZ/4);
 
-	usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
+	res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
+	if (res) {
+		usb_unlink_urb(kaweth->rx_urb);
+		return -EIO;
+	}
 
 	netif_start_queue(net);
 
@@ -633,7 +642,6 @@
 
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
-	MOD_DEC_USE_COUNT;
 
 	printk("Dev usage: %d", kaweth->dev->refcnt.counter);
 
@@ -846,6 +854,7 @@
 	)
 {
 	struct kaweth_device *kaweth;
+	struct net_device *netdev;
 	const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 	int result = 0;
 
@@ -861,10 +870,8 @@
 		 (int)dev->descriptor.bLength,
 		 (int)dev->descriptor.bDescriptorType);
 
-	if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) {
-		kaweth_dbg("out of memory allocating device structure\n");
+	if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL)))
 		return NULL;
-	}
 
 	memset(kaweth, 0, sizeof(struct kaweth_device));
 
@@ -990,11 +997,17 @@
 
 	if(result < 0) {
 		kaweth_err("Error setting receive filter");
-		return kaweth;
+		kfree(kaweth);
+		return NULL;
 	}
 
 	kaweth_dbg("Initializing net device.");
 
+	if(!(netdev = kmalloc(sizeof(struct net_device), GFP_KERNEL))) {
+		kfree(kaweth);
+		return NULL;
+	}
+
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!kaweth->tx_urb)
 		goto err_no_urb;
@@ -1005,12 +1018,7 @@
 	if (!kaweth->irq_urb)
 		goto err_tx_and_rx;
 
-	kaweth->net = init_etherdev(0, 0);
-	if (!kaweth->net) {
-		kaweth_err("Error calling init_etherdev.");
-		return kaweth;
-	}
-
+	kaweth->net = netdev;
 	memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
 	memcpy(kaweth->net->dev_addr,
                &kaweth->configuration.hw_addr,
@@ -1030,6 +1038,13 @@
 	kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size);
 
 	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
+	
+	SET_MODULE_OWNER(netdev);
+
+	if (!init_etherdev(netdev, 0)) {
+		kaweth_err("Error calling init_etherdev.");
+		goto err_tx_and_rx;
+	}
 
 	kaweth_info("kaweth interface created at %s", kaweth->net->name);
 
@@ -1043,6 +1058,7 @@
 	usb_free_urb(kaweth->tx_urb);
 err_no_urb:
 	kfree(kaweth);
+	kfree(netdev);
 	return NULL;
 }
 
diff -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
--- a/drivers/usb/net/pegasus.h	Sun Sep 15 19:20:24 2002
+++ b/drivers/usb/net/pegasus.h	Sun Sep 15 19:20:24 2002
@@ -191,6 +191,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Corega FEter", VENDOR_COREGA, 0x0004,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
@@ -205,7 +207,7 @@
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "ELCON EPLC10Mi USB to Powerline Adapter", VENDOR_ELCON, 0x0002,
+PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
 PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
 		DEFAULT_GPIO_RESET )
@@ -254,7 +256,7 @@
 PEGASUS_DEV( "SOHOware NUB110 Ethernet", VENDOR_SOHOWARE, 0x9110,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
-		DEFAULT_GPIO_RESET )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 
 
 #endif	/* PEGASUS_DEV */
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/usb/net/usbnet.c	Sun Sep 15 19:19:28 2002
@@ -16,6 +16,7 @@
  *
  *	- AnchorChip 2720
  *	- Belkin, eTEK (interops with Win32 drivers)
+ *	- EPSON USB clients
  *	- GeneSys GL620USB-A
  *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
@@ -23,7 +24,7 @@
  *
  * USB devices can implement their side of this protocol at the cost
  * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the LINUXDEV support.
+ * See the LINUXDEV or EPSON device/client support.
  *
  * 
  * Status:
@@ -57,7 +58,7 @@
  *
  * Need smarter hotplug policy scripts ... ones that know how to arrange
  * bridging with "brctl", and can handle static and dynamic ("pump") setups.
- * Use those eventual "peer connected" events.
+ * Use those eventual "peer connected" events, and zeroconf.
  *
  *
  * CHANGELOG:
@@ -128,6 +129,7 @@
 /* minidrivers _could_ be individually configured */
 #define	CONFIG_USB_AN2720
 #define	CONFIG_USB_BELKIN
+#define	CONFIG_USB_EPSON2888
 #define	CONFIG_USB_GENESYS
 #define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
@@ -329,6 +331,29 @@
 
 
 
+#ifdef	CONFIG_USB_EPSON2888
+
+/*-------------------------------------------------------------------------
+ *
+ * EPSON USB clients
+ *
+ * This is the same idea as "linuxdev" (below) except the firmware in the
+ * device might not be Tux-powered.  Epson provides reference firmware that
+ * implements this interface.  Product developers can reuse or modify that
+ * code, such as by using their own product and vendor codes.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	epson2888_info = {
+	.description =	"Epson USB Device",
+
+	.in = 4, .out = 3,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_EPSON2888 */
+
+
 #ifdef CONFIG_USB_GENESYS
 
 /*-------------------------------------------------------------------------
@@ -338,6 +363,15 @@
  * ... should partially interop with the Win32 driver for this hardware
  * The GeneSys docs imply there's some NDIS issue motivating this framing.
  *
+ * Some info from GeneSys:
+ *  - GL620USB-A is full duplex; GL620USB is only half duplex for bulk.
+ *    (Some cables, like the BAFO-100c, use the half duplex version.)
+ *  - For the full duplex model, the low bit of the version code says
+ *    which side is which ("left/right").
+ *  - For the half duplex type, a control/interrupt handshake settles
+ *    the transfer direction.  (That's disabled here, partially coded.)
+ *    A control URB would block until other side writes an interrupt.
+ *
  *-------------------------------------------------------------------------*/
 
 // control msg write command
@@ -504,13 +538,6 @@
 
 #endif
 
-// reset the device status
-static int genelink_reset (struct usbnet *dev)
-{
-	// we don't need to reset, just return 0
-	return 0;
-}
-
 static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb)
 {
 	struct gl_header	*header;
@@ -632,7 +659,6 @@
 static const struct driver_info	genelink_info = {
 	.description =	"Genesys GeneLink",
 	.flags =	FLAG_FRAMING_GL | FLAG_NO_SETINT,
-	.reset =	genelink_reset,
 	.rx_fixup =	genelink_rx_fixup,
 	.tx_fixup =	genelink_tx_fixup,
 
@@ -662,25 +688,19 @@
  *
  * One example is Intel's SA-1100 chip, which integrates basic USB
  * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
+ * And others too, like the Yopy.
  *
  *-------------------------------------------------------------------------*/
 
-static int linuxdev_check_connect (struct usbnet *dev)
-{
-	return 0;		// by definition, always connected
-}
-
 static const struct driver_info	linuxdev_info = {
 	.description =	"Linux Device",
-	// no reset defined (yet?)
-	.check_connect =linuxdev_check_connect,
+
 	.in = 2, .out = 1,
-	.epsize =64,
+	.epsize = 64,
 };
 
 #endif	/* CONFIG_USB_LINUXDEV */
 
-
 
 #ifdef	CONFIG_USB_NET1080
 
@@ -2049,9 +2069,7 @@
 {
 	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
 	.driver_info =	(unsigned long) &an2720_info,
-},
-
-{
+}, {
 	USB_DEVICE (0x0547, 0x2727),	// Xircom PGUNET
 	.driver_info =	(unsigned long) &an2720_info,
 },
@@ -2070,11 +2088,21 @@
 },
 #endif
 
+#ifdef	CONFIG_USB_EPSON2888
+{
+	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
+	driver_info:	(unsigned long) &epson2888_info,
+},
+#endif
+
 #ifdef	CONFIG_USB_GENESYS
 {
 	USB_DEVICE (0x05e3, 0x0502),	// GL620USB-A
 	.driver_info =	(unsigned long) &genelink_info,
 },
+	/* NOT: USB_DEVICE (0x05e3, 0x0501),	// GL620USB
+	 * that's half duplex, not currently supported
+	 */
 #endif
 
 #ifdef	CONFIG_USB_LINUXDEV
@@ -2086,15 +2114,19 @@
 	// 1183 = 0x049F, both used as hex values?
 	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"
 	.driver_info =	(unsigned long) &linuxdev_info,
+}, {
+	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
+	.driver_info =	(unsigned long) &linuxdev_info,
 },
+	// NOTE:  the Sharp Zaurus uses a modified version of
+	// this driver, which is not interoperable with this.
 #endif
 
 #ifdef	CONFIG_USB_NET1080
 {
 	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design
 	.driver_info =	(unsigned long) &net1080_info,
-},
-{
+}, {
 	USB_DEVICE (0x06D0, 0x0622),	// Laplink Gold
 	.driver_info =	(unsigned long) &net1080_info,
 },
diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c	Sun Sep 15 19:19:51 2002
+++ b/drivers/usb/serial/belkin_sa.c	Sun Sep 15 19:19:51 2002
@@ -108,6 +108,7 @@
 	{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
 	{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
 	{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
+	{ USB_DEVICE(GOHUBS_VID, HANDYLINK_PID) },
 	{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
 	{ }							/* Terminating entry */
 };
diff -Nru a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
--- a/drivers/usb/serial/belkin_sa.h	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/serial/belkin_sa.h	Sun Sep 15 19:19:29 2002
@@ -47,6 +47,7 @@
 
 #define GOHUBS_VID	0x0921	/* GoHubs vendor id */
 #define GOHUBS_PID	0x1000	/* GoHubs single port serial converter's id (identical to the Peracom device) */
+#define HANDYLINK_PID	0x1200	/* HandyLink USB's id (identical to the Peracom device) */
 
 /* Vendor Request Interface */
 #define BELKIN_SA_SET_BAUDRATE_REQUEST	0  /* Set baud rate */
diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
--- a/drivers/usb/storage/protocol.c	Sun Sep 15 19:19:28 2002
+++ b/drivers/usb/storage/protocol.c	Sun Sep 15 19:19:28 2002
@@ -54,10 +54,27 @@
  * Helper routines
  ***********************************************************************/
 
-/* Fix-up the return data from an INQUIRY command to show 
+static void *
+find_data_location(Scsi_Cmnd *srb) {
+	if (srb->use_sg) {
+		/*
+		 * This piece of code only works if the first page is
+		 * big enough to hold more than 3 bytes -- which is
+		 * _very_ likely.
+		 */
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) srb->request_buffer;
+		return (void *) page_address(sg[0].page) + sg[0].offset;
+	} else
+		return (void *) srb->request_buffer;
+}
+
+/*
+ * Fix-up the return data from an INQUIRY command to show 
  * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
  */
-void fix_inquiry_data(Scsi_Cmnd *srb)
+static void fix_inquiry_data(Scsi_Cmnd *srb)
 {
 	unsigned char *data_ptr;
 
@@ -65,24 +82,43 @@
 	if (srb->cmnd[0] != INQUIRY)
 		return;
 
-	US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
+	data_ptr = find_data_location(srb);
 
-	/* find the location of the data */
-	if (srb->use_sg) {
-		/* this piece of code only works if the first page is big enough to
-		 * hold more than 3 bytes -- which is _very_ likely
-		 */
-		struct scatterlist *sg;
+	if ((data_ptr[2] & 7) == 2)
+		return;
 
-		sg = (struct scatterlist *) srb->request_buffer;
-		data_ptr = (unsigned char *) page_address(sg[0].page) + sg[0].offset;
-	} else
-		data_ptr = (unsigned char *)srb->request_buffer;
+	US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2 - was %d\n",
+		  data_ptr[2] & 7);
 
 	/* Change the SCSI revision number */
 	data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
+/*
+ * Fix-up the return data from a READ CAPACITY command. My Feiya reader
+ * returns a value that is 1 too large.
+ */
+static void fix_read_capacity(Scsi_Cmnd *srb)
+{
+	unsigned char *dp;
+	unsigned long capacity;
+
+	/* verify that it's a READ CAPACITY command */
+	if (srb->cmnd[0] != READ_CAPACITY)
+		return;
+
+	dp = find_data_location(srb);
+
+	capacity = (dp[0]<<24) + (dp[1]<<16) + (dp[2]<<8) + (dp[3]);
+	US_DEBUGP("US: Fixing capacity: from %ld to %ld\n",
+	       capacity+1, capacity);
+	capacity--;
+	dp[0] = (capacity >> 24);
+	dp[1] = (capacity >> 16);
+	dp[2] = (capacity >> 8);
+	dp[3] = (capacity);
+}
+
 /***********************************************************************
  * Protocol routines
  ***********************************************************************/
@@ -346,8 +382,11 @@
 		if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE))
 			usb_stor_scsiSense10to6(srb);
 
-		/* fix the INQUIRY data if necessary */
+		/* Fix the INQUIRY data if necessary */
 		fix_inquiry_data(srb);
+
+		/* Fix the READ CAPACITY result if necessary */
+		if (us->flags & US_FL_FIX_CAPACITY)
+			fix_read_capacity(srb);
 	}
 }
-
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Sun Sep 15 19:19:34 2002
+++ b/drivers/usb/storage/transport.c	Sun Sep 15 19:19:34 2002
@@ -883,6 +883,9 @@
 		usb_stor_CBI_irq(us->irq_urb);
 	}
 
+	/* Wait for the aborted command to finish */
+	wait_for_completion(&us->notify);
+
 	/* Reacquire the lock */
 	scsi_lock(us->srb->host);
 }
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Sun Sep 15 19:20:18 2002
+++ b/drivers/usb/storage/unusual_devs.h	Sun Sep 15 19:20:18 2002
@@ -310,6 +310,13 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Reported by Blake Matheny <bmatheny@purdue.edu> */
+UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x0113,
+		"Lexar",
+		"USB CF Reader",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Reported by Carlos Villegas <cav@uniscope.co.jp>
  * This device needs an INQUIRY of exactly 36-bytes to function.
  * That is the only reason this entry is needed.
@@ -506,6 +513,13 @@
 		"QV DigitalCamera",
 		US_SC_8070, US_PR_CB, NULL,
 		US_FL_FIX_INQUIRY ),
+
+/* aeb */
+UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
+	        "Feiya",
+	        "5-in-1 Card Reader",
+	        US_SC_SCSI, US_PR_BULK, NULL,
+	        US_FL_FIX_CAPACITY ),
 
 UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x0001,
 		"Minds@Work",
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Sun Sep 15 19:19:29 2002
+++ b/drivers/usb/storage/usb.c	Sun Sep 15 19:19:29 2002
@@ -440,8 +440,14 @@
 		/* Most USB devices can't handle START_STOP.  But we
 		 * need something for media-change, so we'll use TUR
 		 * instead.
+		 *
+		 * We specifically allow this command through if either:
+		 * (a) it's a load/eject command (cmnd[4] & 2)
+		 * (b) it's a multi-target unit (i.e. legacy SCSI adaptor)
 		 */
-		else if (us->srb->cmnd[0] == START_STOP) {
+		else if (us->srb->cmnd[0] == START_STOP &&
+				!(us->srb->cmnd[4] & 2) &&
+				!(us->flags & US_FL_SCM_MULT_TARG)) {
 			unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
 			__u8 old_cmd_len;
 
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Sun Sep 15 19:19:57 2002
+++ b/drivers/usb/storage/usb.h	Sun Sep 15 19:19:57 2002
@@ -102,6 +102,7 @@
 #define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
 #define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets	    */
 #define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing   */
+#define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big  */
 
 #define US_FL_DEV_ATTACHED    0x00010000 /* is the device attached?	    */
 #define US_FLIDX_IP_WANTED   17  /* 0x00020000	is an IRQ expected?	    */
diff -Nru a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c	Sun Sep 15 19:19:37 2002
+++ b/fs/aio.c	Sun Sep 15 19:19:37 2002
@@ -30,10 +30,11 @@
 #include <linux/compiler.h>
 #include <linux/brlock.h>
 #include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/highmem.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
-#include <linux/highmem.h>
 
 #if DEBUG > 1
 #define dprintk		printk
@@ -304,10 +305,25 @@
 		schedule();
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 	}
-	set_task_state(tsk, TASK_RUNNING);
+	__set_task_state(tsk, TASK_RUNNING);
 	remove_wait_queue(&ctx->wait, &wait);
 }
 
+/* wait_on_sync_kiocb:
+ *	Waits on the given sync kiocb to complete.
+ */
+ssize_t wait_on_sync_kiocb(struct kiocb *iocb)
+{
+	while (iocb->ki_users) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (!iocb->ki_users)
+			break;
+		schedule();
+	}
+	__set_current_state(TASK_RUNNING);
+	return iocb->ki_user_data;
+}
+
 /* exit_aio: called when the last user of mm goes away.  At this point, 
  * there is no way for any new requests to be submited or any of the 
  * io_* syscalls to be called on the context.  However, there may be 
@@ -516,12 +532,35 @@
 int aio_complete(struct kiocb *iocb, long res, long res2)
 {
 	struct kioctx	*ctx = iocb->ki_ctx;
-	struct aio_ring_info	*info = &ctx->ring_info;
+	struct aio_ring_info	*info;
 	struct aio_ring	*ring;
 	struct io_event	*event;
 	unsigned long	flags;
 	unsigned long	tail;
 	int		ret;
+
+	/* Special case handling for sync iocbs: events go directly
+	 * into the iocb for fast handling.  Note that this will not 
+	 * work if we allow sync kiocbs to be cancelled. in which
+	 * case the usage count checks will have to move under ctx_lock
+	 * for all cases.
+	 */
+	if (ctx == &ctx->mm->default_kioctx) {
+		int ret;
+
+		iocb->ki_user_data = res;
+		if (iocb->ki_users == 1) {
+			iocb->ki_users = 0;
+			return 1;
+		}
+		spin_lock_irq(&ctx->ctx_lock);
+		iocb->ki_users--;
+		ret = (0 == iocb->ki_users);
+		spin_unlock_irq(&ctx->ctx_lock);
+		return 0;
+	}
+
+	info = &ctx->ring_info;
 
 	/* add a completion event to the ring buffer.
 	 * must be done holding ctx->ctx_lock to prevent
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Sun Sep 15 19:20:24 2002
+++ b/fs/block_dev.c	Sun Sep 15 19:20:24 2002
@@ -116,11 +116,11 @@
 }
 
 static int
-blkdev_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count)
+blkdev_direct_IO(int rw, struct inode *inode, const struct iovec *iov,
+			loff_t offset, unsigned long nr_segs)
 {
-	return generic_direct_IO(rw, inode, buf, offset,
-				count, blkdev_get_blocks);
+	return generic_direct_IO(rw, inode, iov, offset,
+				nr_segs, blkdev_get_blocks);
 }
 
 static int blkdev_writepage(struct page * page)
@@ -787,6 +787,14 @@
 	return res;
 }
 
+static ssize_t blkdev_file_write(struct file *file, const char *buf,
+				   size_t count, loff_t *ppos)
+{
+	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
+
+	return generic_file_write_nolock(file, &local_iov, 1, ppos);
+}
+
 static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
 			unsigned long arg)
 {
@@ -832,26 +840,28 @@
 }
 
 struct address_space_operations def_blk_aops = {
-	readpage: blkdev_readpage,
-	writepage: blkdev_writepage,
-	sync_page: block_sync_page,
-	prepare_write: blkdev_prepare_write,
-	commit_write: blkdev_commit_write,
-	writepages: generic_writepages,
-	vm_writeback: generic_vm_writeback,
-	direct_IO: blkdev_direct_IO,
+	.readpage	= blkdev_readpage,
+	.writepage	= blkdev_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= blkdev_prepare_write,
+	.commit_write	= blkdev_commit_write,
+	.writepages	= generic_writepages,
+	.vm_writeback	= generic_vm_writeback,
+	.direct_IO	= blkdev_direct_IO,
 };
 
 struct file_operations def_blk_fops = {
-	open:		blkdev_open,
-	release:	blkdev_close,
-	llseek:		block_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write_nolock,
-	mmap:		generic_file_mmap,
-	fsync:		block_fsync,
-	ioctl:		blkdev_ioctl,
-	sendfile:	generic_file_sendfile,
+	.open		= blkdev_open,
+	.release	= blkdev_close,
+	.llseek		= block_llseek,
+	.read		= generic_file_read,
+	.write		= blkdev_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= block_fsync,
+	.ioctl		= blkdev_ioctl,
+	.readv		= generic_file_readv,
+	.writev		= generic_file_writev,
+	.sendfile	= generic_file_sendfile,
 };
 
 int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Sun Sep 15 19:19:50 2002
+++ b/fs/buffer.c	Sun Sep 15 19:19:50 2002
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/percpu.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/blkdev.h>
@@ -2513,7 +2514,7 @@
 		 * This only applies in the rare case where try_to_free_buffers
 		 * succeeds but the page is not freed.
 		 */
-		ClearPageDirty(page);
+		clear_page_dirty(page);
 	}
 	spin_unlock(&mapping->private_lock);
 out:
@@ -2555,9 +2556,44 @@
 static kmem_cache_t *bh_cachep;
 static mempool_t *bh_mempool;
 
+/*
+ * Once the number of bh's in the machine exceeds this level, we start
+ * stripping them in writeback.
+ */
+static int max_buffer_heads;
+
+int buffer_heads_over_limit;
+
+struct bh_accounting {
+	int nr;			/* Number of live bh's */
+	int ratelimit;		/* Limit cacheline bouncing */
+};
+
+static DEFINE_PER_CPU(struct bh_accounting, bh_accounting) = {0, 0};
+
+static void recalc_bh_state(void)
+{
+	int i;
+	int tot = 0;
+
+	if (__get_cpu_var(bh_accounting).ratelimit++ < 4096)
+		return;
+	__get_cpu_var(bh_accounting).ratelimit = 0;
+	for (i = 0; i < NR_CPUS; i++)
+		tot += per_cpu(bh_accounting, i).nr;
+	buffer_heads_over_limit = (tot > max_buffer_heads);
+}
+	
 struct buffer_head *alloc_buffer_head(void)
 {
-	return mempool_alloc(bh_mempool, GFP_NOFS);
+	struct buffer_head *ret = mempool_alloc(bh_mempool, GFP_NOFS);
+	if (ret) {
+		preempt_disable();
+		__get_cpu_var(bh_accounting).nr++;
+		recalc_bh_state();
+		preempt_enable();
+	}
+	return ret;
 }
 EXPORT_SYMBOL(alloc_buffer_head);
 
@@ -2565,6 +2601,10 @@
 {
 	BUG_ON(!list_empty(&bh->b_assoc_buffers));
 	mempool_free(bh, bh_mempool);
+	preempt_disable();
+	__get_cpu_var(bh_accounting).nr--;
+	recalc_bh_state();
+	preempt_enable();
 }
 EXPORT_SYMBOL(free_buffer_head);
 
@@ -2595,6 +2635,7 @@
 void __init buffer_init(void)
 {
 	int i;
+	int nrpages;
 
 	bh_cachep = kmem_cache_create("buffer_head",
 			sizeof(struct buffer_head), 0,
@@ -2603,4 +2644,10 @@
 				bh_mempool_free, NULL);
 	for (i = 0; i < ARRAY_SIZE(bh_wait_queue_heads); i++)
 		init_waitqueue_head(&bh_wait_queue_heads[i].wqh);
+
+	/*
+	 * Limit the bh occupancy to 10% of ZONE_NORMAL
+	 */
+	nrpages = (nr_free_buffer_pages() * 10) / 100;
+	max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));
 }
diff -Nru a/fs/direct-io.c b/fs/direct-io.c
--- a/fs/direct-io.c	Sun Sep 15 19:19:50 2002
+++ b/fs/direct-io.c	Sun Sep 15 19:19:50 2002
@@ -75,7 +75,7 @@
  */
 static inline unsigned dio_pages_present(struct dio *dio)
 {
-	return dio->head - dio->tail;
+	return dio->tail - dio->head;
 }
 
 /*
@@ -265,6 +265,10 @@
 static int dio_await_completion(struct dio *dio)
 {
 	int ret = 0;
+
+	if (dio->bio)
+		dio_bio_submit(dio);
+
 	while (atomic_read(&dio->bio_count)) {
 		struct bio *bio = dio_await_one(dio);
 		int ret2;
@@ -523,29 +527,16 @@
 	return ret;
 }
 
-/*
- * The main direct-IO function.  This is a library function for use by
- * filesystem drivers.
- */
 int
-generic_direct_IO(int rw, struct inode *inode, char *buf, loff_t offset,
-			size_t count, get_blocks_t get_blocks)
+direct_io_worker(int rw, struct inode *inode, const struct iovec *iov, 
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks)
 {
 	const unsigned blkbits = inode->i_blkbits;
-	const unsigned blocksize_mask = (1 << blkbits) - 1;
-	const unsigned long user_addr = (unsigned long)buf;
-	int ret;
-	int ret2;
+	unsigned long user_addr; 
+	int seg, ret2, ret = 0;
 	struct dio dio;
-	size_t bytes;
-
-	/* Check the memory alignment.  Blocks cannot straddle pages */
-	if ((user_addr & blocksize_mask) || (count & blocksize_mask)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	size_t bytes, tot_bytes = 0;
 
-	/* BIO submission state */
 	dio.bio = NULL;
 	dio.bvec = NULL;
 	dio.inode = inode;
@@ -553,31 +544,13 @@
 	dio.blkbits = blkbits;
 	dio.block_in_file = offset >> blkbits;
 	dio.blocks_available = 0;
-	dio.final_block_in_request = (offset + count) >> blkbits;
 
-	/* Index into the first page of the first block */
-	dio.first_block_in_page = (user_addr & (PAGE_SIZE - 1)) >> blkbits;
 	dio.boundary = 0;
 	dio.reap_counter = 0;
 	dio.get_blocks = get_blocks;
 	dio.last_block_in_bio = -1;
 	dio.next_block_in_bio = -1;
 
-	/* Page fetching state */
-	dio.curr_page = 0;
-	bytes = count;
-	dio.total_pages = 0;
-	if (user_addr & (PAGE_SIZE - 1)) {
-		dio.total_pages++;
-		bytes -= PAGE_SIZE - (user_addr & (PAGE_SIZE - 1));
-	}
-
-	dio.total_pages += (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
-	dio.curr_user_address = user_addr;
-
-	/* Page queue */
-	dio.head = 0;
-	dio.tail = 0;
 	dio.page_errors = 0;
 
 	/* BIO completion state */
@@ -586,38 +559,75 @@
 	dio.bio_list = NULL;
 	dio.waiter = NULL;
 
-	ret = do_direct_IO(&dio);
+	for (seg = 0; seg < nr_segs; seg++) {
+		user_addr = (unsigned long)iov[seg].iov_base;
+		bytes = iov[seg].iov_len;
+
+		/* Index into the first page of the first block */
+		dio.first_block_in_page = (user_addr & (PAGE_SIZE - 1)) >> blkbits;
+		dio.final_block_in_request = dio.block_in_file + (bytes >> blkbits);
+		/* Page fetching state */
+		dio.head = 0;
+		dio.tail = 0;
+		dio.curr_page = 0;
+
+		dio.total_pages = 0;
+		if (user_addr & (PAGE_SIZE-1)) {
+			dio.total_pages++;
+			bytes -= PAGE_SIZE - (user_addr & (PAGE_SIZE - 1));
+		}
+		dio.total_pages += (bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+		dio.curr_user_address = user_addr;
+	
+		ret = do_direct_IO(&dio);
+
+		if (ret) {
+			dio_cleanup(&dio);
+			break;
+		}
+
+		tot_bytes += iov[seg].iov_len - ((dio.final_block_in_request -
+					dio.block_in_file) << blkbits);
+
+	} /* end iovec loop */
 
-	if (dio.bio)
-		dio_bio_submit(&dio);
-	if (ret)
-		dio_cleanup(&dio);
 	ret2 = dio_await_completion(&dio);
 	if (ret == 0)
 		ret = ret2;
 	if (ret == 0)
 		ret = dio.page_errors;
 	if (ret == 0)
-		ret = count - ((dio.final_block_in_request -
-				dio.block_in_file) << blkbits);
-out:
+		ret = tot_bytes; 
+
 	return ret;
 }
 
-ssize_t
-generic_file_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count)
+/*
+ * This is a library function for use by filesystem drivers.
+ */
+int
+generic_direct_IO(int rw, struct inode *inode, const struct iovec *iov, 
+	loff_t offset, unsigned long nr_segs, get_blocks_t get_blocks)
 {
+	int seg;
+	size_t size;
+	unsigned long addr;
 	struct address_space *mapping = inode->i_mapping;
-	unsigned blocksize_mask;
-	ssize_t retval;
+	unsigned blocksize_mask = (1 << inode->i_blkbits) - 1;
+	ssize_t retval = -EINVAL;
 
-	blocksize_mask = (1 << inode->i_blkbits) - 1;
-	if ((offset & blocksize_mask) || (count & blocksize_mask)) {
-		retval = -EINVAL;
+	if (offset & blocksize_mask) {
 		goto out;
 	}
 
+	/* Check the memory alignment.  Blocks cannot straddle pages */
+	for (seg = 0; seg < nr_segs; seg++) {
+		addr = (unsigned long)iov[seg].iov_base;
+		size = iov[seg].iov_len;
+		if ((addr & blocksize_mask) || (size & blocksize_mask)) 
+			goto out;	
+	}
+
 	if (mapping->nrpages) {
 		retval = filemap_fdatawrite(mapping);
 		if (retval == 0)
@@ -625,9 +635,21 @@
 		if (retval)
 			goto out;
 	}
-	retval = mapping->a_ops->direct_IO(rw, inode, buf, offset, count);
+
+	retval = direct_io_worker(rw, inode, iov, offset, nr_segs, get_blocks);
+out:
+	return retval;
+}
+
+ssize_t
+generic_file_direct_IO(int rw, struct inode *inode, const struct iovec *iov, 
+	loff_t offset, unsigned long nr_segs)
+{
+	struct address_space *mapping = inode->i_mapping;
+	ssize_t retval;
+
+	retval = mapping->a_ops->direct_IO(rw, inode, iov, offset, nr_segs);
 	if (inode->i_mapping->nrpages)
 		invalidate_inode_pages2(inode->i_mapping);
-out:
 	return retval;
 }
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Sun Sep 15 19:19:29 2002
+++ b/fs/driverfs/inode.c	Sun Sep 15 19:19:29 2002
@@ -32,6 +32,7 @@
 #include <linux/namei.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/backing-dev.h>
 #include <linux/driverfs_fs.h>
 
 #include <asm/uaccess.h>
@@ -56,6 +57,11 @@
 static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
 static int mount_count = 0;
 
+static struct backing_dev_info driverfs_backing_dev_info = {
+	.ra_pages	= 0,	/* No readahead */
+	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+};
+
 static int driverfs_readpage(struct file *file, struct page * page)
 {
 	if (!PageUptodate(page)) {
@@ -108,6 +114,7 @@
 		inode->i_rdev = NODEV;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		inode->i_mapping->a_ops = &driverfs_aops;
+		inode->i_mapping->backing_dev_info = &driverfs_backing_dev_info;
 		switch (mode & S_IFMT) {
 		default:
 			init_special_inode(inode, mode, dev);
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Sun Sep 15 19:19:34 2002
+++ b/fs/exec.c	Sun Sep 15 19:19:34 2002
@@ -40,6 +40,7 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/namei.h>
+#include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -493,50 +494,153 @@
 	return 0;
 }
 
+static struct dentry *clean_proc_dentry(struct task_struct *p)
+{
+	struct dentry *proc_dentry = p->proc_dentry;
+
+	if (proc_dentry) {
+		spin_lock(&dcache_lock);
+		if (!list_empty(&proc_dentry->d_hash)) {
+			dget_locked(proc_dentry);
+			list_del_init(&proc_dentry->d_hash);
+		} else
+			proc_dentry = NULL;
+		spin_unlock(&dcache_lock);
+	}
+	return proc_dentry;
+}
+
+static inline void put_proc_dentry(struct dentry *dentry)
+{
+	if (dentry) {
+		shrink_dcache_parent(dentry);
+		dput(dentry);
+	}
+}
+
 /*
  * This function makes sure the current process has its own signal table,
  * so that flush_signal_handlers can later reset the handlers without
  * disturbing other processes.  (Other processes might share the signal
- * table via the CLONE_SIGNAL option to clone().)
+ * table via the CLONE_SIGHAND option to clone().)
  */
- 
-static inline int make_private_signals(void)
+static inline int de_thread(struct signal_struct *oldsig)
 {
-	struct signal_struct * newsig;
-
-	remove_thread_group(current, current->sig);
+	struct signal_struct *newsig;
+	int count;
 
 	if (atomic_read(&current->sig->count) <= 1)
 		return 0;
+
 	newsig = kmem_cache_alloc(sigact_cachep, GFP_KERNEL);
-	if (newsig == NULL)
+	if (!newsig)
 		return -ENOMEM;
+
+	if (list_empty(&current->thread_group))
+		goto out;
+	/*
+	 * Kill all other threads in the thread group:
+	 */
+	spin_lock_irq(&oldsig->siglock);
+	if (oldsig->group_exit) {
+		/*
+		 * Another group action in progress, just
+		 * return so that the signal is processed.
+		 */
+		spin_unlock_irq(&oldsig->siglock);
+		kmem_cache_free(sigact_cachep, newsig);
+		return -EAGAIN;
+	}
+	oldsig->group_exit = 1;
+	__broadcast_thread_group(current, SIGKILL);
+
+	/*
+	 * Account for the thread group leader hanging around:
+	 */
+	count = 2;
+	if (current->pid == current->tgid)
+		count = 1;
+	while (atomic_read(&oldsig->count) > count) {
+		oldsig->group_exit_task = current;
+		current->state = TASK_UNINTERRUPTIBLE;
+		spin_unlock_irq(&oldsig->siglock);
+		schedule();
+		spin_lock_irq(&oldsig->siglock);
+		if (oldsig->group_exit_task)
+			BUG();
+	}
+	spin_unlock_irq(&oldsig->siglock);
+
+	/*
+	 * At this point all other threads have exited, all we have to
+	 * do is to wait for the thread group leader to become inactive,
+	 * and to assume its PID:
+	 */
+	if (current->pid != current->tgid) {
+		struct task_struct *leader = current->group_leader;
+		struct dentry *proc_dentry1, *proc_dentry2;
+		unsigned long state;
+
+		wait_task_inactive(leader);
+
+		write_lock_irq(&tasklist_lock);
+		proc_dentry1 = clean_proc_dentry(current);
+		proc_dentry2 = clean_proc_dentry(leader);
+
+		if (leader->tgid != current->tgid)
+			BUG();
+		if (current->pid == current->tgid)
+			BUG();
+		/*
+		 * An exec() starts a new thread group with the
+		 * TGID of the previous thread group. Rehash the
+		 * two threads with a switched PID, and release
+		 * the former thread group leader:
+		 */
+		unhash_pid(current);
+		unhash_pid(leader);
+		leader->pid = leader->tgid = current->pid;
+		current->pid = current->tgid;
+		hash_pid(current);
+		hash_pid(leader);
+		
+		list_add_tail(&current->tasks, &init_task.tasks);
+		state = leader->state;
+		write_unlock_irq(&tasklist_lock);
+
+		if (state == TASK_ZOMBIE)
+			release_task(leader);
+
+		put_proc_dentry(proc_dentry1);
+		put_proc_dentry(proc_dentry2);
+        }
+
+out:
 	spin_lock_init(&newsig->siglock);
 	atomic_set(&newsig->count, 1);
+	newsig->group_exit = 0;
+	newsig->group_exit_code = 0;
+	newsig->group_exit_task = NULL;
 	memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
 	init_sigpending(&newsig->shared_pending);
 
+	remove_thread_group(current, current->sig);
 	spin_lock_irq(&current->sigmask_lock);
 	current->sig = newsig;
+	init_sigpending(&current->pending);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
-	return 0;
-}
-	
-/*
- * If make_private_signals() made a copy of the signal table, decrement the
- * refcount of the original table, and free it if necessary.
- * We don't do that in make_private_signals() so that we can back off
- * in flush_old_exec() if an error occurs after calling make_private_signals().
- */
 
-static inline void release_old_signals(struct signal_struct * oldsig)
-{
-	if (current->sig == oldsig)
-		return;
 	if (atomic_dec_and_test(&oldsig->count))
 		kmem_cache_free(sigact_cachep, oldsig);
-}
 
+	if (!list_empty(&current->thread_group))
+		BUG();
+	if (current->tgid != current->pid)
+		BUG();
+	return 0;
+}
+	
 /*
  * These functions flushes out all traces of the currently running executable
  * so that a new one can be started
@@ -570,44 +674,27 @@
 	write_unlock(&files->file_lock);
 }
 
-/*
- * An execve() will automatically "de-thread" the process.
- * - if a master thread (PID==TGID) is doing this, then all subsidiary threads
- *   will be killed (otherwise there will end up being two independent thread
- *   groups with the same TGID).
- * - if a subsidary thread is doing this, then it just leaves the thread group
- */
-static void de_thread(struct task_struct *tsk)
-{
-	if (!list_empty(&tsk->thread_group))
-		BUG();
-	/* An exec() starts a new thread group: */
-	tsk->tgid = tsk->pid;
-}
-
 int flush_old_exec(struct linux_binprm * bprm)
 {
 	char * name;
 	int i, ch, retval;
-	struct signal_struct * oldsig;
-
-	/*
-	 * Make sure we have a private signal table
-	 */
-	oldsig = current->sig;
-	retval = make_private_signals();
-	if (retval) goto flush_failed;
+	struct signal_struct * oldsig = current->sig;
 
 	/* 
 	 * Release all of the old mmap stuff
 	 */
 	retval = exec_mmap(bprm->mm);
-	if (retval) goto mmap_failed;
+	if (retval)
+		goto mmap_failed;
+	/*
+	 * Make sure we have a private signal table and that
+	 * we are unassociated from the previous thread group.
+	 */
+	retval = de_thread(oldsig);
+	if (retval)
+		goto flush_failed;
 
 	/* This is the point of no return */
-	de_thread(current);
-
-	release_old_signals(oldsig);
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c
--- a/fs/ext2/file.c	Sun Sep 15 19:19:30 2002
+++ b/fs/ext2/file.c	Sun Sep 15 19:19:30 2002
@@ -46,6 +46,8 @@
 	.open		= generic_file_open,
 	.release	= ext2_release_file,
 	.fsync		= ext2_sync_file,
+	.readv		= generic_file_readv,
+	.writev		= generic_file_writev,
 	.sendfile	= generic_file_sendfile,
 };
 
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Sun Sep 15 19:19:29 2002
+++ b/fs/ext2/inode.c	Sun Sep 15 19:19:29 2002
@@ -619,11 +619,11 @@
 }
 
 static int
-ext2_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count)
+ext2_direct_IO(int rw, struct inode *inode, const struct iovec *iov,
+			loff_t offset, unsigned long nr_segs)
 {
-	return generic_direct_IO(rw, inode, buf,
-				offset, count, ext2_get_blocks);
+	return generic_direct_IO(rw, inode, iov,
+				offset, nr_segs, ext2_get_blocks);
 }
 
 static int
diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c
--- a/fs/ext3/file.c	Sun Sep 15 19:20:24 2002
+++ b/fs/ext3/file.c	Sun Sep 15 19:20:24 2002
@@ -76,19 +76,21 @@
 }
 
 struct file_operations ext3_file_operations = {
-	.llseek		= generic_file_llseek,	/* BKL held */
-	.read		= generic_file_read,	/* BKL not held.  Don't need */
-	.write		= ext3_file_write,	/* BKL not held.  Don't need */
-	.ioctl		= ext3_ioctl,		/* BKL held */
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= ext3_file_write,
+	.readv		= generic_file_readv,
+	.writev		= generic_file_writev,
+	.ioctl		= ext3_ioctl,
 	.mmap		= generic_file_mmap,
-	.open		= ext3_open_file,		/* BKL not held.  Don't need */
-	.release	= ext3_release_file,	/* BKL not held.  Don't need */
-	.fsync		= ext3_sync_file,		/* BKL held */
-	.sendfile	= generic_file_sendfile,	/* BKL not held.  Don't need */
+	.open		= ext3_open_file,
+	.release	= ext3_release_file,
+	.fsync		= ext3_sync_file,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations ext3_file_inode_operations = {
-	.truncate	= ext3_truncate,		/* BKL held */
-	.setattr	= ext3_setattr,		/* BKL held */
+	.truncate	= ext3_truncate,
+	.setattr	= ext3_setattr,
 };
 
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Sun Sep 15 19:20:00 2002
+++ b/fs/ext3/inode.c	Sun Sep 15 19:20:00 2002
@@ -1399,13 +1399,15 @@
  * If the O_DIRECT write is intantiating holes inside i_size and the machine
  * crashes then stale disk data _may_ be exposed inside the file.
  */
-static int ext3_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count)
+static int ext3_direct_IO(int rw, struct inode *inode,
+			const struct iovec *iov, loff_t offset,
+			unsigned long nr_segs)
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	handle_t *handle = NULL;
 	int ret;
 	int orphan = 0;
+	size_t count = iov_length(iov, nr_segs);
 
 	if (rw == WRITE) {
 		loff_t final_size = offset + count;
@@ -1428,8 +1430,8 @@
 		}
 	}
 
-	ret = generic_direct_IO(rw, inode, buf, offset,
-				count, ext3_direct_io_get_blocks);
+	ret = generic_direct_IO(rw, inode, iov, offset,
+				nr_segs, ext3_direct_io_get_blocks);
 
 out_stop:
 	if (handle) {
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Sun Sep 15 19:19:29 2002
+++ b/fs/fcntl.c	Sun Sep 15 19:19:29 2002
@@ -493,7 +493,7 @@
 		send_sigio_to_task(p, fown, fd, band);
 		goto out_unlock_task;
 	}
-	for_each_task(p) {
+	for_each_process(p) {
 		int match = p->pid;
 		if (pid < 0)
 			match = -p->pgrp;
@@ -531,7 +531,7 @@
 		send_sigurg_to_task(p, fown);
 		goto out_unlock_task;
 	}
-	for_each_task(p) {
+	for_each_process(p) {
 		int match = p->pid;
 		if (pid < 0)
 			match = -p->pgrp;
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Sun Sep 15 19:19:46 2002
+++ b/fs/fs-writeback.c	Sun Sep 15 19:19:46 2002
@@ -134,8 +134,6 @@
 	struct address_space *mapping = inode->i_mapping;
 	struct super_block *sb = inode->i_sb;
 
-	list_move(&inode->i_list, &sb->s_locked_inodes);
-
 	BUG_ON(inode->i_state & I_LOCK);
 
 	/* Set I_LOCK, reset I_DIRTY */
@@ -163,12 +161,12 @@
 		if (inode->i_state & I_DIRTY) {		/* Redirtied */
 			list_add(&inode->i_list, &sb->s_dirty);
 		} else {
-			if (!list_empty(&mapping->dirty_pages)) {
+			if (!list_empty(&mapping->dirty_pages) ||
+					!list_empty(&mapping->io_pages)) {
 			 	/* Not a whole-file writeback */
 				mapping->dirtied_when = orig_dirtied_when;
 				inode->i_state |= I_DIRTY_PAGES;
-				list_add_tail(&inode->i_list,
-						&sb->s_dirty);
+				list_add_tail(&inode->i_list, &sb->s_dirty);
 			} else if (atomic_read(&inode->i_count)) {
 				list_add(&inode->i_list, &inode_in_use);
 			} else {
@@ -205,7 +203,7 @@
  * If older_than_this is non-NULL, then only write out mappings which
  * had their first dirtying at a time earlier than *older_than_this.
  *
- * If we're a pdlfush thread, then implement pdlfush collision avoidance
+ * If we're a pdlfush thread, then implement pdflush collision avoidance
  * against the entire list.
  *
  * WB_SYNC_HOLD is a hack for sys_sync(): reattach the inode to sb->s_dirty so
@@ -221,6 +219,11 @@
  * FIXME: this linear search could get expensive with many fileystems.  But
  * how to fix?  We need to go from an address_space to all inodes which share
  * a queue with that address_space.
+ *
+ * The inodes to be written are parked on sb->s_io.  They are moved back onto
+ * sb->s_dirty as they are selected for writing.  This way, none can be missed
+ * on the writer throttling path, and we get decent balancing between many
+ * thrlttled threads: we don't want them all piling up on __wait_on_inode.
  */
 static void
 sync_sb_inodes(struct backing_dev_info *single_bdi, struct super_block *sb,
@@ -241,7 +244,7 @@
 		if (single_bdi && mapping->backing_dev_info != single_bdi) {
 			if (sb != blockdev_superblock)
 				break;		/* inappropriate superblock */
-			list_move(&inode->i_list, &inode->i_sb->s_dirty);
+			list_move(&inode->i_list, &sb->s_dirty);
 			continue;		/* not this blockdev */
 		}
 
@@ -263,10 +266,11 @@
 
 		BUG_ON(inode->i_state & I_FREEING);
 		__iget(inode);
+		list_move(&inode->i_list, &sb->s_dirty);
 		__writeback_single_inode(inode, really_sync, nr_to_write);
 		if (sync_mode == WB_SYNC_HOLD) {
 			mapping->dirtied_when = jiffies;
-			list_move(&inode->i_list, &inode->i_sb->s_dirty);
+			list_move(&inode->i_list, &sb->s_dirty);
 		}
 		if (current_is_pdflush())
 			writeback_release(bdi);
@@ -278,9 +282,8 @@
 	}
 out:
 	/*
-	 * Put the rest back, in the correct order.
+	 * Leave any unwritten inodes on s_io.
 	 */
-	list_splice_init(&sb->s_io, sb->s_dirty.prev);
 	return;
 }
 
@@ -302,7 +305,7 @@
 	spin_lock(&sb_lock);
 	sb = sb_entry(super_blocks.prev);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
-		if (!list_empty(&sb->s_dirty)) {
+		if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) {
 			spin_unlock(&sb_lock);
 			sync_sb_inodes(bdi, sb, sync_mode, nr_to_write,
 					older_than_this);
@@ -321,7 +324,7 @@
  * Note:
  * We don't need to grab a reference to superblock here. If it has non-empty
  * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
- * past sync_inodes_sb() until both ->s_dirty and ->s_locked_inodes are
+ * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are
  * empty. Since __sync_single_inode() regains inode_lock before it finally moves
  * inode from superblock lists we are OK.
  *
@@ -352,19 +355,6 @@
 				sync_mode, older_than_this);
 }
 
-static void __wait_on_locked(struct list_head *head)
-{
-	struct list_head * tmp;
-	while ((tmp = head->prev) != head) {
-		struct inode *inode = list_entry(tmp, struct inode, i_list);
-		__iget(inode);
-		spin_unlock(&inode_lock);
-		__wait_on_inode(inode);
-		iput(inode);
-		spin_lock(&inode_lock);
-	}
-}
-
 /*
  * writeback and wait upon the filesystem's dirty inodes.  The caller will
  * do this in two passes - one to write, and one to wait.  WB_SYNC_HOLD is
@@ -384,8 +374,6 @@
 	spin_lock(&inode_lock);
 	sync_sb_inodes(NULL, sb, wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
 				&nr_to_write, NULL);
-	if (wait)
-		__wait_on_locked(&sb->s_locked_inodes);
 	spin_unlock(&inode_lock);
 }
 
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Sun Sep 15 19:20:24 2002
+++ b/fs/inode.c	Sun Sep 15 19:20:24 2002
@@ -321,7 +321,6 @@
 	busy |= invalidate_list(&inode_unused, sb, &throw_away);
 	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
 	busy |= invalidate_list(&sb->s_io, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_locked_inodes, sb, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
@@ -995,11 +994,6 @@
 			remove_inode_dquot_ref(inode, type, &tofree_head);
 	}
 	list_for_each(act_head, &sb->s_io) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, &tofree_head);
-	}
-	list_for_each(act_head, &sb->s_locked_inodes) {
 		inode = list_entry(act_head, struct inode, i_list);
 		if (IS_QUOTAINIT(inode))
 			remove_inode_dquot_ref(inode, type, &tofree_head);
diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c
--- a/fs/jfs/file.c	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/file.c	Sun Sep 15 19:19:29 2002
@@ -108,6 +108,8 @@
 	.write		= generic_file_write,
 	.read		= generic_file_read,
 	.mmap		= generic_file_mmap,
+	.readv		= generic_file_readv,
+	.writev		= generic_file_writev,
  	.sendfile	= generic_file_sendfile,
 	.fsync		= jfs_fsync,
 };
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/inode.c	Sun Sep 15 19:19:28 2002
@@ -309,11 +309,11 @@
 	return generic_block_bmap(mapping, block, jfs_get_block);
 }
 
-static int jfs_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count)
+static int jfs_direct_IO(int rw, struct inode *inode, const struct iovec *iov, 
+			loff_t offset, unsigned long nr_segs)
 {
-	return generic_direct_IO(rw, inode, buf,
-				offset, count, jfs_get_blocks);
+	return generic_direct_IO(rw, inode, iov,
+				offset, nr_segs, jfs_get_blocks);
 }
 
 struct address_space_operations jfs_aops = {
diff -Nru a/fs/jfs/jfs_btree.h b/fs/jfs/jfs_btree.h
--- a/fs/jfs/jfs_btree.h	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/jfs_btree.h	Sun Sep 15 19:19:28 2002
@@ -25,18 +25,18 @@
  */
 
 /*
- *	basic btree page - btpage_t
- */
-typedef struct {
-	s64 next;		/* 8: right sibling bn */
-	s64 prev;		/* 8: left sibling bn */
-
-	u8 flag;		/* 1: */
-	u8 rsrvd[7];		/* 7: type specific */
-	s64 self;		/* 8: self address */
+ *	basic btree page - btpage
+ *
+struct btpage {
+	s64 next;		right sibling bn
+	s64 prev;		left sibling bn
+
+	u8 flag;
+	u8 rsrvd[7];		type specific
+	s64 self;		self address
 
-	u8 entry[4064];		/* 4064: */
-} btpage_t;			/* (4096) */
+	u8 entry[4064];
+};						*/
 
 /* btpaget_t flag */
 #define BT_TYPE		0x07	/* B+-tree index */
@@ -68,7 +68,7 @@
 {\
 	if ((BN) == 0)\
 	{\
-		MP = (metapage_t *)&JFS_IP(IP)->bxflag;\
+		MP = (struct metapage *)&JFS_IP(IP)->bxflag;\
 		P = (TYPE *)&JFS_IP(IP)->ROOT;\
 		RC = 0;\
 		jEVENT(0,("%d BT_GETPAGE returning root\n", __LINE__));\
@@ -112,18 +112,18 @@
  * top frame record the leaf page/entry selected.
  */
 #define	MAXTREEHEIGHT		8
-typedef struct btframe {	/* stack frame */
+struct btframe {	/* stack frame */
 	s64 bn;			/* 8: */
 	s16 index;		/* 2: */
 	s16 lastindex;		/* 2: */
 	struct metapage *mp;	/* 4: */
-} btframe_t;			/* (16) */
+};				/* (16) */
 
-typedef struct btstack {
-	btframe_t *top;		/* 4: */
-	int nsplit;		/* 4: */
-	btframe_t stack[MAXTREEHEIGHT];
-} btstack_t;
+struct btstack {
+	struct btframe *top;
+	int nsplit;
+	struct btframe stack[MAXTREEHEIGHT];
+};
 
 #define BT_CLR(btstack)\
 	(btstack)->top = (btstack)->stack
diff -Nru a/fs/jfs/jfs_defragfs.h b/fs/jfs/jfs_defragfs.h
--- a/fs/jfs/jfs_defragfs.h	Sun Sep 15 19:20:00 2002
+++ b/fs/jfs/jfs_defragfs.h	Sun Sep 15 19:20:00 2002
@@ -21,7 +21,7 @@
 /*
  *	defragfs parameter list
  */
-typedef struct {
+struct defragfs {
 	uint flag;		/* 4: */
 	u8 dev;			/* 1: */
 	u8 pad[3];		/* 3: */
@@ -33,7 +33,7 @@
 	s64 old_xaddr;		/* 8: */
 	s64 new_xaddr;		/* 8: */
 	s32 xlen;		/* 4: */
-} defragfs_t;			/* (52) */
+};
 
 /* plist flag */
 #define DEFRAGFS_SYNC		0x80000000
diff -Nru a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h
--- a/fs/jfs/jfs_dinode.h	Sun Sep 15 19:19:34 2002
+++ b/fs/jfs/jfs_dinode.h	Sun Sep 15 19:19:34 2002
@@ -28,7 +28,7 @@
 
 
 /*
- *      on-disk inode (dinode_t): 512 bytes
+ *      on-disk inode : 512 bytes
  *
  * note: align 64-bit fields on 8-byte boundary.
  */
@@ -89,7 +89,7 @@
 			 * If the index is small enough, the table is inline,
 			 * otherwise, an x-tree root overlays this table
 			 */
-			dir_table_slot_t _table[12];	/* 96: inline */
+			struct dir_table_slot _table[12]; /* 96: inline */
 
 			dtroot_t _dtroot;		/* 288: dtree root */
 		} _dir;					/* (384) */
@@ -130,9 +130,6 @@
 #define di_inlineea     u._file._u2._special._inlineea
 	} u;
 };
-
-typedef struct dinode dinode_t;
-
 
 /* extended mode bits (on-disk inode di_mode) */
 #define IFJOURNAL       0x00010000	/* journalled file */
diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	Sun Sep 15 19:20:20 2002
+++ b/fs/jfs/jfs_dmap.c	Sun Sep 15 19:20:20 2002
@@ -100,30 +100,37 @@
 /*
  * forward references
  */
-static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			int nblocks);
 static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);
 static void dbBackSplit(dmtree_t * tp, int leafno);
 static void dbJoin(dmtree_t * tp, int leafno, int newval);
 static void dbAdjTree(dmtree_t * tp, int leafno, int newval);
-static int dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc,
+static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,
 		    int level);
-static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results);
-static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
-static int dbAllocNear(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks,
+static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);
+static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbAllocNear(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks,
 		       int l2nb, s64 * results);
-static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
-static int dbAllocDmapLev(bmap_t * bmp, dmap_t * dp, int nblocks, int l2nb,
+static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbAllocDmapLev(struct bmap * bmp, struct dmap * dp, int nblocks,
+			  int l2nb,
 			  s64 * results);
-static int dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb,
+static int dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb,
 		     s64 * results);
-static int dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno,
+static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno,
 		      s64 * results);
 int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);
 static int dbFindBits(u32 word, int l2nb);
-static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno);
+static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno);
 static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);
-static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
-static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static void dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks);
+static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		      int nblocks);
 static int dbMaxBud(u8 * cp);
 s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
 int blkstol2(s64 nb);
@@ -132,12 +139,12 @@
 int cntlz(u32 value);
 int cnttz(u32 word);
 
-static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno,
+static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
 			 int nblocks);
-static int dbInitDmap(dmap_t * dp, s64 blkno, int nblocks);
-static int dbInitDmapTree(dmap_t * dp);
-static int dbInitTree(dmaptree_t * dtp);
-static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i);
+static int dbInitDmap(struct dmap * dp, s64 blkno, int nblocks);
+static int dbInitDmapTree(struct dmap * dp);
+static int dbInitTree(struct dmaptree * dtp);
+static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i);
 static int dbGetL2AGSize(s64 nblocks);
 
 /*
@@ -186,16 +193,16 @@
  */
 int dbMount(struct inode *ipbmap)
 {
-	bmap_t *bmp;
-	dbmap_t *dbmp_le;
-	metapage_t *mp;
+	struct bmap *bmp;
+	struct dbmap *dbmp_le;
+	struct metapage *mp;
 	int i;
 
 	/*
 	 * allocate/initialize the in-memory bmap descriptor
 	 */
 	/* allocate memory for the in-memory bmap descriptor */
-	bmp = kmalloc(sizeof(bmap_t), GFP_KERNEL);
+	bmp = kmalloc(sizeof(struct bmap), GFP_KERNEL);
 	if (bmp == NULL)
 		return (ENOMEM);
 
@@ -209,7 +216,7 @@
 	}
 
 	/* copy the on-disk bmap descriptor to its in-memory version. */
-	dbmp_le = (dbmap_t *) mp->data;
+	dbmp_le = (struct dbmap *) mp->data;
 	bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);
 	bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
 	bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
@@ -263,7 +270,7 @@
  */
 int dbUnmount(struct inode *ipbmap, int mounterror)
 {
-	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
 
 	if (!(mounterror || isReadOnly(ipbmap)))
 		dbSync(ipbmap);
@@ -284,9 +291,9 @@
  */
 int dbSync(struct inode *ipbmap)
 {
-	dbmap_t *dbmp_le;
-	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
-	metapage_t *mp;
+	struct dbmap *dbmp_le;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct metapage *mp;
 	int i;
 
 	/*
@@ -301,7 +308,7 @@
 		return (EIO);
 	}
 	/* copy the in-memory version of the bmap to the on-disk version */
-	dbmp_le = (dbmap_t *) mp->data;
+	dbmp_le = (struct dbmap *) mp->data;
 	dbmp_le->dn_mapsize = cpu_to_le64(bmp->db_mapsize);
 	dbmp_le->dn_nfree = cpu_to_le64(bmp->db_nfree);
 	dbmp_le->dn_l2nbperpage = cpu_to_le32(bmp->db_l2nbperpage);
@@ -355,12 +362,12 @@
  */
 int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
 {
-	metapage_t *mp;
-	dmap_t *dp;
+	struct metapage *mp;
+	struct dmap *dp;
 	int nb, rc;
 	s64 lblkno, rem;
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
 	IREAD_LOCK(ipbmap);
 
@@ -384,7 +391,7 @@
 			IREAD_UNLOCK(ipbmap);
 			return (EIO);
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* determine the number of blocks to be freed from
 		 * this dmap.
@@ -435,16 +442,16 @@
  */
 int
 dbUpdatePMap(struct inode *ipbmap,
-	     int free, s64 blkno, s64 nblocks, tblock_t * tblk)
+	     int free, s64 blkno, s64 nblocks, struct tblock * tblk)
 {
 	int nblks, dbitno, wbitno, rbits;
 	int word, nbits, nwords;
-	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
 	s64 lblkno, rem, lastlblkno;
 	u32 mask;
-	dmap_t *dp;
-	metapage_t *mp;
-	log_t *log;
+	struct dmap *dp;
+	struct metapage *mp;
+	struct jfs_log *log;
 	int lsn, difft, diffp;
 
 	/* the blocks better be within the mapsize. */
@@ -452,7 +459,7 @@
 
 	/* compute delta of transaction lsn from log syncpt */
 	lsn = tblk->lsn;
-	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
 	logdiff(difft, lsn, log);
 
 	/*
@@ -473,7 +480,7 @@
 			if (mp == NULL)
 				return (EIO);
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* determine the bit number and word within the dmap of
 		 * the starting block.  also determine how many blocks
@@ -619,7 +626,7 @@
 {
 	s64 avgfree, inactfree, actfree, rem;
 	int actags, inactags, l2agsize;
-	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
 
 	BMAP_LOCK(bmp);
 
@@ -737,10 +744,10 @@
 {
 	int rc, agno;
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	bmap_t *bmp;
-	metapage_t *mp;
+	struct bmap *bmp;
+	struct metapage *mp;
 	s64 lblkno, blkno;
-	dmap_t *dp;
+	struct dmap *dp;
 	int l2nb;
 	s64 mapSize;
 
@@ -832,7 +839,7 @@
 		if (mp == NULL)
 			goto read_unlock;
 
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* first, try to satisfy the allocation request with the
 		 * blocks beginning at the hint.
@@ -933,10 +940,10 @@
 {
 	int rc;
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
-	dmap_t *dp;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
+	struct dmap *dp;
 	s64 lblkno;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	IREAD_LOCK(ipbmap);
 
@@ -965,7 +972,7 @@
 		IREAD_UNLOCK(ipbmap);
 		return (EIO);
 	}
-	dp = (dmap_t *) mp->data;
+	dp = (struct dmap *) mp->data;
 
 	/* try to allocate the requested extent */
 	rc = dbAllocNext(bmp, dp, blkno, nblocks);
@@ -1068,11 +1075,11 @@
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	s64 lblkno, lastblkno, extblkno;
 	uint rel_block;
-	metapage_t *mp;
-	dmap_t *dp;
+	struct metapage *mp;
+	struct dmap *dp;
 	int rc;
 	struct inode *ipbmap = sbi->ipbmap;
-	bmap_t *bmp;
+	struct bmap *bmp;
 
 	/*
 	 * We don't want a non-aligned extent to cross a page boundary
@@ -1120,7 +1127,7 @@
 	}
 
 	DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
-	dp = (dmap_t *) mp->data;
+	dp = (struct dmap *) mp->data;
 
 	/* try to allocate the blocks immediately following the
 	 * current allocation.
@@ -1163,7 +1170,8 @@
  *
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
-static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
 {
 	int dbitno, word, rembits, nb, nwords, wbitno, nw;
 	int l2size;
@@ -1289,8 +1297,8 @@
  * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
  */
 static int
-dbAllocNear(bmap_t * bmp,
-	    dmap_t * dp, s64 blkno, int nblocks, int l2nb, s64 * results)
+dbAllocNear(struct bmap * bmp,
+	    struct dmap * dp, s64 blkno, int nblocks, int l2nb, s64 * results)
 {
 	int word, lword, rc;
 	s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
@@ -1391,10 +1399,10 @@
  * note: IWRITE_LOCK(ipmap) held on entry/exit;
  */
 static int
-dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
+dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
 {
-	metapage_t *mp;
-	dmapctl_t *dcp;
+	struct metapage *mp;
+	struct dmapctl *dcp;
 	int rc, ti, i, k, m, n, agperlev;
 	s64 blkno, lblkno;
 	int budmin;
@@ -1447,7 +1455,7 @@
 	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL)
 		return (EIO);
-	dcp = (dmapctl_t *) mp->data;
+	dcp = (struct dmapctl *) mp->data;
 	budmin = dcp->budmin;
 
 	/* search the subtree(s) of the dmap control page that describes
@@ -1566,7 +1574,7 @@
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results)
+static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results)
 {
 	int rc;
 	s64 blkno = 0;
@@ -1616,13 +1624,13 @@
  *
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno)
+static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
 {
 	int rc, leafidx, lev;
 	s64 b, lblkno;
-	dmapctl_t *dcp;
+	struct dmapctl *dcp;
 	int budmin;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	/* starting at the specified dmap control page level and block
 	 * number, search down the dmap control levels for the starting
@@ -1637,7 +1645,7 @@
 		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL)
 			return (EIO);
-		dcp = (dmapctl_t *) mp->data;
+		dcp = (struct dmapctl *) mp->data;
 		budmin = dcp->budmin;
 
 		/* search the tree within the dmap control page for
@@ -1724,12 +1732,12 @@
  * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
  */
 static int
-dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
+dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
 {
 	int rc, nb;
 	s64 b, lblkno, n;
-	metapage_t *mp;
-	dmap_t *dp;
+	struct metapage *mp;
+	struct dmap *dp;
 
 	/* check if the allocation request is confined to a single dmap.
 	 */
@@ -1740,7 +1748,7 @@
 		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 		if (mp == NULL)
 			return (EIO);
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* try to allocate the blocks.
 		 */
@@ -1769,7 +1777,7 @@
 			rc = EIO;
 			goto backout;
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* the dmap better be all free.
 		 */
@@ -1821,7 +1829,7 @@
 			       ("dbAllocCtl: I/O Error: Block Leakage.\n"));
 			continue;
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* free the blocks is this dmap.
 		 */
@@ -1871,8 +1879,8 @@
  *	IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
  */
 static int
-dbAllocDmapLev(bmap_t * bmp,
-	       dmap_t * dp, int nblocks, int l2nb, s64 * results)
+dbAllocDmapLev(struct bmap * bmp,
+	       struct dmap * dp, int nblocks, int l2nb, s64 * results)
 {
 	s64 blkno;
 	int leafidx, rc;
@@ -1934,7 +1942,8 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
 {
 	s8 oldroot;
 	int rc;
@@ -1988,7 +1997,8 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		      int nblocks)
 {
 	s8 oldroot;
 	int rc, word;
@@ -2049,7 +2059,8 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			int nblocks)
 {
 	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
 	dmtree_t *tp = (dmtree_t *) & dp->tree;
@@ -2190,7 +2201,8 @@
  *
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
-static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static void dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
+		       int nblocks)
 {
 	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
 	dmtree_t *tp = (dmtree_t *) & dp->tree;
@@ -2368,13 +2380,13 @@
  * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
  */
 static int
-dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc, int level)
+dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level)
 {
-	metapage_t *mp;
+	struct metapage *mp;
 	s8 oldroot;
 	int oldval;
 	s64 lblkno;
-	dmapctl_t *dcp;
+	struct dmapctl *dcp;
 	int rc, leafno, ti;
 
 	/* get the buffer for the dmap control page for the specified
@@ -2384,7 +2396,7 @@
 	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
 	if (mp == NULL)
 		return (EIO);
-	dcp = (dmapctl_t *) mp->data;
+	dcp = (struct dmapctl *) mp->data;
 
 	/* determine the leaf number corresponding to the block and
 	 * the index within the dmap control tree.
@@ -3064,12 +3076,12 @@
  */
 int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
 {
-	metapage_t *mp;
-	dmap_t *dp;
+	struct metapage *mp;
+	struct dmap *dp;
 	int nb, rc;
 	s64 lblkno, rem;
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
 	IREAD_LOCK(ipbmap);
 
@@ -3093,7 +3105,7 @@
 			IREAD_UNLOCK(ipbmap);
 			return (EIO);
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		/* determine the number of blocks to be allocated from
 		 * this dmap.
@@ -3121,12 +3133,13 @@
 }
 
 
-static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
+			 int nblocks)
 {
 	int rc;
 	int dbitno, word, rembits, nb, nwords, wbitno, agno;
 	s8 oldroot, *leaf;
-	dmaptree_t *tp = (dmaptree_t *) & dp->tree;
+	struct dmaptree *tp = (struct dmaptree *) & dp->tree;
 
 	/* save the current value of the root (i.e. maximum free string)
 	 * of the dmap tree.
@@ -3251,11 +3264,11 @@
 	int i, i0 = TRUE, j, j0 = TRUE, k, n;
 	s64 newsize;
 	s64 p;
-	metapage_t *mp, *l2mp, *l1mp, *l0mp;
-	dmapctl_t *l2dcp, *l1dcp, *l0dcp;
-	dmap_t *dp;
+	struct metapage *mp, *l2mp, *l1mp, *l0mp;
+	struct dmapctl *l2dcp, *l1dcp, *l0dcp;
+	struct dmap *dp;
 	s8 *l0leaf, *l1leaf, *l2leaf;
-	bmap_t *bmp = sbi->bmap;
+	struct bmap *bmp = sbi->bmap;
 	int agno, l2agsize, oldl2agsize;
 	s64 ag_rem;
 
@@ -3331,7 +3344,7 @@
 	p = BMAPBLKNO + nbperpage;	/* L2 page */
 	l2mp = read_metapage(ipbmap, p, PSIZE, 0);
 	assert(l2mp);
-	l2dcp = (dmapctl_t *) l2mp->data;
+	l2dcp = (struct dmapctl *) l2mp->data;
 
 	/* compute start L1 */
 	k = blkno >> L2MAXL1SIZE;
@@ -3348,7 +3361,7 @@
 			l1mp = read_metapage(ipbmap, p, PSIZE, 0);
 			if (l1mp == NULL)
 				goto errout;
-			l1dcp = (dmapctl_t *) l1mp->data;
+			l1dcp = (struct dmapctl *) l1mp->data;
 
 			/* compute start L0 */
 			j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE;
@@ -3361,7 +3374,7 @@
 			if (l1mp == NULL)
 				goto errout;
 
-			l1dcp = (dmapctl_t *) l1mp->data;
+			l1dcp = (struct dmapctl *) l1mp->data;
 
 			/* compute start L0 */
 			j = 0;
@@ -3380,7 +3393,7 @@
 				l0mp = read_metapage(ipbmap, p, PSIZE, 0);
 				if (l0mp == NULL)
 					goto errout;
-				l0dcp = (dmapctl_t *) l0mp->data;
+				l0dcp = (struct dmapctl *) l0mp->data;
 
 				/* compute start dmap */
 				i = (blkno & (MAXL0SIZE - 1)) >>
@@ -3395,7 +3408,7 @@
 				if (l0mp == NULL)
 					goto errout;
 
-				l0dcp = (dmapctl_t *) l0mp->data;
+				l0dcp = (struct dmapctl *) l0mp->data;
 
 				/* compute start dmap */
 				i = 0;
@@ -3428,7 +3441,7 @@
 					n = min(nblocks, (s64)BPERDMAP);
 				}
 
-				dp = (dmap_t *) mp->data;
+				dp = (struct dmap *) mp->data;
 				*l0leaf = dbInitDmap(dp, blkno, n);
 
 				bmp->db_nfree += n;
@@ -3510,7 +3523,7 @@
  */
 void dbFinalizeBmap(struct inode *ipbmap)
 {
-	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
 	int actags, inactags, l2nl;
 	s64 ag_rem, actfree, inactfree, avgfree;
 	int i, n;
@@ -3600,7 +3613,7 @@
  *
  * RETURNS: NONE
  */
-static int dbInitDmap(dmap_t * dp, s64 Blkno, int nblocks)
+static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
 {
 	int blkno, w, b, r, nw, nb, i;
 /*
@@ -3713,9 +3726,9 @@
  *
  * RETURNS:	max free string at the root of the tree
  */
-static int dbInitDmapTree(dmap_t * dp)
+static int dbInitDmapTree(struct dmap * dp)
 {
-	dmaptree_t *tp;
+	struct dmaptree *tp;
 	s8 *cp;
 	int i;
 
@@ -3759,7 +3772,7 @@
  *
  * RETURNS: max free string at the root of the tree
  */
-static int dbInitTree(dmaptree_t * dtp)
+static int dbInitTree(struct dmaptree * dtp)
 {
 	int l2max, l2free, bsize, nextb, i;
 	int child, parent, nparent;
@@ -3834,7 +3847,7 @@
  *
  * function: initialize dmapctl page
  */
-static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i)
+static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i)
 {				/* start leaf index not covered by range */
 	s8 *cp;
 
@@ -3854,7 +3867,7 @@
 		*cp++ = NOFREE;
 
 	/* build the dmap's binary buddy summary tree */
-	return (dbInitTree((dmaptree_t *) dcp));
+	return (dbInitTree((struct dmaptree *) dcp));
 }
 
 
@@ -3969,8 +3982,8 @@
 	u32 *dbmap, *d;
 	int n;
 	s64 lblkno, cur_block;
-	dmap_t *dp;
-	metapage_t *mp;
+	struct dmap *dp;
+	struct metapage *mp;
 
 	npages = size / 32768;
 	npages += (size % 32768) ? 1 : 0;
@@ -3993,7 +4006,7 @@
 		if (mp == NULL) {
 			assert(0);
 		}
-		dp = (dmap_t *) mp->data;
+		dp = (struct dmap *) mp->data;
 
 		for (n = 0; n < LPERDMAP; n++)
 			d[n] = le32_to_cpu(dp->wmap[n]);
@@ -4122,7 +4135,7 @@
 /*
  *	dbPrtMap()
  */
-static void dbPrtMap(bmap_t * bmp)
+static void dbPrtMap(struct bmap * bmp)
 {
 	printk("   mapsize:   %d%d\n", bmp->db_mapsize);
 	printk("   nfree:     %d%d\n", bmp->db_nfree);
@@ -4143,7 +4156,7 @@
 /*
  *	dbPrtCtl()
  */
-static void dbPrtCtl(dmapctl_t * dcp)
+static void dbPrtCtl(struct dmapctl * dcp)
 {
 	int i, j, n;
 
diff -Nru a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h
--- a/fs/jfs/jfs_dmap.h	Sun Sep 15 19:19:50 2002
+++ b/fs/jfs/jfs_dmap.h	Sun Sep 15 19:19:50 2002
@@ -142,9 +142,9 @@
 /*
  *	dmap summary tree
  *
- * dmaptree_t must be consistent with dmapctl_t.
+ * dmaptree must be consistent with dmapctl.
  */
-typedef struct {
+struct dmaptree {
 	s32 nleafs;		/* 4: number of tree leafs      */
 	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
 	s32 leafidx;		/* 4: index of first tree leaf  */
@@ -152,27 +152,27 @@
 	s8 budmin;		/* 1: min l2 tree leaf value to combine */
 	s8 stree[TREESIZE];	/* TREESIZE: tree               */
 	u8 pad[2];		/* 2: pad to word boundary      */
-} dmaptree_t;			/* - 360 -                      */
+};				/* - 360 -                      */
 
 /*
  *	dmap page per 8K blocks bitmap
  */
-typedef struct {
+struct dmap {
 	s32 nblocks;		/* 4: num blks covered by this dmap     */
 	s32 nfree;		/* 4: num of free blks in this dmap     */
 	s64 start;		/* 8: starting blkno for this dmap      */
-	dmaptree_t tree;	/* 360: dmap tree                       */
+	struct dmaptree tree;	/* 360: dmap tree                       */
 	u8 pad[1672];		/* 1672: pad to 2048 bytes              */
 	u32 wmap[LPERDMAP];	/* 1024: bits of the working map        */
 	u32 pmap[LPERDMAP];	/* 1024: bits of the persistent map     */
-} dmap_t;			/* - 4096 -                             */
+};				/* - 4096 -                             */
 
 /*
  *	disk map control page per level.
  *
- * dmapctl_t must be consistent with dmaptree_t.
+ * dmapctl must be consistent with dmaptree.
  */
-typedef struct {
+struct dmapctl {
 	s32 nleafs;		/* 4: number of tree leafs      */
 	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
 	s32 leafidx;		/* 4: index of the first tree leaf      */
@@ -180,17 +180,17 @@
 	s8 budmin;		/* 1: minimum l2 tree leaf value        */
 	s8 stree[CTLTREESIZE];	/* CTLTREESIZE: dmapctl tree    */
 	u8 pad[2714];		/* 2714: pad to 4096            */
-} dmapctl_t;			/* - 4096 -                     */
+};				/* - 4096 -                     */
 
 /*
- *	common definition for dmaptree_t within dmap and dmapctl
+ *	common definition for dmaptree within dmap and dmapctl
  */
-typedef union {
-	dmaptree_t t1;
-	dmapctl_t t2;
+typedef union dmtree {
+	struct dmaptree t1;
+	struct dmapctl t2;
 } dmtree_t;
 
-/* macros for accessing fields within dmtree_t */
+/* macros for accessing fields within dmtree */
 #define	dmt_nleafs	t1.nleafs
 #define	dmt_l2nleafs 	t1.l2nleafs
 #define	dmt_leafidx 	t1.leafidx
@@ -201,7 +201,7 @@
 /* 
  *	on-disk aggregate disk allocation map descriptor.
  */
-typedef struct {
+struct dbmap {
 	s64 dn_mapsize;		/* 8: number of blocks in aggregate     */
 	s64 dn_nfree;		/* 8: num free blks in aggregate map    */
 	s32 dn_l2nbperpage;	/* 4: number of blks per page           */
@@ -218,17 +218,17 @@
 	s64 dn_agsize;		/* 8: num of blks per alloc group       */
 	s8 dn_maxfreebud;	/* 1: max free buddy system             */
 	u8 pad[3007];		/* 3007: pad to 4096                    */
-} dbmap_t;			/* - 4096 -                             */
+};				/* - 4096 -                             */
 
 /* 
  *	in-memory aggregate disk allocation map descriptor.
  */
-typedef struct bmap {
-	dbmap_t db_bmap;	/* on-disk aggregate map descriptor */
+struct bmap {
+	struct dbmap db_bmap;	/* on-disk aggregate map descriptor */
 	struct inode *db_ipbmap;	/* ptr to aggregate map incore inode */
 	struct semaphore db_bmaplock;	/* aggregate map lock */
 	u32 *db_DBmap;
-} bmap_t;
+};
 
 /* macros for accessing fields within in-memory aggregate map descriptor */
 #define	db_mapsize	db_bmap.dn_mapsize
@@ -279,7 +279,7 @@
 extern int dbFree(struct inode *ipbmap, s64 blkno, s64 nblocks);
 
 extern int dbUpdatePMap(struct inode *ipbmap,
-			int free, s64 blkno, s64 nblocks, tblock_t * tblk);
+			int free, s64 blkno, s64 nblocks, struct tblock * tblk);
 
 extern int dbNextAG(struct inode *ipbmap);
 
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_dtree.c	Sun Sep 15 19:19:29 2002
@@ -110,14 +110,14 @@
 #include "jfs_debug.h"
 
 /* dtree split parameter */
-typedef struct {
-	metapage_t *mp;
+struct dtsplit {
+	struct metapage *mp;
 	s16 index;
 	s16 nslot;
-	component_t *key;
+	struct component_name *key;
 	ddata_t *data;
-	pxdlist_t *pxdlist;
-} dtsplit_t;
+	struct pxdlist *pxdlist;
+};
 
 #define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
 
@@ -149,51 +149,53 @@
  * forward references
  */
 static int dtSplitUp(tid_t tid, struct inode *ip,
-		     dtsplit_t * split, btstack_t * btstack);
+		     struct dtsplit * split, struct btstack * btstack);
 
-static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split,
-		       metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rxdp);
+static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
+		       struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rxdp);
 
 static int dtExtendPage(tid_t tid, struct inode *ip,
-			dtsplit_t * split, btstack_t * btstack);
+			struct dtsplit * split, struct btstack * btstack);
 
 static int dtSplitRoot(tid_t tid, struct inode *ip,
-		       dtsplit_t * split, metapage_t ** rmpp);
+		       struct dtsplit * split, struct metapage ** rmpp);
 
-static int dtDeleteUp(tid_t tid, struct inode *ip, metapage_t * fmp,
-		      dtpage_t * fp, btstack_t * btstack);
+static int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp,
+		      dtpage_t * fp, struct btstack * btstack);
 
 static int dtSearchNode(struct inode *ip,
-			s64 lmxaddr, pxd_t * kpxd, btstack_t * btstack);
+			s64 lmxaddr, pxd_t * kpxd, struct btstack * btstack);
 
 static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p);
 
-static int dtReadFirst(struct inode *ip, btstack_t * btstack);
+static int dtReadFirst(struct inode *ip, struct btstack * btstack);
 
 static int dtReadNext(struct inode *ip,
-		      loff_t * offset, btstack_t * btstack);
+		      loff_t * offset, struct btstack * btstack);
 
-static int dtCompare(component_t * key, dtpage_t * p, int si);
+static int dtCompare(struct component_name * key, dtpage_t * p, int si);
 
-static int ciCompare(component_t * key, dtpage_t * p, int si, int flag);
+static int ciCompare(struct component_name * key, dtpage_t * p, int si,
+		     int flag);
 
-static void dtGetKey(dtpage_t * p, int i, component_t * key, int flag);
+static void dtGetKey(dtpage_t * p, int i, struct component_name * key,
+		     int flag);
 
 static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
-			       int ri, component_t * key, int flag);
+			       int ri, struct component_name * key, int flag);
 
-static void dtInsertEntry(dtpage_t * p, int index, component_t * key,
-			  ddata_t * data, dtlock_t ** dtlock);
+static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
+			  ddata_t * data, struct dt_lock **);
 
 static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
-			dtlock_t ** sdtlock, dtlock_t ** ddtlock,
+			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
 			int do_index);
 
-static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock);
+static void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock);
 
-static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock);
+static void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock);
 
-static void dtLinelockFreelist(dtpage_t * p, int m, dtlock_t ** dtlock);
+static void dtLinelockFreelist(dtpage_t * p, int m, struct dt_lock ** dtlock);
 
 #define ciToUpper(c)	UniStrupr((c)->name)
 
@@ -205,14 +207,14 @@
  *
  *	mp must be released by caller.
  */
-static dir_table_slot_t *find_index(struct inode *ip, u32 index,
-				    metapage_t ** mp)
+static struct dir_table_slot *find_index(struct inode *ip, u32 index,
+					 struct metapage ** mp)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	s64 blkno;
 	s64 offset;
 	int page_offset;
-	dir_table_slot_t *slot;
+	struct dir_table_slot *slot;
 	static int maxWarnings = 10;
 
 	if (index < 2) {
@@ -236,7 +238,7 @@
 		*mp = 0;
 		slot = &jfs_ip->i_dirtable[index - 2];
 	} else {
-		offset = (index - 2) * sizeof(dir_table_slot_t);
+		offset = (index - 2) * sizeof(struct dir_table_slot);
 		page_offset = offset & (PSIZE - 1);
 		blkno = ((offset + 1) >> L2PSIZE) <<
 		    JFS_SBI(ip->i_sb)->l2nbperpage;
@@ -254,21 +256,21 @@
 		}
 
 		slot =
-		    (dir_table_slot_t *) ((char *) (*mp)->data +
-					  page_offset);
+		    (struct dir_table_slot *) ((char *) (*mp)->data +
+					       page_offset);
 	}
 	return slot;
 }
 
-static inline void lock_index(tid_t tid, struct inode *ip, metapage_t * mp,
+static inline void lock_index(tid_t tid, struct inode *ip, struct metapage * mp,
 			      u32 index)
 {
-	tlock_t *tlck;
-	linelock_t *llck;
-	lv_t *lv;
+	struct tlock *tlck;
+	struct linelock *llck;
+	struct lv *lv;
 
 	tlck = txLock(tid, ip, mp, tlckDATA);
-	llck = (linelock_t *) tlck->lock;
+	llck = (struct linelock *) tlck->lock;
 
 	if (llck->index >= llck->maxcnt)
 		llck = txLinelock(llck);
@@ -296,15 +298,15 @@
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	u64 blkno;
-	dir_table_slot_t *dirtab_slot;
+	struct dir_table_slot *dirtab_slot;
 	u32 index;
-	linelock_t *llck;
-	lv_t *lv;
-	metapage_t *mp;
+	struct linelock *llck;
+	struct lv *lv;
+	struct metapage *mp;
 	s64 offset;
 	uint page_offset;
 	int rc;
-	tlock_t *tlck;
+	struct tlock *tlck;
 	s64 xaddr;
 
 	ASSERT(DO_INDEX(ip));
@@ -345,7 +347,7 @@
 		 * Save the table, we're going to overwrite it with the
 		 * xtree root
 		 */
-		dir_table_slot_t temp_table[12];
+		struct dir_table_slot temp_table[12];
 		memcpy(temp_table, &jfs_ip->i_dirtable, sizeof(temp_table));
 
 		/*
@@ -372,7 +374,7 @@
 			return -1;
 		}
 		tlck = txLock(tid, ip, mp, tlckDATA);
-		llck = (linelock_t *) & tlck->lock;
+		llck = (struct linelock *) & tlck->lock;
 		ASSERT(llck->index == 0);
 		lv = &llck->lv[0];
 
@@ -391,7 +393,7 @@
 		clear_cflag(COMMIT_Dirtable, ip);
 	}
 
-	offset = (index - 2) * sizeof(dir_table_slot_t);
+	offset = (index - 2) * sizeof(struct dir_table_slot);
 	page_offset = offset & (PSIZE - 1);
 	blkno = ((offset + 1) >> L2PSIZE) << sbi->l2nbperpage;
 	if (page_offset == 0) {
@@ -424,7 +426,7 @@
 	lock_index(tid, ip, mp, index);
 
 	dirtab_slot =
-	    (dir_table_slot_t *) ((char *) mp->data + page_offset);
+	    (struct dir_table_slot *) ((char *) mp->data + page_offset);
 	dirtab_slot->flag = DIR_INDEX_VALID;
 	dirtab_slot->slot = slot;
 	DTSaddress(dirtab_slot, bn);
@@ -442,8 +444,8 @@
  */
 static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
 {
-	dir_table_slot_t *dirtab_slot;
-	metapage_t *mp = 0;
+	struct dir_table_slot *dirtab_slot;
+	struct metapage *mp = 0;
 
 	dirtab_slot = find_index(ip, index, &mp);
 
@@ -468,9 +470,9 @@
  *	Changes an entry in the directory index table
  */
 static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
-			 int slot, metapage_t ** mp)
+			 int slot, struct metapage ** mp)
 {
-	dir_table_slot_t *dirtab_slot;
+	struct dir_table_slot *dirtab_slot;
 
 	dirtab_slot = find_index(ip, index, mp);
 
@@ -493,17 +495,17 @@
  *	reads a directory table slot
  */
 static int get_index(struct inode *ip, u32 index,
-		     dir_table_slot_t * dirtab_slot)
+		     struct dir_table_slot * dirtab_slot)
 {
-	metapage_t *mp = 0;
-	dir_table_slot_t *slot;
+	struct metapage *mp = 0;
+	struct dir_table_slot *slot;
 
 	slot = find_index(ip, index, &mp);
 	if (slot == 0) {
 		return -EIO;
 	}
 
-	memcpy(dirtab_slot, slot, sizeof(dir_table_slot_t));
+	memcpy(dirtab_slot, slot, sizeof(struct dir_table_slot));
 
 	if (mp)
 		release_metapage(mp);
@@ -522,21 +524,21 @@
  * return: 0 - search result on stack, leaf page pinned;
  *	   errno - I/O error
  */
-int dtSearch(struct inode *ip,
-	 component_t * key, ino_t * data, btstack_t * btstack, int flag)
+int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
+	     struct btstack * btstack, int flag)
 {
 	int rc = 0;
 	int cmp = 1;		/* init for empty page */
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	s8 *stbl;
 	int base, index, lim;
-	btframe_t *btsp;
+	struct btframe *btsp;
 	pxd_t *pxd;
 	int psize = 288;	/* initial in-line directory */
 	ino_t inumber;
-	component_t ciKey;
+	struct component_name ciKey;
 	struct super_block *sb = ip->i_sb;
 
 	ciKey.name =
@@ -613,7 +615,7 @@
 				 */
 				if (p->header.flag & BT_LEAF) {
 					inumber = le32_to_cpu(
-			((ldtentry_t *) & p->slot[stbl[index]])->inumber);
+			((struct ldtentry *) & p->slot[stbl[index]])->inumber);
 
 					/*
 					 * search for JFS_LOOKUP
@@ -766,19 +768,19 @@
  *	   errno - failure;
  */
 int dtInsert(tid_t tid, struct inode *ip,
-	 component_t * name, ino_t * fsn, btstack_t * btstack)
+	 struct component_name * name, ino_t * fsn, struct btstack * btstack)
 {
 	int rc = 0;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	dtpage_t *p;		/* base B+-tree index page */
 	s64 bn;
 	int index;
-	dtsplit_t split;	/* split information */
+	struct dtsplit split;	/* split information */
 	ddata_t data;
-	dtlock_t *dtlck;
+	struct dt_lock *dtlck;
 	int n;
-	tlock_t *tlck;
-	lv_t *lv;
+	struct tlock *tlck;
+	struct lv *lv;
 
 	/*
 	 *      retrieve search result
@@ -833,9 +835,9 @@
 	 * acquire a transaction lock on the leaf page
 	 */
 	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 
 	/* linelock header */
 	lv->offset = 0;
@@ -847,8 +849,8 @@
 	/* linelock stbl of non-root leaf page */
 	if (!(p->header.flag & BT_ROOT)) {
 		if (dtlck->index >= dtlck->maxcnt)
-			dtlck = (dtlock_t *) txLinelock(dtlck);
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
 		n = index >> L2DTSLOTSIZE;
 		lv->offset = p->header.stblindex + n;
 		lv->length =
@@ -875,29 +877,29 @@
  * 	leaf page unpinned;
  */
 static int dtSplitUp(tid_t tid,
-	  struct inode *ip, dtsplit_t * split, btstack_t * btstack)
+	  struct inode *ip, struct dtsplit * split, struct btstack * btstack)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	int rc = 0;
-	metapage_t *smp;
+	struct metapage *smp;
 	dtpage_t *sp;		/* split page */
-	metapage_t *rmp;
+	struct metapage *rmp;
 	dtpage_t *rp;		/* new right page split from sp */
 	pxd_t rpxd;		/* new right page extent descriptor */
-	metapage_t *lmp;
+	struct metapage *lmp;
 	dtpage_t *lp;		/* left child page */
 	int skip;		/* index of entry of insertion */
-	btframe_t *parent;	/* parent page entry on traverse stack */
+	struct btframe *parent;	/* parent page entry on traverse stack */
 	s64 xaddr, nxaddr;
 	int xlen, xsize;
-	pxdlist_t pxdlist;
+	struct pxdlist pxdlist;
 	pxd_t *pxd;
-	component_t key = { 0, 0 };
+	struct component_name key = { 0, 0 };
 	ddata_t *data = split->data;
 	int n;
-	dtlock_t *dtlck;
-	tlock_t *tlck;
-	lv_t *lv;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
 
 	/* get split page */
 	smp = split->mp;
@@ -1183,9 +1185,9 @@
 			 * acquire a transaction lock on the parent page
 			 */
 			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
-			dtlck = (dtlock_t *) & tlck->lock;
+			dtlck = (struct dt_lock *) & tlck->lock;
 			ASSERT(dtlck->index == 0);
-			lv = (lv_t *) & dtlck->lv[0];
+			lv = & dtlck->lv[0];
 
 			/* linelock header */
 			lv->offset = 0;
@@ -1243,32 +1245,32 @@
  *	   errno - failure;
  *	return split and new page pinned;
  */
-static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split,
-	    metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
+static int dtSplitPage(tid_t tid, struct inode *ip, struct dtsplit * split,
+	    struct metapage ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
 {
 	struct super_block *sb = ip->i_sb;
 	int rc = 0;
-	metapage_t *smp;
+	struct metapage *smp;
 	dtpage_t *sp;
-	metapage_t *rmp;
+	struct metapage *rmp;
 	dtpage_t *rp;		/* new right page allocated */
 	s64 rbn;		/* new right page block number */
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	s64 nextbn;
-	pxdlist_t *pxdlist;
+	struct pxdlist *pxdlist;
 	pxd_t *pxd;
 	int skip, nextindex, half, left, nxt, off, si;
-	ldtentry_t *ldtentry;
-	idtentry_t *idtentry;
+	struct ldtentry *ldtentry;
+	struct idtentry *idtentry;
 	u8 *stbl;
-	dtslot_t *f;
+	struct dtslot *f;
 	int fsi, stblsize;
 	int n;
-	dtlock_t *sdtlck, *rdtlck;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	lv_t *slv, *rlv, *lv;
+	struct dt_lock *sdtlck, *rdtlck;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *slv, *rlv, *lv;
 
 	/* get split page */
 	smp = split->mp;
@@ -1293,7 +1295,7 @@
 	 * acquire a transaction lock on the new right page
 	 */
 	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
-	rdtlck = (dtlock_t *) & tlck->lock;
+	rdtlck = (struct dt_lock *) & tlck->lock;
 
 	rp = (dtpage_t *) rmp->data;
 	*rpp = rp;
@@ -1306,11 +1308,11 @@
 	 * action:
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
-	sdtlck = (dtlock_t *) & tlck->lock;
+	sdtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock header of split page */
 	ASSERT(sdtlck->index == 0);
-	slv = (lv_t *) & sdtlck->lv[0];
+	slv = & sdtlck->lv[0];
 	slv->offset = 0;
 	slv->length = 1;
 	sdtlck->index++;
@@ -1356,7 +1358,7 @@
 	 */
 	if (nextbn == 0 && split->index == sp->header.nextindex) {
 		/* linelock header + stbl (first slot) of new page */
-		rlv = (lv_t *) & rdtlck->lv[rdtlck->index];
+		rlv = & rdtlck->lv[rdtlck->index];
 		rlv->offset = 0;
 		rlv->length = 2;
 		rdtlck->index++;
@@ -1395,10 +1397,10 @@
 		jEVENT(0,
 		       ("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
 			tlck, ip, mp));
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header of previous right sibling page */
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv = & dtlck->lv[dtlck->index];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -1431,7 +1433,7 @@
 			si = stbl[nxt];
 			switch (sp->header.flag & BT_TYPE) {
 			case BT_LEAF:
-				ldtentry = (ldtentry_t *) & sp->slot[si];
+				ldtentry = (struct ldtentry *) & sp->slot[si];
 				if (DO_INDEX(ip))
 					n = NDTLEAF(ldtentry->namlen);
 				else
@@ -1440,7 +1442,7 @@
 				break;
 
 			case BT_INTERNAL:
-				idtentry = (idtentry_t *) & sp->slot[si];
+				idtentry = (struct idtentry *) & sp->slot[si];
 				n = NDTINTERNAL(idtentry->namlen);
 				break;
 
@@ -1467,7 +1469,7 @@
 	 * new/right page moved in entries are linelocked;
 	 */
 	/* linelock header + stbl of new right page */
-	rlv = (lv_t *) & rdtlck->lv[rdtlck->index];
+	rlv = & rdtlck->lv[rdtlck->index];
 	rlv->offset = 0;
 	rlv->length = 5;
 	rdtlck->index++;
@@ -1492,7 +1494,7 @@
 		mp = 0;
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
-			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
+			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
 				     rbn, n, &mp);
 		}
@@ -1509,8 +1511,8 @@
 
 		/* linelock stbl of split page */
 		if (sdtlck->index >= sdtlck->maxcnt)
-			sdtlck = (dtlock_t *) txLinelock(sdtlck);
-		slv = (lv_t *) & sdtlck->lv[sdtlck->index];
+			sdtlck = (struct dt_lock *) txLinelock(sdtlck);
+		slv = & sdtlck->lv[sdtlck->index];
 		n = skip >> L2DTSLOTSIZE;
 		slv->offset = sp->header.stblindex + n;
 		slv->length =
@@ -1551,28 +1553,28 @@
  *	return extended page pinned;
  */
 static int dtExtendPage(tid_t tid,
-	     struct inode *ip, dtsplit_t * split, btstack_t * btstack)
+	     struct inode *ip, struct dtsplit * split, struct btstack * btstack)
 {
 	struct super_block *sb = ip->i_sb;
 	int rc;
-	metapage_t *smp, *pmp, *mp;
+	struct metapage *smp, *pmp, *mp;
 	dtpage_t *sp, *pp;
-	pxdlist_t *pxdlist;
+	struct pxdlist *pxdlist;
 	pxd_t *pxd, *tpxd;
 	int xlen, xsize;
 	int newstblindex, newstblsize;
 	int oldstblindex, oldstblsize;
 	int fsi, last;
-	dtslot_t *f;
-	btframe_t *parent;
+	struct dtslot *f;
+	struct btframe *parent;
 	int n;
-	dtlock_t *dtlck;
+	struct dt_lock *dtlck;
 	s64 xaddr, txaddr;
-	tlock_t *tlck;
-	pxdlock_t *pxdlock;
-	lv_t *lv;
+	struct tlock *tlck;
+	struct pxd_lock *pxdlock;
+	struct lv *lv;
 	uint type;
-	ldtentry_t *ldtentry;
+	struct ldtentry *ldtentry;
 	u8 *stbl;
 
 	/* get page to extend */
@@ -1605,7 +1607,7 @@
 
 		/* save moved extent descriptor for later free */
 		tlck = txMaplock(tid, ip, tlckDTREE | tlckRELOCATE);
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		pxdlock->flag = mlckFREEPXD;
 		pxdlock->pxd = sp->header.self;
 		pxdlock->index = 1;
@@ -1618,7 +1620,7 @@
 			stbl = DT_GETSTBL(sp);
 			for (n = 0; n < sp->header.nextindex; n++) {
 				ldtentry =
-				    (ldtentry_t *) & sp->slot[stbl[n]];
+				    (struct ldtentry *) & sp->slot[stbl[n]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
 					     xaddr, n, &mp);
@@ -1641,8 +1643,8 @@
 	 * acquire a transaction lock on the extended/leaf page
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | type);
-	dtlck = (dtlock_t *) & tlck->lock;
-	lv = (lv_t *) & dtlck->lv[0];
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[0];
 
 	/* update buffer extent descriptor of extended page */
 	xlen = lengthPXD(pxd);
@@ -1750,8 +1752,8 @@
 	 * acquire a transaction lock on the parent/root page
 	 */
 	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
-	dtlck = (dtlock_t *) & tlck->lock;
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[dtlck->index];
 
 	/* linelock parent entry - 1st slot */
 	lv->offset = 1;
@@ -1800,26 +1802,26 @@
  *	return new page pinned;
  */
 static int dtSplitRoot(tid_t tid,
-	    struct inode *ip, dtsplit_t * split, metapage_t ** rmpp)
+	    struct inode *ip, struct dtsplit * split, struct metapage ** rmpp)
 {
 	struct super_block *sb = ip->i_sb;
-	metapage_t *smp;
+	struct metapage *smp;
 	dtroot_t *sp;
-	metapage_t *rmp;
+	struct metapage *rmp;
 	dtpage_t *rp;
 	s64 rbn;
 	int xlen;
 	int xsize;
-	dtslot_t *f;
+	struct dtslot *f;
 	s8 *stbl;
 	int fsi, stblsize, n;
-	idtentry_t *s;
+	struct idtentry *s;
 	pxd_t *ppxd;
-	pxdlist_t *pxdlist;
+	struct pxdlist *pxdlist;
 	pxd_t *pxd;
-	dtlock_t *dtlck;
-	tlock_t *tlck;
-	lv_t *lv;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
 
 	/* get split root page */
 	smp = split->mp;
@@ -1845,7 +1847,7 @@
 	 * acquire a transaction lock on the new right page
 	 */
 	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 
 	rp->header.flag =
 	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
@@ -1860,7 +1862,7 @@
 	 */
 	/* linelock header + copied entries + new stbl (1st slot) in new page */
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 	lv->offset = 0;
 	lv->length = 10;	/* 1 + 8 + 1 */
 	dtlck->index++;
@@ -1909,12 +1911,12 @@
 	 * Update directory index table for entries now in right page
 	 */
 	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
-		metapage_t *mp = 0;
-		ldtentry_t *ldtentry;
+		struct metapage *mp = 0;
+		struct ldtentry *ldtentry;
 
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
-			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
+			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
 				     rbn, n, &mp);
 		}
@@ -1941,11 +1943,11 @@
 	 * acquire a transaction lock on the root page (in-memory inode)
 	 */
 	tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock root */
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 	lv->offset = 0;
 	lv->length = DTROOTMAXSLOT;
 	dtlck->index++;
@@ -1957,7 +1959,7 @@
 	}
 
 	/* init the first entry */
-	s = (idtentry_t *) & sp->slot[DTENTRYSTART];
+	s = (struct idtentry *) & sp->slot[DTENTRYSTART];
 	ppxd = (pxd_t *) s;
 	*ppxd = *pxd;
 	s->next = -1;
@@ -1996,22 +1998,22 @@
  * return:
  */
 int dtDelete(tid_t tid,
-	 struct inode *ip, component_t * key, ino_t * ino, int flag)
+	 struct inode *ip, struct component_name * key, ino_t * ino, int flag)
 {
 	int rc = 0;
 	s64 bn;
-	metapage_t *mp, *imp;
+	struct metapage *mp, *imp;
 	dtpage_t *p;
 	int index;
-	btstack_t btstack;
-	dtlock_t *dtlck;
-	tlock_t *tlck;
-	lv_t *lv;
+	struct btstack btstack;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
 	int i;
-	ldtentry_t *ldtentry;
+	struct ldtentry *ldtentry;
 	u8 *stbl;
 	u32 table_index, next_index;
-	metapage_t *nmp;
+	struct metapage *nmp;
 	dtpage_t *np;
 
 	/*
@@ -2032,7 +2034,7 @@
 	 */
 	if (DO_INDEX(ip)) {
 		stbl = DT_GETSTBL(p);
-		ldtentry = (ldtentry_t *) & p->slot[stbl[index]];
+		ldtentry = (struct ldtentry *) & p->slot[stbl[index]];
 		table_index = le32_to_cpu(ldtentry->index);
 		if (index == (p->header.nextindex - 1)) {
 			/*
@@ -2050,7 +2052,7 @@
 				else {
 					stbl = DT_GETSTBL(np);
 					ldtentry =
-					    (ldtentry_t *) & np->
+					    (struct ldtentry *) & np->
 					    slot[stbl[0]];
 					next_index =
 					    le32_to_cpu(ldtentry->index);
@@ -2059,7 +2061,7 @@
 			}
 		} else {
 			ldtentry =
-			    (ldtentry_t *) & p->slot[stbl[index + 1]];
+			    (struct ldtentry *) & p->slot[stbl[index + 1]];
 			next_index = le32_to_cpu(ldtentry->index);
 		}
 		free_index(tid, ip, table_index, next_index);
@@ -2082,7 +2084,7 @@
 		 * acquire a transaction lock on the leaf page
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/*
 		 * Do not assume that dtlck->index will be zero.  During a
@@ -2092,8 +2094,8 @@
 
 		/* linelock header */
 		if (dtlck->index >= dtlck->maxcnt)
-			dtlck = (dtlock_t *) txLinelock(dtlck);
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2101,8 +2103,8 @@
 		/* linelock stbl of non-root leaf page */
 		if (!(p->header.flag & BT_ROOT)) {
 			if (dtlck->index >= dtlck->maxcnt)
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-			lv = (lv_t *) & dtlck->lv[dtlck->index];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+			lv = & dtlck->lv[dtlck->index];
 			i = index >> L2DTSLOTSIZE;
 			lv->offset = p->header.stblindex + i;
 			lv->length =
@@ -2122,7 +2124,7 @@
 			stbl = DT_GETSTBL(p);
 			for (i = index; i < p->header.nextindex; i++) {
 				ldtentry =
-				    (ldtentry_t *) & p->slot[stbl[i]];
+				    (struct ldtentry *) & p->slot[stbl[i]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
 					     bn, i, &imp);
@@ -2149,18 +2151,18 @@
  * return:
  */
 static int dtDeleteUp(tid_t tid, struct inode *ip,
-	   metapage_t * fmp, dtpage_t * fp, btstack_t * btstack)
+	   struct metapage * fmp, dtpage_t * fp, struct btstack * btstack)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	int index, nextindex;
 	int xlen;
-	btframe_t *parent;
-	dtlock_t *dtlck;
-	tlock_t *tlck;
-	lv_t *lv;
-	pxdlock_t *pxdlock;
+	struct btframe *parent;
+	struct dt_lock *dtlck;
+	struct tlock *tlck;
+	struct lv *lv;
+	struct pxd_lock *pxdlock;
 	int i;
 
 	/*
@@ -2190,7 +2192,7 @@
 	 * the buffer page is freed;
 	 */
 	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
-	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock = (struct pxd_lock *) & tlck->lock;
 	pxdlock->flag = mlckFREEPXD;
 	pxdlock->pxd = fp->header.self;
 	pxdlock->index = 1;
@@ -2262,7 +2264,7 @@
 				tlck =
 				    txMaplock(tid, ip,
 					      tlckDTREE | tlckFREE);
-				pxdlock = (pxdlock_t *) & tlck->lock;
+				pxdlock = (struct pxd_lock *) & tlck->lock;
 				pxdlock->flag = mlckFREEPXD;
 				pxdlock->pxd = p->header.self;
 				pxdlock->index = 1;
@@ -2294,12 +2296,12 @@
 		 * action: router entry deletion
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
 		if (dtlck->index >= dtlck->maxcnt)
-			dtlck = (dtlock_t *) txLinelock(dtlck);
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2309,8 +2311,8 @@
 			if (dtlck->index < dtlck->maxcnt)
 				lv++;
 			else {
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-				lv = (lv_t *) & dtlck->lv[0];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
 			}
 			i = index >> L2DTSLOTSIZE;
 			lv->offset = p->header.stblindex + i;
@@ -2349,25 +2351,26 @@
 	       s64 nxaddr)
 {
 	int rc = 0;
-	metapage_t *mp, *pmp, *lmp, *rmp;
+	struct metapage *mp, *pmp, *lmp, *rmp;
 	dtpage_t *p, *pp, *rp = 0, *lp= 0;
 	s64 bn;
 	int index;
-	btstack_t btstack;
+	struct btstack btstack;
 	pxd_t *pxd;
 	s64 oxaddr, nextbn, prevbn;
 	int xlen, xsize;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	pxdlock_t *pxdlock;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct pxd_lock *pxdlock;
 	s8 *stbl;
-	lv_t *lv;
+	struct lv *lv;
 
 	oxaddr = addressPXD(opxd);
 	xlen = lengthPXD(opxd);
 
 	jEVENT(0, ("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d\n",
-		   (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr, xlen));
+		   (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr,
+		   xlen));
 
 	/*
 	 *      1. get the internal parent dtpage covering
@@ -2426,10 +2429,10 @@
 	 */
 	if (lmp) {
 		tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK);
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 		/* linelock header */
 		ASSERT(dtlck->index == 0);
-		lv = (lv_t *) & dtlck->lv[0];
+		lv = & dtlck->lv[0];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2440,10 +2443,10 @@
 
 	if (rmp) {
 		tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK);
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 		/* linelock header */
 		ASSERT(dtlck->index == 0);
-		lv = (lv_t *) & dtlck->lv[0];
+		lv = & dtlck->lv[0];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2462,10 +2465,10 @@
 	 * the dst extent;
 	 */
 	tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 	/* linelock header */
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 
 	/* update the self address in the dtpage header */
 	pxd = &p->header.self;
@@ -2501,7 +2504,7 @@
 	 * dtpage), and upadte bmap for free of the source dtpage;
 	 */
 	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
-	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock = (struct pxd_lock *) & tlck->lock;
 	pxdlock->flag = mlckFREEPXD;
 	PXDaddress(&pxdlock->pxd, oxaddr);
 	PXDlength(&pxdlock->pxd, xlen);
@@ -2515,8 +2518,8 @@
 	 */
 	jEVENT(0, ("dtRelocate: update parent router entry.\n"));
 	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
-	dtlck = (dtlock_t *) & tlck->lock;
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+	dtlck = (struct dt_lock *) & tlck->lock;
+	lv = & dtlck->lv[dtlck->index];
 
 	/* update the PXD with the new address */
 	stbl = DT_GETSTBL(pp);
@@ -2545,17 +2548,17 @@
  *		dtree level, in which the required dtpage resides.
  */
 static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
-			btstack_t * btstack)
+			struct btstack * btstack)
 {
 	int rc = 0;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	int psize = 288;	/* initial in-line directory */
 	s8 *stbl;
 	int i;
 	pxd_t *pxd;
-	btframe_t *btsp;
+	struct btframe *btsp;
 
 	BT_CLR(btstack);	/* reset stack */
 
@@ -2650,11 +2653,11 @@
 static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
 {
 	int rc;
-	metapage_t *mp;
+	struct metapage *mp;
 	s64 nextbn, prevbn;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	lv_t *lv;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
 
 	nextbn = le64_to_cpu(p->header.next);
 	prevbn = le64_to_cpu(p->header.prev);
@@ -2675,12 +2678,12 @@
 		jEVENT(0,
 		       ("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
 			tlck, ip, mp));
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
 		if (dtlck->index >= dtlck->maxcnt)
-			dtlck = (dtlock_t *) txLinelock(dtlck);
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2705,12 +2708,12 @@
 		jEVENT(0,
 		       ("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
 			tlck, ip, mp));
-		dtlck = (dtlock_t *) & tlck->lock;
+		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
 		if (dtlck->index >= dtlck->maxcnt)
-			dtlck = (dtlock_t *) txLinelock(dtlck);
-		lv = (lv_t *) & dtlck->lv[dtlck->index];
+			dtlck = (struct dt_lock *) txLinelock(dtlck);
+		lv = & dtlck->lv[dtlck->index];
 		lv->offset = 0;
 		lv->length = 1;
 		dtlck->index++;
@@ -2733,10 +2736,10 @@
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	dtroot_t *p;
 	int fsi;
-	dtslot_t *f;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	lv_t *lv;
+	struct dtslot *f;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
 	u16 xflag_save;
 
 	/*
@@ -2745,7 +2748,7 @@
 	 */
 	if (DO_INDEX(ip)) {
 		if (jfs_ip->next_index > (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
-			tblock_t *tblk = tid_to_tblock(tid);
+			struct tblock *tblk = tid_to_tblock(tid);
 			/*
 			 * We're playing games with the tid's xflag.  If
 			 * we're removing a regular file, the file's xtree
@@ -2784,13 +2787,13 @@
 	 *
 	 * action: directory initialization;
 	 */
-	tlck = txLock(tid, ip, (metapage_t *) & jfs_ip->bxflag,
+	tlck = txLock(tid, ip, (struct metapage *) & jfs_ip->bxflag,
 		      tlckDTREE | tlckENTRY | tlckBTROOT);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* linelock root */
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 	lv->offset = 0;
 	lv->length = DTROOTMAXSLOT;
 	dtlck->index++;
@@ -2849,14 +2852,14 @@
 		s32 unused;
 	} *dtoffset = (struct dtoffset *) &filp->f_pos;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	int index;
 	s8 *stbl;
-	btstack_t btstack;
+	struct btstack btstack;
 	int i, next;
-	ldtentry_t *d;
-	dtslot_t *t;
+	struct ldtentry *d;
+	struct dtslot *t;
 	int d_namleft, d_namlen, len, outlen;
 	char *d_name, *name_ptr;
 	int dtlhdrdatalen;
@@ -2880,7 +2883,7 @@
 		dir_index = (u32) filp->f_pos;
 
 		if (dir_index > 1) {
-			dir_table_slot_t dirtab_slot;
+			struct dir_table_slot dirtab_slot;
 
 			if (dtEmpty(ip)) {
 				filp->f_pos = DIREND;
@@ -3017,7 +3020,7 @@
 		stbl = DT_GETSTBL(p);
 
 		for (i = index; i < p->header.nextindex; i++) {
-			d = (ldtentry_t *) & p->slot[stbl[i]];
+			d = (struct ldtentry *) & p->slot[stbl[i]];
 
 			d_namleft = d->namlen;
 			name_ptr = d_name;
@@ -3036,7 +3039,7 @@
 			/* copy name in the additional segment(s) */
 			next = d->next;
 			while (next >= 0) {
-				t = (dtslot_t *) & p->slot[next];
+				t = (struct dtslot *) & p->slot[next];
 				name_ptr += outlen;
 				d_namleft -= len;
 				/* Sanity Check */
@@ -3110,15 +3113,15 @@
  *
  * function: get the leftmost page of the directory
  */
-static int dtReadFirst(struct inode *ip, btstack_t * btstack)
+static int dtReadFirst(struct inode *ip, struct btstack * btstack)
 {
 	int rc = 0;
 	s64 bn;
 	int psize = 288;	/* initial in-line directory */
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	s8 *stbl;
-	btframe_t *btsp;
+	struct btframe *btsp;
 	pxd_t *xd;
 
 	BT_CLR(btstack);	/* reset stack */
@@ -3176,7 +3179,8 @@
  * note: if index > nextindex of the target leaf page,
  * start with 1st entry of next leaf page;
  */
-static int dtReadNext(struct inode *ip, loff_t * offset, btstack_t * btstack)
+static int dtReadNext(struct inode *ip, loff_t * offset,
+		      struct btstack * btstack)
 {
 	int rc = 0;
 	struct dtoffset {
@@ -3185,12 +3189,12 @@
 		s32 unused;
 	} *dtoffset = (struct dtoffset *) offset;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	int index;
 	int pn;
 	s8 *stbl;
-	btframe_t *btsp, *parent;
+	struct btframe *btsp, *parent;
 	pxd_t *xd;
 
 	/*
@@ -3351,14 +3355,14 @@
  *	= 0 if k is = record
  *	> 0 if k is > record
  */
-static int dtCompare(component_t * key,	/* search key */
+static int dtCompare(struct component_name * key,	/* search key */
 		     dtpage_t * p,	/* directory page */
 		     int si)
 {				/* entry slot index */
 	wchar_t *kname, *name;
 	int klen, namlen, len, rc;
-	idtentry_t *ih;
-	dtslot_t *t;
+	struct idtentry *ih;
+	struct dtslot *t;
 
 	/*
 	 * force the left-most key on internal pages, at any level of
@@ -3379,7 +3383,7 @@
 	kname = key->name;
 	klen = key->namlen;
 
-	ih = (idtentry_t *) & p->slot[si];
+	ih = (struct idtentry *) & p->slot[si];
 	si = ih->next;
 	name = ih->name;
 	namlen = ih->namlen;
@@ -3397,7 +3401,7 @@
 	kname += len;
 	while (klen > 0 && namlen > 0) {
 		/* compare with next name segment */
-		t = (dtslot_t *) & p->slot[si];
+		t = (struct dtslot *) & p->slot[si];
 		len = min(namlen, DTSLOTDATALEN);
 		len = min(klen, len);
 		name = t->name;
@@ -3426,16 +3430,16 @@
  *	= 0 if k is = record
  *	> 0 if k is > record
  */
-static int ciCompare(component_t * key,	/* search key */
+static int ciCompare(struct component_name * key,	/* search key */
 		     dtpage_t * p,	/* directory page */
 		     int si,	/* entry slot index */
 		     int flag)
 {
 	wchar_t *kname, *name, x;
 	int klen, namlen, len, rc;
-	ldtentry_t *lh;
-	idtentry_t *ih;
-	dtslot_t *t;
+	struct ldtentry *lh;
+	struct idtentry *ih;
+	struct dtslot *t;
 	int i;
 
 	/*
@@ -3461,7 +3465,7 @@
 	 * leaf page entry
 	 */
 	if (p->header.flag & BT_LEAF) {
-		lh = (ldtentry_t *) & p->slot[si];
+		lh = (struct ldtentry *) & p->slot[si];
 		si = lh->next;
 		name = lh->name;
 		namlen = lh->namlen;
@@ -3474,7 +3478,7 @@
 	 * internal page entry
 	 */
 	else {
-		ih = (idtentry_t *) & p->slot[si];
+		ih = (struct idtentry *) & p->slot[si];
 		si = ih->next;
 		name = ih->name;
 		namlen = ih->namlen;
@@ -3499,7 +3503,7 @@
 	/* compare with additional segment(s) */
 	while (klen > 0 && namlen > 0) {
 		/* compare with next name segment */
-		t = (dtslot_t *) & p->slot[si];
+		t = (struct dtslot *) & p->slot[si];
 		len = min(namlen, DTSLOTDATALEN);
 		len = min(klen, len);
 		name = t->name;
@@ -3534,14 +3538,14 @@
  *	Number of prefix bytes needed to distinguish b from a.
  */
 static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
-			       int ri, component_t * key, int flag)
+			       int ri, struct component_name * key, int flag)
 {
 	int klen, namlen;
 	wchar_t *pl, *pr, *kname;
 	wchar_t lname[JFS_NAME_MAX + 1];
-	component_t lkey = { 0, lname };
+	struct component_name lkey = { 0, lname };
 	wchar_t rname[JFS_NAME_MAX + 1];
-	component_t rkey = { 0, rname };
+	struct component_name rkey = { 0, rname };
 
 	/* get left and right key */
 	dtGetKey(lp, li, &lkey, flag);
@@ -3588,13 +3592,13 @@
  * function: get key of the entry
  */
 static void dtGetKey(dtpage_t * p, int i,	/* entry index */
-		     component_t * key, int flag)
+		     struct component_name * key, int flag)
 {
 	int si;
 	s8 *stbl;
-	ldtentry_t *lh;
-	idtentry_t *ih;
-	dtslot_t *t;
+	struct ldtentry *lh;
+	struct idtentry *ih;
+	struct dtslot *t;
 	int namlen, len;
 	wchar_t *name, *kname;
 
@@ -3602,7 +3606,7 @@
 	stbl = DT_GETSTBL(p);
 	si = stbl[i];
 	if (p->header.flag & BT_LEAF) {
-		lh = (ldtentry_t *) & p->slot[si];
+		lh = (struct ldtentry *) & p->slot[si];
 		si = lh->next;
 		namlen = lh->namlen;
 		name = lh->name;
@@ -3611,7 +3615,7 @@
 		else
 			len = min(namlen, DTLHDRDATALEN_LEGACY);
 	} else {
-		ih = (idtentry_t *) & p->slot[si];
+		ih = (struct idtentry *) & p->slot[si];
 		si = ih->next;
 		namlen = ih->namlen;
 		name = ih->name;
@@ -3650,21 +3654,21 @@
  *
  * return: entry slot index
  */
-static void dtInsertEntry(dtpage_t * p, int index, component_t * key,
-			  ddata_t * data, dtlock_t ** dtlock)
+static void dtInsertEntry(dtpage_t * p, int index, struct component_name * key,
+			  ddata_t * data, struct dt_lock ** dtlock)
 {
-	dtslot_t *h, *t;
-	ldtentry_t *lh = 0;
-	idtentry_t *ih = 0;
+	struct dtslot *h, *t;
+	struct ldtentry *lh = 0;
+	struct idtentry *ih = 0;
 	int hsi, fsi, klen, len, nextindex;
 	wchar_t *kname, *name;
 	s8 *stbl;
 	pxd_t *xd;
-	dtlock_t *dtlck = *dtlock;
-	lv_t *lv;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
 	int xsi, n;
 	s64 bn = 0;
-	metapage_t *mp = 0;
+	struct metapage *mp = 0;
 
 	klen = key->namlen;
 	kname = key->name;
@@ -3677,14 +3681,14 @@
 
 	/* open new linelock */
 	if (dtlck->index >= dtlck->maxcnt)
-		dtlck = (dtlock_t *) txLinelock(dtlck);
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
 
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+	lv = & dtlck->lv[dtlck->index];
 	lv->offset = hsi;
 
 	/* write head/only segment */
 	if (p->header.flag & BT_LEAF) {
-		lh = (ldtentry_t *) h;
+		lh = (struct ldtentry *) h;
 		lh->next = h->next;
 		lh->inumber = data->leaf.ino;	/* little-endian */
 		lh->namlen = klen;
@@ -3699,7 +3703,7 @@
 		} else
 			len = min(klen, DTLHDRDATALEN_LEGACY);
 	} else {
-		ih = (idtentry_t *) h;
+		ih = (struct idtentry *) h;
 		ih->next = h->next;
 		xd = (pxd_t *) ih;
 		*xd = data->xd;
@@ -3733,8 +3737,8 @@
 			if (dtlck->index < dtlck->maxcnt)
 				lv++;
 			else {
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-				lv = (lv_t *) & dtlck->lv[0];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
 			}
 
 			lv->offset = fsi;
@@ -3780,7 +3784,7 @@
 			 */
 			mp = 0;
 			for (n = index + 1; n <= nextindex; n++) {
-				lh = (ldtentry_t *) & (p->slot[stbl[n]]);
+				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
 				modify_index(data->leaf.tid, data->leaf.ip,
 					     le32_to_cpu(lh->index), bn, n,
 					     &mp);
@@ -3806,7 +3810,7 @@
  *	are updated.
  */
 static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
-			dtlock_t ** sdtlock, dtlock_t ** ddtlock,
+			struct dt_lock ** sdtlock, struct dt_lock ** ddtlock,
 			int do_index)
 {
 	int ssi, next;		/* src slot index */
@@ -3814,11 +3818,11 @@
 	int dsi;		/* dst slot index */
 	s8 *sstbl, *dstbl;	/* sorted entry table */
 	int snamlen, len;
-	ldtentry_t *slh, *dlh = 0;
-	idtentry_t *sih, *dih = 0;
-	dtslot_t *h, *s, *d;
-	dtlock_t *sdtlck = *sdtlock, *ddtlck = *ddtlock;
-	lv_t *slv, *dlv;
+	struct ldtentry *slh, *dlh = 0;
+	struct idtentry *sih, *dih = 0;
+	struct dtslot *h, *s, *d;
+	struct dt_lock *sdtlck = *sdtlock, *ddtlck = *ddtlock;
+	struct lv *slv, *dlv;
 	int xssi, ns, nd;
 	int sfsi;
 
@@ -3829,11 +3833,11 @@
 	sfsi = sp->header.freelist;
 
 	/* linelock destination entry slot */
-	dlv = (lv_t *) & ddtlck->lv[ddtlck->index];
+	dlv = & ddtlck->lv[ddtlck->index];
 	dlv->offset = dsi;
 
 	/* linelock source entry slot */
-	slv = (lv_t *) & sdtlck->lv[sdtlck->index];
+	slv = & sdtlck->lv[sdtlck->index];
 	slv->offset = sstbl[si];
 	xssi = slv->offset - 1;
 
@@ -3855,8 +3859,8 @@
 			if (sdtlck->index < sdtlck->maxcnt)
 				slv++;
 			else {
-				sdtlck = (dtlock_t *) txLinelock(sdtlck);
-				slv = (lv_t *) & sdtlck->lv[0];
+				sdtlck = (struct dt_lock *) txLinelock(sdtlck);
+				slv = & sdtlck->lv[0];
 			}
 
 			slv->offset = ssi;
@@ -3873,8 +3877,8 @@
 		s = &sp->slot[ssi];
 		if (sp->header.flag & BT_LEAF) {
 			/* get source entry */
-			slh = (ldtentry_t *) s;
-			dlh = (ldtentry_t *) h;
+			slh = (struct ldtentry *) s;
+			dlh = (struct ldtentry *) h;
 			snamlen = slh->namlen;
 
 			if (do_index) {
@@ -3891,11 +3895,11 @@
 			dsi++;
 			dlh->next = dsi;
 		} else {
-			sih = (idtentry_t *) s;
+			sih = (struct idtentry *) s;
 			snamlen = sih->namlen;
 
 			len = min(snamlen, DTIHDRDATALEN);
-			dih = (idtentry_t *) h;
+			dih = (struct idtentry *) h;
 			memcpy(dih, sih, 10 + len * 2);
 			next = sih->next;
 
@@ -3928,9 +3932,9 @@
 					slv++;
 				else {
 					sdtlck =
-					    (dtlock_t *)
+					    (struct dt_lock *)
 					    txLinelock(sdtlck);
-					slv = (lv_t *) & sdtlck->lv[0];
+					slv = & sdtlck->lv[0];
 				}
 
 				slv->offset = ssi;
@@ -4006,14 +4010,14 @@
  * the entry logged to avoid applying previous updates
  * to the same slots)
  */
-static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock)
+static void dtDeleteEntry(dtpage_t * p, int fi, struct dt_lock ** dtlock)
 {
 	int fsi;		/* free entry slot index */
 	s8 *stbl;
-	dtslot_t *t;
+	struct dtslot *t;
 	int si, freecnt;
-	dtlock_t *dtlck = *dtlock;
-	lv_t *lv;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
 	int xsi, n;
 
 	/* get free entry slot index */
@@ -4022,17 +4026,17 @@
 
 	/* open new linelock */
 	if (dtlck->index >= dtlck->maxcnt)
-		dtlck = (dtlock_t *) txLinelock(dtlck);
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
 
 	lv->offset = fsi;
 
 	/* get the head/only segment */
 	t = &p->slot[fsi];
 	if (p->header.flag & BT_LEAF)
-		si = ((ldtentry_t *) t)->next;
+		si = ((struct ldtentry *) t)->next;
 	else
-		si = ((idtentry_t *) t)->next;
+		si = ((struct idtentry *) t)->next;
 	t->next = si;
 	t->cnt = 1;
 
@@ -4051,8 +4055,8 @@
 			if (dtlck->index < dtlck->maxcnt)
 				lv++;
 			else {
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-				lv = (lv_t *) & dtlck->lv[0];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
 			}
 
 			lv->offset = si;
@@ -4101,14 +4105,14 @@
  * the entry logged to avoid applying previous updates
  * to the same slots)
  */
-static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock)
+static void dtTruncateEntry(dtpage_t * p, int ti, struct dt_lock ** dtlock)
 {
 	int tsi;		/* truncate entry slot index */
 	s8 *stbl;
-	dtslot_t *t;
+	struct dtslot *t;
 	int si, freecnt;
-	dtlock_t *dtlck = *dtlock;
-	lv_t *lv;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
 	int fsi, xsi, n;
 
 	/* get free entry slot index */
@@ -4117,17 +4121,17 @@
 
 	/* open new linelock */
 	if (dtlck->index >= dtlck->maxcnt)
-		dtlck = (dtlock_t *) txLinelock(dtlck);
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
 
 	lv->offset = tsi;
 
 	/* get the head/only segment */
 	t = &p->slot[tsi];
 	ASSERT(p->header.flag & BT_INTERNAL);
-	((idtentry_t *) t)->namlen = 0;
-	si = ((idtentry_t *) t)->next;
-	((idtentry_t *) t)->next = -1;
+	((struct idtentry *) t)->namlen = 0;
+	si = ((struct idtentry *) t)->next;
+	((struct idtentry *) t)->next = -1;
 
 	n = 1;
 	freecnt = 0;
@@ -4146,8 +4150,8 @@
 			if (dtlck->index < dtlck->maxcnt)
 				lv++;
 			else {
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-				lv = (lv_t *) & dtlck->lv[0];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
 			}
 
 			lv->offset = si;
@@ -4183,13 +4187,13 @@
  */
 static void dtLinelockFreelist(dtpage_t * p,	/* directory page */
 			       int m,	/* max slot index */
-			       dtlock_t ** dtlock)
+			       struct dt_lock ** dtlock)
 {
 	int fsi;		/* free entry slot index */
-	dtslot_t *t;
+	struct dtslot *t;
 	int si;
-	dtlock_t *dtlck = *dtlock;
-	lv_t *lv;
+	struct dt_lock *dtlck = *dtlock;
+	struct lv *lv;
 	int xsi, n;
 
 	/* get free entry slot index */
@@ -4197,8 +4201,8 @@
 
 	/* open new linelock */
 	if (dtlck->index >= dtlck->maxcnt)
-		dtlck = (dtlock_t *) txLinelock(dtlck);
-	lv = (lv_t *) & dtlck->lv[dtlck->index];
+		dtlck = (struct dt_lock *) txLinelock(dtlck);
+	lv = & dtlck->lv[dtlck->index];
 
 	lv->offset = fsi;
 
@@ -4220,8 +4224,8 @@
 			if (dtlck->index < dtlck->maxcnt)
 				lv++;
 			else {
-				dtlck = (dtlock_t *) txLinelock(dtlck);
-				lv = (lv_t *) & dtlck->lv[0];
+				dtlck = (struct dt_lock *) txLinelock(dtlck);
+				lv = & dtlck->lv[0];
 			}
 
 			lv->offset = si;
@@ -4262,20 +4266,20 @@
  *	0	- If successfully modified entry
  */
 int dtModify(tid_t tid, struct inode *ip,
-	 component_t * key, ino_t * orig_ino, ino_t new_ino, int flag)
+	 struct component_name * key, ino_t * orig_ino, ino_t new_ino, int flag)
 {
 	int rc;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	int index;
-	btstack_t btstack;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	lv_t *lv;
+	struct btstack btstack;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
 	s8 *stbl;
 	int entry_si;		/* entry slot index */
-	ldtentry_t *entry;
+	struct ldtentry *entry;
 
 	/*
 	 *      search for the entry to modify:
@@ -4293,7 +4297,7 @@
 	 * acquire a transaction lock on the leaf page of named entry
 	 */
 	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
-	dtlck = (dtlock_t *) & tlck->lock;
+	dtlck = (struct dt_lock *) & tlck->lock;
 
 	/* get slot index of the entry */
 	stbl = DT_GETSTBL(p);
@@ -4301,13 +4305,13 @@
 
 	/* linelock entry */
 	ASSERT(dtlck->index == 0);
-	lv = (lv_t *) & dtlck->lv[0];
+	lv = & dtlck->lv[0];
 	lv->offset = entry_si;
 	lv->length = 1;
 	dtlck->index++;
 
 	/* get the head/only segment */
-	entry = (ldtentry_t *) & p->slot[entry_si];
+	entry = (struct ldtentry *) & p->slot[entry_si];
 
 	/* substitute the inode number of the entry */
 	entry->inumber = cpu_to_le32(new_ino);
@@ -4327,14 +4331,14 @@
 int dtDisplayTree(struct inode *ip)
 {
 	int rc;
-	metapage_t *mp;
+	struct metapage *mp;
 	dtpage_t *p;
 	s64 bn, pbn;
 	int index, lastindex, v, h;
 	pxd_t *xd;
-	btstack_t btstack;
-	btframe_t *btsp;
-	btframe_t *parent;
+	struct btstack btstack;
+	struct btframe *btsp;
+	struct btframe *parent;
 	u8 *stbl;
 	int psize = 256;
 
@@ -4465,14 +4469,14 @@
 int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p)
 {
 	int rc;
-	metapage_t *mp;
-	ldtentry_t *lh;
-	idtentry_t *ih;
+	struct metapage *mp;
+	struct ldtentry *lh;
+	struct idtentry *ih;
 	pxd_t *xd;
 	int i, j;
 	u8 *stbl;
 	wchar_t name[JFS_NAME_MAX + 1];
-	component_t key = { 0, name };
+	struct component_name key = { 0, name };
 	int freepage = 0;
 
 	if (p == NULL) {
@@ -4492,11 +4496,11 @@
 		dtGetKey(p, i, &key, JFS_SBI(ip->i_sb)->mntflag);
 		key.name[key.namlen] = '\0';
 		if (p->header.flag & BT_LEAF) {
-			lh = (ldtentry_t *) & p->slot[stbl[i]];
+			lh = (struct ldtentry *) & p->slot[stbl[i]];
 			printf("\t[%d] %s:%d", i, key.name,
 			       le32_to_cpu(lh->inumber));
 		} else {
-			ih = (idtentry_t *) & p->slot[stbl[i]];
+			ih = (struct idtentry *) & p->slot[stbl[i]];
 			xd = (pxd_t *) ih;
 			bn = addressPXD(xd);
 			printf("\t[%d] %s:0x%Lx", i, key.name, bn);
diff -Nru a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
--- a/fs/jfs/jfs_dtree.h	Sun Sep 15 19:19:46 2002
+++ b/fs/jfs/jfs_dtree.h	Sun Sep 15 19:19:46 2002
@@ -44,11 +44,11 @@
 /*
  *	directory page slot
  */
-typedef struct {
+struct dtslot {
 	s8 next;		/* 1: */
 	s8 cnt;			/* 1: */
 	wchar_t name[15];	/* 30: */
-} dtslot_t;			/* (32) */
+};				/* (32) */
 
 
 #define DATASLOTSIZE	16
@@ -62,13 +62,13 @@
 /*
  *	 internal node entry head/only segment
  */
-typedef struct {
+struct idtentry {
 	pxd_t xd;		/* 8: child extent descriptor */
 
 	s8 next;		/* 1: */
 	u8 namlen;		/* 1: */
 	wchar_t name[11];	/* 22: 2-byte aligned */
-} idtentry_t;			/* (32) */
+};				/* (32) */
 
 #define DTIHDRSIZE	10
 #define DTIHDRDATALEN	11
@@ -82,13 +82,13 @@
  *
  * 	For legacy filesystems, name contains 13 wchars -- no index field
  */
-typedef struct {
+struct ldtentry {
 	u32 inumber;		/* 4: 4-byte aligned */
 	s8 next;		/* 1: */
 	u8 namlen;		/* 1: */
 	wchar_t name[11];	/* 22: 2-byte aligned */
 	u32 index;		/* 4: index into dir_table */
-} ldtentry_t;			/* (32) */
+};				/* (32) */
 
 #define DTLHDRSIZE	6
 #define DTLHDRDATALEN_LEGACY	13	/* Old (OS/2) format */
@@ -108,14 +108,14 @@
  */
 #define MAX_INLINE_DIRTABLE_ENTRY 13
 
-typedef struct dir_table_slot {
+struct dir_table_slot {
 	u8 rsrvd;		/* 1: */
 	u8 flag;		/* 1: 0 if free */
 	u8 slot;		/* 1: slot within leaf page of entry */
 	u8 addr1;		/* 1: upper 8 bits of leaf page address */
 	u32 addr2;		/* 4: lower 32 bits of leaf page address -OR-
 				   index of next entry when this entry was deleted */
-} dir_table_slot_t;		/* (8) */
+};				/* (8) */
 
 /*
  * flag values
@@ -144,7 +144,7 @@
  */
 typedef union {
 	struct {
-		dasd_t DASD;	/* 16: DASD limit/usage info  F226941 */
+		struct dasd DASD; /* 16: DASD limit/usage info */
 
 		u8 flag;	/* 1: */
 		u8 nextindex;	/* 1: next free entry in stbl */
@@ -156,7 +156,7 @@
 		s8 stbl[8];	/* 8: sorted entry index table */
 	} header;		/* (32) */
 
-	dtslot_t slot[9];
+	struct dtslot slot[9];
 } dtroot_t;
 
 #define PARENT(IP) \
@@ -207,7 +207,7 @@
 		pxd_t self;	/* 8: self pxd */
 	} header;		/* (32) */
 
-	dtslot_t slot[128];
+	struct dtslot slot[128];
 } dtpage_t;
 
 #define DTPAGEMAXSLOT        128
@@ -256,20 +256,20 @@
  */
 extern void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot);
 
-extern int dtSearch(struct inode *ip, component_t * key,
-		    ino_t * data, btstack_t * btstack, int flag);
+extern int dtSearch(struct inode *ip, struct component_name * key,
+		    ino_t * data, struct btstack * btstack, int flag);
 
-extern int dtInsert(tid_t tid, struct inode *ip,
-		    component_t * key, ino_t * ino, btstack_t * btstack);
+extern int dtInsert(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * ino, struct btstack * btstack);
 
-extern int dtDelete(tid_t tid,
-		    struct inode *ip, component_t * key, ino_t * data, int flag);
+extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * data, int flag);
 
 extern int dtRelocate(tid_t tid,
 		      struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr);
 
-extern int dtModify(tid_t tid, struct inode *ip,
-		    component_t * key, ino_t * orig_ino, ino_t new_ino, int flag);
+extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key,
+		    ino_t * orig_ino, ino_t new_ino, int flag);
 
 extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
 
diff -Nru a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
--- a/fs/jfs/jfs_extent.c	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/jfs_extent.c	Sun Sep 15 19:19:28 2002
@@ -358,8 +358,8 @@
 int extHint(struct inode *ip, s64 offset, xad_t * xp)
 {
 	struct super_block *sb = ip->i_sb;
-	xadlist_t xadl;
-	lxdlist_t lxdl;
+	struct xadlist xadl;
+	struct lxdlist lxdl;
 	lxd_t lxd;
 	s64 prev;
 	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
@@ -516,7 +516,7 @@
 {
 	s64 nb, nblks, daddr, max;
 	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
-	bmap_t *mp = JFS_SBI(ip->i_sb)->bmap;
+	struct bmap *mp = JFS_SBI(ip->i_sb)->bmap;
 
 	/* get the number of blocks to initially attempt to allocate.
 	 * we'll first try the number of blocks requested unless this
diff -Nru a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
--- a/fs/jfs/jfs_filsys.h	Sun Sep 15 19:19:46 2002
+++ b/fs/jfs/jfs_filsys.h	Sun Sep 15 19:19:46 2002
@@ -125,7 +125,7 @@
 #define MAXBLOCKSIZE		4096
 #define	MAXFILESIZE		((s64)1 << 52)
 
-#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+#define JFS_LINK_MAX		0xffffffff
 
 /* Minimum number of bytes supported for a JFS partition */
 #define MINJFS			(0x1000000)
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_imap.c	Sun Sep 15 19:19:29 2002
@@ -74,19 +74,19 @@
 /*
  * forward references
  */
-static int diAllocAG(imap_t *, int, boolean_t, struct inode *);
-static int diAllocAny(imap_t *, int, boolean_t, struct inode *);
-static int diAllocBit(imap_t *, iag_t *, int);
-static int diAllocExt(imap_t *, int, struct inode *);
-static int diAllocIno(imap_t *, int, struct inode *);
+static int diAllocAG(struct inomap *, int, boolean_t, struct inode *);
+static int diAllocAny(struct inomap *, int, boolean_t, struct inode *);
+static int diAllocBit(struct inomap *, struct iag *, int);
+static int diAllocExt(struct inomap *, int, struct inode *);
+static int diAllocIno(struct inomap *, int, struct inode *);
 static int diFindFree(u32, int);
-static int diNewExt(imap_t *, iag_t *, int);
-static int diNewIAG(imap_t *, int *, int, metapage_t **);
+static int diNewExt(struct inomap *, struct iag *, int);
+static int diNewIAG(struct inomap *, int *, int, struct metapage **);
 static void duplicateIXtree(struct super_block *, s64, int, s64 *);
 
-static int diIAGRead(imap_t * imap, int, metapage_t **);
-static int copy_from_dinode(dinode_t *, struct inode *);
-static void copy_to_dinode(dinode_t *, struct inode *);
+static int diIAGRead(struct inomap * imap, int, struct metapage **);
+static int copy_from_dinode(struct dinode *, struct inode *);
+static void copy_to_dinode(struct dinode *, struct inode *);
 
 /*
  *	debug code for double-checking inode map
@@ -98,9 +98,9 @@
 #define DBG_DIALLOC(imap, ino)	DBGdiAlloc(imap, ino)
 #define DBG_DIFREE(imap, ino)	DBGdiFree(imap, ino)
 
-static void *DBGdiInit(imap_t * imap);
-static void DBGdiAlloc(imap_t * imap, ino_t ino);
-static void DBGdiFree(imap_t * imap, ino_t ino);
+static void *DBGdiInit(struct inomap * imap);
+static void DBGdiAlloc(struct inomap * imap, ino_t ino);
+static void DBGdiFree(struct inomap * imap, ino_t ino);
 #else
 #define DBG_DIINIT(imap)
 #define DBG_DIALLOC(imap, ino)
@@ -113,7 +113,7 @@
  * FUNCTION:    initialize the incore inode map control structures for
  *		a fileset or aggregate init time.
  *
- *              the inode map's control structure (dinomap_t) is 
+ *              the inode map's control structure (dinomap) is 
  *              brought in from disk and placed in virtual memory.
  *
  * PARAMETERS:
@@ -126,16 +126,16 @@
  */
 int diMount(struct inode *ipimap)
 {
-	imap_t *imap;
-	metapage_t *mp;
+	struct inomap *imap;
+	struct metapage *mp;
 	int index;
-	dinomap_t *dinom_le;
+	struct dinomap *dinom_le;
 
 	/*
 	 * allocate/initialize the in-memory inode map control structure
 	 */
 	/* allocate the in-memory inode map control structure. */
-	imap = (imap_t *) kmalloc(sizeof(imap_t), GFP_KERNEL);
+	imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL);
 	if (imap == NULL) {
 		jERROR(1, ("diMount: kmalloc returned NULL!\n"));
 		return (ENOMEM);
@@ -152,7 +152,7 @@
 	}
 
 	/* copy the on-disk version to the in-memory version. */
-	dinom_le = (dinomap_t *) mp->data;
+	dinom_le = (struct dinomap *) mp->data;
 	imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag);
 	imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag);
 	atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos));
@@ -212,7 +212,7 @@
  */
 int diUnmount(struct inode *ipimap, int mounterror)
 {
-	imap_t *imap = JFS_IP(ipimap)->i_imap;
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
 
 	/*
 	 * update the on-disk inode map control structure
@@ -240,9 +240,9 @@
  */
 int diSync(struct inode *ipimap)
 {
-	dinomap_t *dinom_le;
-	imap_t *imp = JFS_IP(ipimap)->i_imap;
-	metapage_t *mp;
+	struct dinomap *dinom_le;
+	struct inomap *imp = JFS_IP(ipimap)->i_imap;
+	struct metapage *mp;
 	int index;
 
 	/*
@@ -258,8 +258,7 @@
 	}
 
 	/* copy the in-memory version to the on-disk version */
-	//memcpy(mp->data, &imp->im_imap,sizeof(dinomap_t));
-	dinom_le = (dinomap_t *) mp->data;
+	dinom_le = (struct dinomap *) mp->data;
 	dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
 	dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
 	dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
@@ -330,11 +329,11 @@
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	int iagno, ino, extno, rc;
 	struct inode *ipimap;
-	dinode_t *dp;
-	iag_t *iagp;
-	metapage_t *mp;
+	struct dinode *dp;
+	struct iag *iagp;
+	struct metapage *mp;
 	s64 blkno, agstart;
-	imap_t *imap;
+	struct inomap *imap;
 	int block_offset;
 	int inodes_left;
 	uint pageno;
@@ -358,7 +357,7 @@
 		return (rc);
 	}
 
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 
 	/* determine inode extent that holds the disk inode */
 	ino = ip->i_ino & (INOSPERIAG - 1);
@@ -410,7 +409,7 @@
 	}
 
 	/* locate the the disk inode requested */
-	dp = (dinode_t *) mp->data;
+	dp = (struct dinode *) mp->data;
 	dp += rel_inode;
 
 	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
@@ -461,9 +460,9 @@
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	uint address;
-	dinode_t *dp;
+	struct dinode *dp;
 	struct inode *ip;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	ip = new_inode(sb);
 	if (ip == NULL) {
@@ -499,7 +498,7 @@
 	}
 
 	/* get the pointer to the disk inode of interest */
-	dp = (dinode_t *) (mp->data);
+	dp = (struct dinode *) (mp->data);
 	dp += inum % 8;		/* 8 inodes per 4K page */
 
 	/* copy on-disk inode to in-memory inode */
@@ -544,9 +543,9 @@
 {
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	uint address;
-	dinode_t *dp;
+	struct dinode *dp;
 	ino_t inum = ip->i_ino;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	ip->i_state &= ~I_DIRTY;
 
@@ -571,7 +570,7 @@
 	}
 
 	/* get the pointer to the disk inode of interest */
-	dp = (dinode_t *) (mp->data);
+	dp = (struct dinode *) (mp->data);
 	dp += inum % 8;		/* 8 inodes per 4K page */
 
 	/* copy on-disk inode to in-memory inode */
@@ -634,20 +633,20 @@
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	int rc = 0;
 	s32 ino;
-	dinode_t *dp;
+	struct dinode *dp;
 	s64 blkno;
 	int block_offset;
 	int inodes_left;
-	metapage_t *mp;
+	struct metapage *mp;
 	uint pageno;
 	int rel_inode;
 	int dioffset;
 	struct inode *ipimap;
 	uint type;
 	lid_t lid;
-	tlock_t *ditlck, *tlck;
-	linelock_t *dilinelock, *ilinelock;
-	lv_t *lv;
+	struct tlock *ditlck, *tlck;
+	struct linelock *dilinelock, *ilinelock;
+	struct lv *lv;
 	int n;
 
 	ipimap = jfs_ip->ipimap;
@@ -688,7 +687,7 @@
 		return (EIO);
 
 	/* get the pointer to the disk inode */
-	dp = (dinode_t *) mp->data;
+	dp = (struct dinode *) mp->data;
 	dp += rel_inode;
 
 	dioffset = (ino & (INOSPERPAGE - 1)) << L2DISIZE;
@@ -700,7 +699,7 @@
 	if ((ditlck =
 	     txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL)
 		goto retry;
-	dilinelock = (linelock_t *) & ditlck->lock;
+	dilinelock = (struct linelock *) & ditlck->lock;
 
 	/*
 	 * copy btree root from in-memory inode to on-disk inode
@@ -728,14 +727,14 @@
 		assert(tlck->type & tlckXTREE);
 		tlck->type |= tlckBTROOT;
 		tlck->mp = mp;
-		ilinelock = (linelock_t *) & tlck->lock;
+		ilinelock = (struct linelock *) & tlck->lock;
 
 		/*
 		 * copy xtree root from inode to dinode:
 		 */
 		p = &jfs_ip->i_xtroot;
 		xp = (xtpage_t *) &dp->di_dirtable;
-		lv = (lv_t *) & ilinelock->lv;
+		lv = ilinelock->lv;
 		for (n = 0; n < ilinelock->index; n++, lv++) {
 			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
 			       lv->length << L2XTSLOTSIZE);
@@ -757,7 +756,7 @@
 	type = tlck->type;
 	tlck->type |= tlckBTROOT;
 	tlck->mp = mp;
-	ilinelock = (linelock_t *) & tlck->lock;
+	ilinelock = (struct linelock *) & tlck->lock;
 
 	/*
 	 *      regular file: 16 byte (XAD slot) granularity
@@ -771,7 +770,7 @@
 		 */
 		p = &jfs_ip->i_xtroot;
 		xp = &dp->di_xtroot;
-		lv = (lv_t *) & ilinelock->lv;
+		lv = ilinelock->lv;
 		for (n = 0; n < ilinelock->index; n++, lv++) {
 			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
 			       lv->length << L2XTSLOTSIZE);
@@ -795,7 +794,7 @@
 		 */
 		p = (dtpage_t *) &jfs_ip->i_dtroot;
 		xp = (dtpage_t *) & dp->di_dtroot;
-		lv = (lv_t *) & ilinelock->lv;
+		lv = ilinelock->lv;
 		for (n = 0; n < ilinelock->index; n++, lv++) {
 			memcpy(&xp->slot[lv->offset], &p->slot[lv->offset],
 			       lv->length << L2DTSLOTSIZE);
@@ -809,7 +808,7 @@
 	 * copy inline symlink from in-memory inode to on-disk inode
 	 */
 	if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) {
-		lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+		lv = & dilinelock->lv[dilinelock->index];
 		lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE;
 		lv->length = 2;
 		memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE);
@@ -820,7 +819,7 @@
 	 * 128 byte slot granularity
 	 */
 	if (test_cflag(COMMIT_Inlineea, ip)) {
-		lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+		lv = & dilinelock->lv[dilinelock->index];
 		lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE;
 		lv->length = 1;
 		memcpy(&dp->di_inlineea, jfs_ip->i_inline_ea, INODESLOTSIZE);
@@ -833,7 +832,7 @@
 	 *      lock/copy inode base: 128 byte slot granularity
 	 */
 // baseDinode:
-	lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+	lv = & dilinelock->lv[dilinelock->index];
 	lv->offset = dioffset >> L2INODESLOTSIZE;
 	copy_to_dinode(dp, ip);
 	if (test_and_clear_cflag(COMMIT_Dirtable, ip)) {
@@ -851,7 +850,7 @@
 	 */
 	if (S_ISDIR(ip->i_mode)
 	    && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED))
-		bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(dasd_t));
+		bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(struct dasd));
 #endif				/*  _JFS_FASTDASD */
 
 	/* release the buffer holding the updated on-disk inode. 
@@ -905,18 +904,18 @@
 {
 	int rc;
 	ino_t inum = ip->i_ino;
-	iag_t *iagp, *aiagp, *biagp, *ciagp, *diagp;
-	metapage_t *mp, *amp, *bmp, *cmp, *dmp;
+	struct iag *iagp, *aiagp, *biagp, *ciagp, *diagp;
+	struct metapage *mp, *amp, *bmp, *cmp, *dmp;
 	int iagno, ino, extno, bitno, sword, agno;
 	int back, fwd;
 	u32 bitmap, mask;
 	struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap;
-	imap_t *imap = JFS_IP(ipimap)->i_imap;
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
 	pxd_t freepxd;
 	tid_t tid;
 	struct inode *iplist[3];
-	tlock_t *tlck;
-	pxdlock_t *pxdlock;
+	struct tlock *tlck;
+	struct pxd_lock *pxdlock;
 
 	/*
 	 * This is just to suppress compiler warnings.  The same logic that
@@ -960,7 +959,7 @@
 		AG_UNLOCK(imap, agno);
 		return (rc);
 	}
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 
 	/* get the inode number and extent number of the inode within
 	 * the iag and the inode number within the extent.
@@ -1017,7 +1016,7 @@
 					release_metapage(mp);
 					return (rc);
 				}
-				aiagp = (iag_t *) amp->data;
+				aiagp = (struct iag *) amp->data;
 
 				/* make current head point back to the iag.
 				 */
@@ -1096,7 +1095,7 @@
 		if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
 			if ((rc = diIAGRead(imap, fwd, &amp)))
 				goto error_out;
-			aiagp = (iag_t *) amp->data;
+			aiagp = (struct iag *) amp->data;
 		}
 	} else {
 		/* iag has free extents. check if the addition of a free
@@ -1113,13 +1112,13 @@
 			if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
 				if ((rc = diIAGRead(imap, fwd, &amp)))
 					goto error_out;
-				aiagp = (iag_t *) amp->data;
+				aiagp = (struct iag *) amp->data;
 			}
 
 			if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
 				if ((rc = diIAGRead(imap, back, &bmp)))
 					goto error_out;
-				biagp = (iag_t *) bmp->data;
+				biagp = (struct iag *) bmp->data;
 			}
 		}
 	}
@@ -1142,30 +1141,30 @@
 		if (inofreefwd >= 0) {
 
 			if (inofreefwd == fwd)
-				ciagp = (iag_t *) amp->data;
+				ciagp = (struct iag *) amp->data;
 			else if (inofreefwd == back)
-				ciagp = (iag_t *) bmp->data;
+				ciagp = (struct iag *) bmp->data;
 			else {
 				if ((rc =
 				     diIAGRead(imap, inofreefwd, &cmp)))
 					goto error_out;
 				assert(cmp != NULL);
-				ciagp = (iag_t *) cmp->data;
+				ciagp = (struct iag *) cmp->data;
 			}
 			assert(ciagp != NULL);
 		}
 
 		if (inofreeback >= 0) {
 			if (inofreeback == fwd)
-				diagp = (iag_t *) amp->data;
+				diagp = (struct iag *) amp->data;
 			else if (inofreeback == back)
-				diagp = (iag_t *) bmp->data;
+				diagp = (struct iag *) bmp->data;
 			else {
 				if ((rc =
 				     diIAGRead(imap, inofreeback, &dmp)))
 					goto error_out;
 				assert(dmp != NULL);
-				diagp = (iag_t *) dmp->data;
+				diagp = (struct iag *) dmp->data;
 			}
 			assert(diagp != NULL);
 		}
@@ -1297,7 +1296,7 @@
 	 * N.B. linelock is overlaid as freed extent descriptor;
 	 */
 	tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE);
-	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock = (struct pxd_lock *) & tlck->lock;
 	pxdlock->flag = mlckFREEPXD;
 	pxdlock->pxd = freepxd;
 	pxdlock->index = 1;
@@ -1350,7 +1349,7 @@
  * the inode.
  */
 static inline void
-diInitInode(struct inode *ip, int iagno, int ino, int extno, iag_t * iagp)
+diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
@@ -1384,10 +1383,10 @@
 	int nwords, rem, i, agno;
 	u32 mask, inosmap, extsmap;
 	struct inode *ipimap;
-	metapage_t *mp;
+	struct metapage *mp;
 	ino_t inum;
-	iag_t *iagp;
-	imap_t *imap;
+	struct iag *iagp;
+	struct inomap *imap;
 
 	/* get the pointers to the inode map inode and the
 	 * corresponding imap control structure.
@@ -1436,7 +1435,7 @@
 		IREAD_UNLOCK(ipimap);
 		return (rc);
 	}
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 
 	/* determine if new inode extent is allowed to be added to the iag.
 	 * new inode extent can be added to the iag if the ag
@@ -1667,7 +1666,7 @@
  *      EIO  	- i/o error.
  */
 static int
-diAllocAG(imap_t * imap, int agno, boolean_t dir, struct inode *ip)
+diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
 {
 	int rc, addext, numfree, numinos;
 
@@ -1738,7 +1737,7 @@
  *      EIO  	- i/o error.
  */
 static int
-diAllocAny(imap_t * imap, int agno, boolean_t dir, struct inode *ip)
+diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
 {
 	int ag, rc;
 	int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
@@ -1802,11 +1801,11 @@
  *      ENOSPC 	- insufficient disk resources.
  *      EIO  	- i/o error.
  */
-static int diAllocIno(imap_t * imap, int agno, struct inode *ip)
+static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
 {
 	int iagno, ino, rc, rem, extno, sword;
-	metapage_t *mp;
-	iag_t *iagp;
+	struct metapage *mp;
+	struct iag *iagp;
 
 	/* check if there are iags on the ag's free inode list.
 	 */
@@ -1822,7 +1821,7 @@
 		IREAD_UNLOCK(imap->im_ipimap);
 		return (rc);
 	}
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 
 	/* better be free inodes in this iag if it is on the
 	 * list.
@@ -1913,11 +1912,11 @@
  *      ENOSPC 	- insufficient disk resources.
  *      EIO  	- i/o error.
  */
-static int diAllocExt(imap_t * imap, int agno, struct inode *ip)
+static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
 {
 	int rem, iagno, sword, extno, rc;
-	metapage_t *mp;
-	iag_t *iagp;
+	struct metapage *mp;
+	struct iag *iagp;
 
 	/* check if the ag has any iags with free extents.  if not,
 	 * allocate a new iag for the ag.
@@ -1929,7 +1928,7 @@
 		if ((rc = diNewIAG(imap, &iagno, agno, &mp))) {
 			return (rc);
 		}
-		iagp = (iag_t *) mp->data;
+		iagp = (struct iag *) mp->data;
 
 		/* set the ag number if this a brand new iag
 		 */
@@ -1942,7 +1941,7 @@
 		if ((rc = diIAGRead(imap, iagno, &mp))) {
 			assert(0);
 		}
-		iagp = (iag_t *) mp->data;
+		iagp = (struct iag *) mp->data;
 	}
 
 	/* using the free extent summary map, find a free extent.
@@ -2018,11 +2017,11 @@
  *      ENOSPC 	- insufficient disk resources.
  *      EIO  	- i/o error.
  */
-static int diAllocBit(imap_t * imap, iag_t * iagp, int ino)
+static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
 {
 	int extno, bitno, agno, sword, rc;
-	metapage_t *amp, *bmp;
-	iag_t *aiagp = 0, *biagp = 0;
+	struct metapage *amp, *bmp;
+	struct iag *aiagp = 0, *biagp = 0;
 	u32 mask;
 
 	/* check if this is the last free inode within the iag.
@@ -2038,7 +2037,7 @@
 			     diIAGRead(imap, le32_to_cpu(iagp->inofreefwd),
 				       &amp)))
 				return (rc);
-			aiagp = (iag_t *) amp->data;
+			aiagp = (struct iag *) amp->data;
 		}
 
 		if ((int) le32_to_cpu(iagp->inofreeback) >= 0) {
@@ -2050,7 +2049,7 @@
 					release_metapage(amp);
 				return (rc);
 			}
-			biagp = (iag_t *) bmp->data;
+			biagp = (struct iag *) bmp->data;
 		}
 	}
 
@@ -2158,17 +2157,17 @@
  *      ENOSPC 	- insufficient disk resources.
  *      EIO  	- i/o error.
  */
-static int diNewExt(imap_t * imap, iag_t * iagp, int extno)
+static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
 {
 	int agno, iagno, fwd, back, freei = 0, sword, rc;
-	iag_t *aiagp = 0, *biagp = 0, *ciagp = 0;
-	metapage_t *amp, *bmp, *cmp, *dmp;
+	struct iag *aiagp = 0, *biagp = 0, *ciagp = 0;
+	struct metapage *amp, *bmp, *cmp, *dmp;
 	struct inode *ipimap;
 	s64 blkno, hint;
 	int i, j;
 	u32 mask;
 	ino_t ino;
-	dinode_t *dp;
+	struct dinode *dp;
 	struct jfs_sb_info *sbi;
 
 	/* better have free extents.
@@ -2196,13 +2195,13 @@
 		if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
 			if ((rc = diIAGRead(imap, fwd, &amp)))
 				return (rc);
-			aiagp = (iag_t *) amp->data;
+			aiagp = (struct iag *) amp->data;
 		}
 
 		if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
 			if ((rc = diIAGRead(imap, back, &bmp)))
 				goto error_out;
-			biagp = (iag_t *) bmp->data;
+			biagp = (struct iag *) bmp->data;
 		}
 	} else {
 		/* the iag has free extents.  if all extents are free
@@ -2216,7 +2215,7 @@
 			if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
 				if ((rc = diIAGRead(imap, fwd, &amp)))
 					goto error_out;
-				aiagp = (iag_t *) amp->data;
+				aiagp = (struct iag *) amp->data;
 			}
 		}
 	}
@@ -2239,7 +2238,7 @@
 			} else {
 				if ((rc = diIAGRead(imap, freei, &cmp)))
 					goto error_out;
-				ciagp = (iag_t *) cmp->data;
+				ciagp = (struct iag *) cmp->data;
 			}
 			assert(ciagp != NULL);
 		}
@@ -2272,7 +2271,7 @@
 			rc = EIO;
 			goto error_out;
 		}
-		dp = (dinode_t *) dmp->data;
+		dp = (struct dinode *) dmp->data;
 
 		/* initialize the inode number, mode, link count and
 		 * inode extent address.
@@ -2433,15 +2432,15 @@
  *   new imap size;
  */
 static int
-diNewIAG(imap_t * imap, int *iagnop, int agno, metapage_t ** mpp)
+diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
 {
 	int rc;
 	int iagno, i, xlen;
 	struct inode *ipimap;
 	struct super_block *sb;
 	struct jfs_sb_info *sbi;
-	metapage_t *mp;
-	iag_t *iagp;
+	struct metapage *mp;
+	struct iag *iagp;
 	s64 xaddr = 0;
 	s64 blkno;
 	tid_t tid;
@@ -2521,10 +2520,10 @@
 			rc = EIO;
 			goto out;
 		}
-		iagp = (iag_t *) mp->data;
+		iagp = (struct iag *) mp->data;
 
 		/* init the iag */
-		memset(iagp, 0, sizeof(iag_t));
+		memset(iagp, 0, sizeof(struct iag));
 		iagp->iagnum = cpu_to_le32(iagno);
 		iagp->inofreefwd = iagp->inofreeback = -1;
 		iagp->extfreefwd = iagp->extfreeback = -1;
@@ -2619,7 +2618,7 @@
 		rc = EIO;
 		goto out;
 	}
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 
 	/* remove the iag from the iag free list */
 	imap->im_freeiag = le32_to_cpu(iagp->iagfree);
@@ -2657,7 +2656,7 @@
  *      0       - success.
  *      EIO  	- i/o error.
  */
-static int diIAGRead(imap_t * imap, int iagno, metapage_t ** mpp)
+static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
 {
 	struct inode *ipimap = imap->im_ipimap;
 	s64 blkno;
@@ -2719,15 +2718,15 @@
  */
 int
 diUpdatePMap(struct inode *ipimap,
-	     unsigned long inum, boolean_t is_free, tblock_t * tblk)
+	     unsigned long inum, boolean_t is_free, struct tblock * tblk)
 {
 	int rc;
-	iag_t *iagp;
-	metapage_t *mp;
+	struct iag *iagp;
+	struct metapage *mp;
 	int iagno, ino, extno, bitno;
-	imap_t *imap;
+	struct inomap *imap;
 	u32 mask;
-	log_t *log;
+	struct jfs_log *log;
 	int lsn, difft, diffp;
 
 	imap = JFS_IP(ipimap)->i_imap;
@@ -2741,7 +2740,7 @@
 	IREAD_UNLOCK(ipimap);
 	if (rc)
 		return (rc);
-	iagp = (iag_t *) mp->data;
+	iagp = (struct iag *) mp->data;
 	/* get the inode number and extent number of the inode within
 	 * the iag and the inode number within the extent.
 	 */
@@ -2837,10 +2836,10 @@
 int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
 {
 	int rc, rcx = 0;
-	imap_t *imap = JFS_IP(ipimap)->i_imap;
-	iag_t *iagp = 0, *hiagp = 0;
-	bmap_t *mp = JFS_SBI(ipbmap->i_sb)->bmap;
-	metapage_t *bp, *hbp;
+	struct inomap *imap = JFS_IP(ipimap)->i_imap;
+	struct iag *iagp = 0, *hiagp = 0;
+	struct bmap *mp = JFS_SBI(ipbmap->i_sb)->bmap;
+	struct metapage *bp, *hbp;
 	int i, n, head;
 	int numinos, xnuminos = 0, xnumfree = 0;
 	s64 agstart;
@@ -2866,7 +2865,7 @@
 	}
 
 	/*
-	 *      process each iag_t page of the map.
+	 *      process each iag page of the map.
 	 *
 	 * rebuild AG Free Inode List, AG Free Inode Extent List;
 	 */
@@ -2875,7 +2874,7 @@
 			rcx = rc;
 			continue;
 		}
-		iagp = (iag_t *) bp->data;
+		iagp = (struct iag *) bp->data;
 		assert(le32_to_cpu(iagp->iagnum) == i);
 
 		/* leave free iag in the free iag list */
@@ -2910,7 +2909,7 @@
 					rcx = rc;
 					goto nextiag;
 				}
-				hiagp = (iag_t *) hbp->data;
+				hiagp = (struct iag *) hbp->data;
 				hiagp->inofreeback =
 				    le32_to_cpu(iagp->iagnum);
 				iagp->inofreefwd = cpu_to_le32(head);
@@ -2936,7 +2935,7 @@
 					rcx = rc;
 					goto nextiag;
 				}
-				hiagp = (iag_t *) hbp->data;
+				hiagp = (struct iag *) hbp->data;
 				hiagp->extfreeback = iagp->iagnum;
 				iagp->extfreefwd = cpu_to_le32(head);
 				iagp->extfreeback = -1;
@@ -3019,7 +3018,7 @@
  *      0       - success
  *      ENOMEM	- insufficient memory
  */
-static int copy_from_dinode(dinode_t * dip, struct inode *ip)
+static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 
@@ -3072,7 +3071,7 @@
  *
  * FUNCTION:    Copies inode info from in-memory inode to disk inode
  */
-static void copy_to_dinode(dinode_t * dip, struct inode *ip)
+static void copy_to_dinode(struct dinode * dip, struct inode *ip)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 
@@ -3112,7 +3111,7 @@
 /*
  *	DBGdiInit()
  */
-static void *DBGdiInit(imap_t * imap)
+static void *DBGdiInit(struct inomap * imap)
 {
 	u32 *dimap;
 	int size;
@@ -3126,7 +3125,7 @@
 /*
  *	DBGdiAlloc()
  */
-static void DBGdiAlloc(imap_t * imap, ino_t ino)
+static void DBGdiAlloc(struct inomap * imap, ino_t ino)
 {
 	u32 *dimap = imap->im_DBGdimap;
 	int w, b;
@@ -3144,7 +3143,7 @@
 /*
  *	DBGdiFree()
  */
-static void DBGdiFree(imap_t * imap, ino_t ino)
+static void DBGdiFree(struct inomap * imap, ino_t ino)
 {
 	u32 *dimap = imap->im_DBGdimap;
 	int w, b;
@@ -3159,7 +3158,7 @@
 	dimap[w] &= ~m;
 }
 
-static void dump_cp(imap_t * ipimap, char *function, int line)
+static void dump_cp(struct inomap * ipimap, char *function, int line)
 {
 	printk("\n* ********* *\nControl Page %s %d\n", function, line);
 	printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag,
@@ -3173,7 +3172,7 @@
 	       ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree);
 }
 
-static void dump_iag(iag_t * iag, char *function, int line)
+static void dump_iag(struct iag * iag, char *function, int line)
 {
 	printk("\n* ********* *\nIAG %s %d\n", function, line);
 	printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum),
diff -Nru a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h
--- a/fs/jfs/jfs_imap.h	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_imap.h	Sun Sep 15 19:19:29 2002
@@ -59,7 +59,7 @@
 /*
  *	inode allocation group page (per 4096 inodes of an AG)
  */
-typedef struct {
+struct iag {
 	s64 agstart;		/* 8: starting block of ag              */
 	s32 iagnum;		/* 4: inode allocation group number     */
 	s32 inofreefwd;		/* 4: ag inode free list forward        */
@@ -87,22 +87,22 @@
 	u32 wmap[EXTSPERIAG];	/* 512: working allocation map  */
 	u32 pmap[EXTSPERIAG];	/* 512: persistent allocation map */
 	pxd_t inoext[EXTSPERIAG];	/* 1024: inode extent addresses */
-} iag_t;			/* (4096) */
+};				/* (4096) */
 
 /*
  *	per AG control information (in inode map control page)
  */
-typedef struct {
+struct iagctl {
 	s32 inofree;		/* 4: free inode list anchor            */
 	s32 extfree;		/* 4: free extent list anchor           */
 	s32 numinos;		/* 4: number of backed inodes           */
 	s32 numfree;		/* 4: number of free inodes             */
-} iagctl_t;			/* (16) */
+};				/* (16) */
 
 /*
  *	per fileset/aggregate inode map control page
  */
-typedef struct {
+struct dinomap {
 	s32 in_freeiag;		/* 4: free iag list anchor     */
 	s32 in_nextiag;		/* 4: next free iag number     */
 	s32 in_numinos;		/* 4: num of backed inodes */
@@ -112,22 +112,22 @@
 	s32 in_diskblock;	/* 4: for standalone test driver  */
 	s32 in_maxag;		/* 4: for standalone test driver  */
 	u8 pad[2016];		/* 2016: pad to 2048 */
-	iagctl_t in_agctl[MAXAG];	/* 2048: AG control information */
-} dinomap_t;			/* (4096) */
+	struct iagctl in_agctl[MAXAG];	/* 2048: AG control information */
+};				/* (4096) */
 
 
 /*
  *	In-core inode map control page
  */
-typedef struct inomap {
-	dinomap_t im_imap;	/* 4096: inode allocation control */
+struct inomap {
+	struct dinomap im_imap;		/* 4096: inode allocation control */
 	struct inode *im_ipimap;	/* 4: ptr to inode for imap   */
 	struct semaphore im_freelock;	/* 4: iag free list lock      */
 	struct semaphore im_aglock[MAXAG];	/* 512: per AG locks          */
 	u32 *im_DBGdimap;
 	atomic_t im_numinos;	/* num of backed inodes */
 	atomic_t im_numfree;	/* num of free backed inodes */
-} imap_t;
+};
 
 #define	im_freeiag	im_imap.in_freeiag
 #define	im_nextiag	im_imap.in_nextiag
@@ -145,7 +145,7 @@
 extern int diSync(struct inode *);
 /* external references */
 extern int diUpdatePMap(struct inode *ipimap, unsigned long inum,
-			boolean_t is_free, tblock_t * tblk);
+			boolean_t is_free, struct tblock * tblk);
 extern int diExtendFS(struct inode *ipimap, struct inode *ipbmap);
 extern int diMount(struct inode *);
 extern int diUnmount(struct inode *, int);
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/jfs_incore.h	Sun Sep 15 19:19:28 2002
@@ -75,7 +75,7 @@
 			struct inomap *_imap;	/* 4: inode map header	*/
 		} file;
 		struct {
-			dir_table_slot_t _table[12]; /* 96: directory index */
+			struct dir_table_slot _table[12]; /* 96: dir index */
 			dtroot_t _dtroot;	/* 288: dtree root */
 		} dir;
 		struct {
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Sun Sep 15 19:19:46 2002
+++ b/fs/jfs/jfs_logmgr.c	Sun Sep 15 19:19:46 2002
@@ -76,7 +76,7 @@
 /*
  * lbuf's ready to be redriven.  Protected by log_redrive_lock (jfsIO thread)
  */
-static lbuf_t *log_redrive_list;
+static struct lbuf *log_redrive_list;
 static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED;
 DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait);
 
@@ -160,32 +160,32 @@
 /*
  * external references
  */
-extern void txLazyUnlock(tblock_t * tblk);
+extern void txLazyUnlock(struct tblock * tblk);
 extern int jfs_stop_threads;
 extern struct completion jfsIOwait;
 
 /*
  * forward references
  */
-static int lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd,
-			 tlock_t * tlck);
+static int lmWriteRecord(struct jfs_log * log, struct tblock * tblk,
+			 struct lrd * lrd, struct tlock * tlck);
 
-static int lmNextPage(log_t * log);
-static int lmLogFileSystem(log_t * log, char *uuid, int activate);
+static int lmNextPage(struct jfs_log * log);
+static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate);
 
-static int lbmLogInit(log_t * log);
-static void lbmLogShutdown(log_t * log);
-static lbuf_t *lbmAllocate(log_t * log, int);
-static void lbmFree(lbuf_t * bp);
-static void lbmfree(lbuf_t * bp);
-static int lbmRead(log_t * log, int pn, lbuf_t ** bpp);
-static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block);
-static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag);
-static int lbmIOWait(lbuf_t * bp, int flag);
+static int lbmLogInit(struct jfs_log * log);
+static void lbmLogShutdown(struct jfs_log * log);
+static struct lbuf *lbmAllocate(struct jfs_log * log, int);
+static void lbmFree(struct lbuf * bp);
+static void lbmfree(struct lbuf * bp);
+static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp);
+static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag, int cant_block);
+static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
+static int lbmIOWait(struct lbuf * bp, int flag);
 static bio_end_io_t lbmIODone;
 
-void lbmStartIO(lbuf_t * bp);
-void lmGCwrite(log_t * log, int cant_block);
+void lbmStartIO(struct lbuf * bp);
+void lmGCwrite(struct jfs_log * log, int cant_block);
 
 
 /*
@@ -212,11 +212,12 @@
  *
  * note: todo: log error handler
  */
-int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck)
 {
 	int lsn;
 	int diffp, difft;
-	metapage_t *mp = NULL;
+	struct metapage *mp = NULL;
 
 	jFYI(1, ("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p\n",
 		 log, tblk, lrd, tlck));
@@ -330,11 +331,12 @@
  * serialization: LOG_LOCK() held on entry/exit
  */
 static int
-lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	      struct tlock * tlck)
 {
 	int lsn = 0;		/* end-of-log address */
-	lbuf_t *bp;		/* dst log page buffer */
-	logpage_t *lp;		/* dst log page */
+	struct lbuf *bp;	/* dst log page buffer */
+	struct logpage *lp;	/* dst log page */
 	caddr_t dst;		/* destination address in log page */
 	int dstoffset;		/* end-of-log offset in log page */
 	int freespace;		/* free space in log page */
@@ -344,16 +346,16 @@
 	int nbytes;		/* number of bytes to move */
 	int i;
 	int len;
-	linelock_t *linelock;
-	lv_t *lv;
-	lvd_t *lvd;
+	struct linelock *linelock;
+	struct lv *lv;
+	struct lvd *lvd;
 	int l2linesize;
 
 	len = 0;
 
 	/* retrieve destination log page to write */
-	bp = (lbuf_t *) log->bp;
-	lp = (logpage_t *) bp->l_ldata;
+	bp = (struct lbuf *) log->bp;
+	lp = (struct logpage *) bp->l_ldata;
 	dstoffset = log->eor;
 
 	/* any log data to write ? */
@@ -366,7 +368,7 @@
 	/* retrieve source meta-data page to log */
 	if (tlck->flag & tlckPAGELOCK) {
 		p = (caddr_t) (tlck->mp->data);
-		linelock = (linelock_t *) & tlck->lock;
+		linelock = (struct linelock *) & tlck->lock;
 	}
 	/* retrieve source in-memory inode to log */
 	else if (tlck->flag & tlckINODELOCK) {
@@ -374,14 +376,14 @@
 			p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
 		else
 			p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
-		linelock = (linelock_t *) & tlck->lock;
+		linelock = (struct linelock *) & tlck->lock;
 	}
 #ifdef	_JFS_WIP
 	else if (tlck->flag & tlckINLINELOCK) {
 
-		inlinelock = (inlinelock_t *) & tlck;
+		inlinelock = (struct inlinelock *) & tlck;
 		p = (caddr_t) & inlinelock->pxd;
-		linelock = (linelock_t *) & tlck;
+		linelock = (struct linelock *) & tlck;
 	}
 #endif				/* _JFS_WIP */
 	else {
@@ -393,7 +395,7 @@
       moveData:
 	ASSERT(linelock->index <= linelock->maxcnt);
 
-	lv = (lv_t *) & linelock->lv;
+	lv = linelock->lv;
 	for (i = 0; i < linelock->index; i++, lv++) {
 		if (lv->length == 0)
 			continue;
@@ -404,7 +406,7 @@
 			lmNextPage(log);
 
 			bp = log->bp;
-			lp = (logpage_t *) bp->l_ldata;
+			lp = (struct logpage *) bp->l_ldata;
 			dstoffset = LOGPHDRSIZE;
 		}
 
@@ -428,8 +430,8 @@
 			/* page become full: move on to next page */
 			lmNextPage(log);
 
-			bp = (lbuf_t *) log->bp;
-			lp = (logpage_t *) bp->l_ldata;
+			bp = (struct lbuf *) log->bp;
+			lp = (struct logpage *) bp->l_ldata;
 			dstoffset = LOGPHDRSIZE;
 
 			srclen -= nbytes;
@@ -440,7 +442,7 @@
 		 * move log vector descriptor
 		 */
 		len += 4;
-		lvd = (lvd_t *) ((caddr_t) lp + dstoffset);
+		lvd = (struct lvd *) ((caddr_t) lp + dstoffset);
 		lvd->offset = cpu_to_le16(lv->offset);
 		lvd->length = cpu_to_le16(lv->length);
 		dstoffset += 4;
@@ -450,7 +452,7 @@
 	}
 
 	if ((i = linelock->next)) {
-		linelock = (linelock_t *) lid_to_tlock(i);
+		linelock = (struct linelock *) lid_to_tlock(i);
 		goto moveData;
 	}
 
@@ -534,8 +536,8 @@
 		/* page become full: move on to next page */
 		lmNextPage(log);
 
-		bp = (lbuf_t *) log->bp;
-		lp = (logpage_t *) bp->l_ldata;
+		bp = (struct lbuf *) log->bp;
+		lp = (struct logpage *) bp->l_ldata;
 		dstoffset = LOGPHDRSIZE;
 		src += nbytes;
 	}
@@ -555,21 +557,21 @@
  *			
  * serialization: LOG_LOCK() held on entry/exit
  */
-static int lmNextPage(log_t * log)
+static int lmNextPage(struct jfs_log * log)
 {
-	logpage_t *lp;
+	struct logpage *lp;
 	int lspn;		/* log sequence page number */
 	int pn;			/* current page number */
-	lbuf_t *bp;
-	lbuf_t *nextbp;
-	tblock_t *tblk;
+	struct lbuf *bp;
+	struct lbuf *nextbp;
+	struct tblock *tblk;
 
 	jFYI(1, ("lmNextPage\n"));
 
 	/* get current log page number and log sequence page number */
 	pn = log->page;
 	bp = log->bp;
-	lp = (logpage_t *) bp->l_ldata;
+	lp = (struct logpage *) bp->l_ldata;
 	lspn = le32_to_cpu(lp->h.page);
 
 	LOGGC_LOCK(log);
@@ -637,7 +639,7 @@
 	log->bp = nextbp;
 
 	/* initialize next log page */
-	lp = (logpage_t *) nextbp->l_ldata;
+	lp = (struct logpage *) nextbp->l_ldata;
 	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
 	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
 
@@ -661,7 +663,7 @@
  *	transaction blocks on the commit queue.
  *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
  */
-int lmGroupCommit(log_t * log, tblock_t * tblk)
+int lmGroupCommit(struct jfs_log * log, struct tblock * tblk)
 {
 	int rc = 0;
 
@@ -738,13 +740,13 @@
  *	LOGGC_LOCK must be held by caller.
  *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
  */
-void lmGCwrite(log_t * log, int cant_write)
+void lmGCwrite(struct jfs_log * log, int cant_write)
 {
-	lbuf_t *bp;
-	logpage_t *lp;
+	struct lbuf *bp;
+	struct logpage *lp;
 	int gcpn;		/* group commit page number */
-	tblock_t *tblk;
-	tblock_t *xtblk;
+	struct tblock *tblk;
+	struct tblock *xtblk;
 
 	/*
 	 * build the commit group of a log page
@@ -768,8 +770,8 @@
 	/*
 	 * pageout to commit transactions on the log page.
 	 */
-	bp = (lbuf_t *) tblk->bp;
-	lp = (logpage_t *) bp->l_ldata;
+	bp = (struct lbuf *) tblk->bp;
+	lp = (struct logpage *) bp->l_ldata;
 	/* is page already full ? */
 	if (tblk->flag & tblkGC_EOP) {
 		/* mark page to free at end of group commit of the page */
@@ -806,12 +808,12 @@
  * NOTE:
  *	This routine is called a interrupt time by lbmIODone
  */
-void lmPostGC(lbuf_t * bp)
+void lmPostGC(struct lbuf * bp)
 {
 	unsigned long flags;
-	log_t *log = bp->l_log;
-	logpage_t *lp;
-	tblock_t *tblk;
+	struct jfs_log *log = bp->l_log;
+	struct logpage *lp;
+	struct tblock *tblk;
 
 	//LOGGC_LOCK(log);
 	spin_lock_irqsave(&log->gclock, flags);
@@ -866,7 +868,7 @@
 		 */
 		else if (tblk->flag & tblkGC_EOP) {
 			/* finalize the page */
-			lp = (logpage_t *) bp->l_ldata;
+			lp = (struct logpage *) bp->l_ldata;
 			bp->l_ceor = bp->l_eor;
 			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
 			jEVENT(0, ("lmPostGC: calling lbmWrite\n"));
@@ -921,14 +923,14 @@
  *			
  * serialization: LOG_LOCK() held on entry/exit
  */
-int lmLogSync(log_t * log, int nosyncwait)
+int lmLogSync(struct jfs_log * log, int nosyncwait)
 {
 	int logsize;
 	int written;		/* written since last syncpt */
 	int free;		/* free space left available */
 	int delta;		/* additional delta to write normally */
 	int more;		/* additional write granted */
-	lrd_t lrd;
+	struct lrd lrd;
 	int lsn;
 	struct logsyncblk *lp;
 
@@ -1056,15 +1058,15 @@
  *
  * serialization:
  */
-int lmLogOpen(struct super_block *sb, log_t ** logptr)
+int lmLogOpen(struct super_block *sb, struct jfs_log ** logptr)
 {
 	int rc;
 	struct block_device *bdev;
-	log_t *log;
+	struct jfs_log *log;
 
-	if (!(log = kmalloc(sizeof(log_t), GFP_KERNEL)))
+	if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL)))
 		return ENOMEM;
-	memset(log, 0, sizeof(log_t));
+	memset(log, 0, sizeof(struct jfs_log));
 	init_waitqueue_head(&log->syncwait);
 
 	log->sb = sb;		/* This should be a list */
@@ -1173,14 +1175,14 @@
  *			
  * serialization: single first open thread
  */
-int lmLogInit(log_t * log)
+int lmLogInit(struct jfs_log * log)
 {
 	int rc = 0;
-	lrd_t lrd;
-	logsuper_t *logsuper;
-	lbuf_t *bpsuper;
-	lbuf_t *bp;
-	logpage_t *lp;
+	struct lrd lrd;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
+	struct lbuf *bp;
+	struct logpage *lp;
 	int lsn;
 
 	jFYI(1, ("lmLogInit: log:0x%p\n", log));
@@ -1206,7 +1208,7 @@
 	if ((rc = lbmRead(log, 1, &bpsuper)))
 		goto errout10;
 
-	logsuper = (logsuper_t *) bpsuper->l_ldata;
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
 
 	if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
 		jERROR(1, ("*** Log Format Error ! ***\n"));
@@ -1252,7 +1254,7 @@
 	if ((rc = lbmRead(log, log->page, &bp)))
 		goto errout20;
 
-	lp = (logpage_t *) bp->l_ldata;
+	lp = (struct logpage *) bp->l_ldata;
 
 	jFYI(1, ("lmLogInit: lsn:0x%x page:%d eor:%d:%d\n",
 		 le32_to_cpu(logsuper->end), log->page, log->eor,
@@ -1291,7 +1293,7 @@
 	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
 	bp = log->bp;
 	bp->l_ceor = bp->l_eor;
-	lp = (logpage_t *) bp->l_ldata;
+	lp = (struct logpage *) bp->l_ldata;
 	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
 	lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0);
 	if ((rc = lbmIOWait(bp, 0)))
@@ -1363,7 +1365,7 @@
  *
  * serialization:
  */
-int lmLogClose(struct super_block *sb, log_t * log)
+int lmLogClose(struct super_block *sb, struct jfs_log * log)
 {
 	struct block_device *bdev = log->bdev;
 	int rc;
@@ -1400,7 +1402,7 @@
  *
  * FUNCTION:	wait for all outstanding log records to be written to disk
  */
-void lmLogWait(log_t *log)
+void lmLogWait(struct jfs_log *log)
 {
 	int i;
 
@@ -1438,15 +1440,15 @@
  *			
  * serialization: single last close thread
  */
-int lmLogShutdown(log_t * log)
+int lmLogShutdown(struct jfs_log * log)
 {
 	int rc;
-	lrd_t lrd;
+	struct lrd lrd;
 	int lsn;
-	logsuper_t *logsuper;
-	lbuf_t *bpsuper;
-	lbuf_t *bp;
-	logpage_t *lp;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
+	struct lbuf *bp;
+	struct logpage *lp;
 
 	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
 
@@ -1469,7 +1471,7 @@
 	lrd.log.syncpt.sync = 0;
 	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
 	bp = log->bp;
-	lp = (logpage_t *) bp->l_ldata;
+	lp = (struct logpage *) bp->l_ldata;
 	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
 	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
 	lbmIOWait(log->bp, lbmFREE);
@@ -1482,7 +1484,7 @@
 	if ((rc = lbmRead(log, 1, &bpsuper)))
 		goto out;
 
-	logsuper = (logsuper_t *) bpsuper->l_ldata;
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
 	logsuper->state = cpu_to_le32(LOGREDONE);
 	logsuper->end = cpu_to_le32(lsn);
 	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
@@ -1518,12 +1520,12 @@
  * RETURN:	0	- success
  *		errors returned by vms_iowait().
  */
-static int lmLogFileSystem(log_t * log, char *uuid, int activate)
+static int lmLogFileSystem(struct jfs_log * log, char *uuid, int activate)
 {
 	int rc = 0;
 	int i;
-	logsuper_t *logsuper;
-	lbuf_t *bpsuper;
+	struct logsuper *logsuper;
+	struct lbuf *bpsuper;
 
 	/*
 	 * insert/remove file system device to log active file system list.
@@ -1531,7 +1533,7 @@
 	if ((rc = lbmRead(log, 1, &bpsuper)))
 		return rc;
 
-	logsuper = (logsuper_t *) bpsuper->l_ldata;
+	logsuper = (struct logsuper *) bpsuper->l_ldata;
 	if (activate) {
 		for (i = 0; i < MAX_ACTIVE; i++)
 			if (!memcmp(logsuper->active[i].uuid, NULL_UUID, 16)) {
@@ -1589,10 +1591,10 @@
  *
  * initialize per log I/O setup at lmLogInit()
  */
-static int lbmLogInit(log_t * log)
+static int lbmLogInit(struct jfs_log * log)
 {				/* log inode */
 	int i;
-	lbuf_t *lbuf;
+	struct lbuf *lbuf;
 
 	jFYI(1, ("lbmLogInit: log:0x%p\n", log));
 
@@ -1616,7 +1618,7 @@
 	log->lbuf_free = NULL;
 
 	for (i = 0; i < LOGPAGES; i++) {
-		lbuf = kmalloc(sizeof(lbuf_t), GFP_KERNEL);
+		lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
 		if (lbuf == 0)
 			goto error;
 		lbuf->l_ldata = (char *) __get_free_page(GFP_KERNEL);
@@ -1644,15 +1646,15 @@
  *
  * finalize per log I/O setup at lmLogShutdown()
  */
-static void lbmLogShutdown(log_t * log)
+static void lbmLogShutdown(struct jfs_log * log)
 {
-	lbuf_t *lbuf;
+	struct lbuf *lbuf;
 
 	jFYI(1, ("lbmLogShutdown: log:0x%p\n", log));
 
 	lbuf = log->lbuf_free;
 	while (lbuf) {
-		lbuf_t *next = lbuf->l_freelist;
+		struct lbuf *next = lbuf->l_freelist;
 		free_page((unsigned long) lbuf->l_ldata);
 		kfree(lbuf);
 		lbuf = next;
@@ -1667,9 +1669,9 @@
  *
  * allocate an empty log buffer
  */
-static lbuf_t *lbmAllocate(log_t * log, int pn)
+static struct lbuf *lbmAllocate(struct jfs_log * log, int pn)
 {
-	lbuf_t *bp;
+	struct lbuf *bp;
 	unsigned long flags;
 
 	/*
@@ -1698,7 +1700,7 @@
  *
  * release a log buffer to freelist
  */
-static void lbmFree(lbuf_t * bp)
+static void lbmFree(struct lbuf * bp)
 {
 	unsigned long flags;
 
@@ -1709,9 +1711,9 @@
 	LCACHE_UNLOCK(flags);
 }
 
-static void lbmfree(lbuf_t * bp)
+static void lbmfree(struct lbuf * bp)
 {
-	log_t *log = bp->l_log;
+	struct jfs_log *log = bp->l_log;
 
 	assert(bp->l_wqnext == NULL);
 
@@ -1737,7 +1739,7 @@
  * NOTES:
  *	Takes log_redrive_lock.
  */
-static inline void lbmRedrive(lbuf_t *bp)
+static inline void lbmRedrive(struct lbuf *bp)
 {
 	unsigned long flags;
 
@@ -1753,10 +1755,10 @@
 /*
  *	lbmRead()
  */
-static int lbmRead(log_t * log, int pn, lbuf_t ** bpp)
+static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
 {
 	struct bio *bio;
-	lbuf_t *bp;
+	struct lbuf *bp;
 
 	/*
 	 * allocate a log buffer
@@ -1804,9 +1806,10 @@
  * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit().
  * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone()
  */
-static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block)
+static void lbmWrite(struct jfs_log * log, struct lbuf * bp, int flag,
+		     int cant_block)
 {
-	lbuf_t *tail;
+	struct lbuf *tail;
 	unsigned long flags;
 
 	jFYI(1, ("lbmWrite: bp:0x%p flag:0x%x pn:0x%x\n",
@@ -1872,7 +1875,7 @@
  * initiate pageout bypassing write queue for sidestream
  * (e.g., log superblock) write;
  */
-static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag)
+static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
 {
 	jEVENT(0, ("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x\n",
 		   bp, flag, bp->l_pn));
@@ -1902,10 +1905,10 @@
  *
  * serialization: LCACHE_LOCK() is NOT held during log i/o;
  */
-void lbmStartIO(lbuf_t * bp)
+void lbmStartIO(struct lbuf * bp)
 {
 	struct bio *bio;
-	log_t *log = bp->l_log;
+	struct jfs_log *log = bp->l_log;
 
 	jFYI(1, ("lbmStartIO\n"));
 
@@ -1935,7 +1938,7 @@
 /*
  *	lbmIOWait()
  */
-static int lbmIOWait(lbuf_t * bp, int flag)
+static int lbmIOWait(struct lbuf * bp, int flag)
 {
 	unsigned long flags;
 	int rc = 0;
@@ -1968,9 +1971,9 @@
  */
 static void lbmIODone(struct bio *bio)
 {
-	lbuf_t *bp = bio->bi_private;
-	lbuf_t *nextbp, *tail;
-	log_t *log;
+	struct lbuf *bp = bio->bi_private;
+	struct lbuf *nextbp, *tail;
+	struct jfs_log *log;
 	unsigned long flags;
 
 	/*
@@ -2109,7 +2112,7 @@
 
 int jfsIOWait(void *arg)
 {
-	lbuf_t *bp;
+	struct lbuf *bp;
 
 	jFYI(1, ("jfsIOWait is here!\n"));
 
@@ -2167,16 +2170,16 @@
  * XXX: We're synchronously writing one page at a time.  This needs to
  *	be improved by writing multiple pages at once.
  */
-int lmLogFormat(log_t *log, s64 logAddress, int logSize)
+int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize)
 {
 	int rc = -EIO;
 	struct jfs_sb_info *sbi = JFS_SBI(log->sb);
-	logsuper_t *logsuper;
-	logpage_t *lp;
+	struct logsuper *logsuper;
+	struct logpage *lp;
 	int lspn;		/* log sequence page number */
 	struct lrd *lrd_ptr;
 	int npages = 0;
-	lbuf_t *bp;
+	struct lbuf *bp;
 
 	jFYI(0, ("lmLogFormat: logAddress:%Ld logSize:%d\n",
 		 (long long)logAddress, logSize));
@@ -2198,7 +2201,7 @@
 	/*
 	 *      init log superblock: log page 1
 	 */
-	logsuper = (logsuper_t *) bp->l_ldata;
+	logsuper = (struct logsuper *) bp->l_ldata;
 
 	logsuper->magic = cpu_to_le32(LOGMAGIC);
 	logsuper->version = cpu_to_le32(LOGVERSION);
@@ -2237,7 +2240,7 @@
 	 * the succeeding log pages will have ascending order of
 	 * the lspn starting from 0, ... (N-2)
 	 */
-	lp = (logpage_t *) bp->l_ldata;
+	lp = (struct logpage *) bp->l_ldata;
 	/*
 	 * initialize 1st log page to be written: lpsn = N - 1,
 	 * write a SYNCPT log record is written to this page
diff -Nru a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
--- a/fs/jfs/jfs_logmgr.h	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_logmgr.h	Sun Sep 15 19:19:29 2002
@@ -61,7 +61,7 @@
 
 #define MAX_ACTIVE	128	/* Max active file systems sharing log */
 
-typedef struct {
+struct logsuper {
 	u32 magic;		/* 4: log lv identifier */
 	s32 version;		/* 4: version number */
 	s32 serial;		/* 4: log open/mount counter */
@@ -78,7 +78,7 @@
 	struct {
 		char uuid[16];
 	} active[MAX_ACTIVE];	/* 2048: active file systems list */
-} logsuper_t;
+};
 
 #define NULL_UUID "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 
@@ -119,7 +119,7 @@
  * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only) 
  * h.eor != t.eor they were set to the smaller of their two values.
  */
-typedef struct {
+struct logpage {
 	struct {		/* header */
 		s32 page;	/* 4: log sequence page number */
 		s16 rsrvd;	/* 2: */
@@ -133,7 +133,7 @@
 		s16 rsrvd;	/* 2: */
 		s16 eor;	/* 2: normally the same as h.eor */
 	} t;
-} logpage_t;
+};
 
 #define LOGPHDRSIZE	8	/* log page header size */
 #define LOGPTLRSIZE	8	/* log page trailer size */
@@ -198,7 +198,7 @@
 #define	LOG_FREEPXD		0x0001
 
 
-typedef struct lrd {
+struct lrd {
 	/*
 	 * type independent area
 	 */
@@ -349,23 +349,23 @@
 		 * no type-dependent information
 		 */
 	} log;
-} lrd_t;			/* (36) */
+};					/* (36) */
 
 #define	LOGRDSIZE	(sizeof(struct lrd))
 
 /*
  *	line vector descriptor
  */
-typedef struct {
+struct lvd {
 	s16 offset;
 	s16 length;
-} lvd_t;
+};
 
 
 /*
  *	log logical volume
  */
-typedef struct jfs_log {
+struct jfs_log {
 
 	struct super_block *sb;	/* 4: This is used to sync metadata
 				 *    before writing syncpt.  Will
@@ -416,7 +416,7 @@
 	struct lbuf *wqueue;	/* 4: log pageout queue */
 	int count;		/* 4: count */
 	char uuid[16];		/* 16: 128-bit uuid of log device */
-} log_t;
+};
 
 /*
  * Log flag
@@ -428,10 +428,10 @@
 /*
  * group commit flag
  */
-/* log_t */
+/* jfs_log */
 #define logGC_PAGEOUT	0x00000001
 
-/* tblock_t/lbuf_t */
+/* tblock/lbuf */
 #define tblkGC_QUEUE		0x0001
 #define tblkGC_READY		0x0002
 #define tblkGC_COMMIT		0x0004
@@ -446,8 +446,8 @@
 /*
  *		log cache buffer header
  */
-typedef struct lbuf {
-	log_t *l_log;		/* 4: log associated with buffer */
+struct lbuf {
+	struct jfs_log *l_log;	/* 4: log associated with buffer */
 
 	/*
 	 * data buffer base area
@@ -466,7 +466,7 @@
 
 	wait_queue_head_t l_ioevent;	/* 4: i/o done event */
 	struct page *l_page;	/* The page itself */
-} lbuf_t;
+};
 
 /* Reuse l_freelist for redrive list */
 #define l_redrive_next l_freelist
@@ -474,15 +474,15 @@
 /*
  *	logsynclist block
  *
- * common logsyncblk prefix for jbuf_t and tblock_t
+ * common logsyncblk prefix for jbuf_t and tblock
  */
-typedef struct logsyncblk {
+struct logsyncblk {
 	u16 xflag;		/* flags */
-	u16 flag;		/* only meaninful in tblock_t */
+	u16 flag;		/* only meaninful in tblock */
 	lid_t lid;		/* lock id */
 	s32 lsn;		/* log sequence number */
 	struct list_head synclist;	/* log sync list link */
-} logsyncblk_t;
+};
 
 /*
  *	logsynclist serialization (per log)
@@ -500,12 +500,12 @@
 		diff += (log)->logsize;\
 }
 
-extern int lmLogOpen(struct super_block *sb, log_t ** log);
-extern void lmLogWait(log_t * log);
-extern int lmLogClose(struct super_block *sb, log_t * log);
-extern int lmLogSync(log_t * log, int nosyncwait);
-extern int lmLogShutdown(log_t * log);
-extern int lmLogInit(log_t * log);
-extern int lmLogFormat(log_t *log, s64 logAddress, int logSize);
+extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log);
+extern void lmLogWait(struct jfs_log * log);
+extern int lmLogClose(struct super_block *sb, struct jfs_log * log);
+extern int lmLogSync(struct jfs_log * log, int nosyncwait);
+extern int lmLogShutdown(struct jfs_log * log);
+extern int lmLogInit(struct jfs_log * log);
+extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
 
 #endif				/* _H_JFS_LOGMGR */
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_metapage.c	Sun Sep 15 19:19:29 2002
@@ -40,7 +40,7 @@
 
 #define HASH_BITS 10		/* This makes hash_table 1 4K page */
 #define HASH_SIZE (1 << HASH_BITS)
-static metapage_t **hash_table = NULL;
+static struct metapage **hash_table = NULL;
 static unsigned long hash_order;
 
 
@@ -92,7 +92,7 @@
 
 static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
 {
-	metapage_t *mp = (metapage_t *)foo;
+	struct metapage *mp = (struct metapage *)foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
@@ -107,12 +107,12 @@
 	}
 }
 
-static inline metapage_t *alloc_metapage(int no_wait)
+static inline struct metapage *alloc_metapage(int no_wait)
 {
 	return mempool_alloc(metapage_mempool, no_wait ? GFP_ATOMIC : GFP_NOFS);
 }
 
-static inline void free_metapage(metapage_t *mp)
+static inline void free_metapage(struct metapage *mp)
 {
 	mp->flag = 0;
 	set_bit(META_free, &mp->flag);
@@ -134,8 +134,8 @@
 	/*
 	 * Allocate the metapage structures
 	 */
-	metapage_cache = kmem_cache_create("jfs_mp", sizeof(metapage_t), 0, 0,
-					   init_once, NULL);
+	metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),
+					   0, 0, init_once, NULL);
 	if (metapage_cache == NULL)
 		return -ENOMEM;
 
@@ -153,7 +153,7 @@
 	     ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE;
 	     hash_order++);
 	hash_table =
-	    (metapage_t **) __get_free_pages(GFP_KERNEL, hash_order);
+	    (struct metapage **) __get_free_pages(GFP_KERNEL, hash_order);
 	assert(hash_table);
 	memset(hash_table, 0, PAGE_SIZE << hash_order);
 
@@ -169,8 +169,8 @@
 /*
  * Basically same hash as in pagemap.h, but using our hash table
  */
-static metapage_t **meta_hash(struct address_space *mapping,
-			      unsigned long index)
+static struct metapage **meta_hash(struct address_space *mapping,
+				   unsigned long index)
 {
 #define i (((unsigned long)mapping)/ \
 	   (sizeof(struct inode) & ~(sizeof(struct inode) -1 )))
@@ -180,11 +180,11 @@
 #undef s
 }
 
-static metapage_t *search_hash(metapage_t ** hash_ptr,
-			       struct address_space *mapping,
+static struct metapage *search_hash(struct metapage ** hash_ptr,
+				    struct address_space *mapping,
 			       unsigned long index)
 {
-	metapage_t *ptr;
+	struct metapage *ptr;
 
 	for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) {
 		if ((ptr->mapping == mapping) && (ptr->index == index))
@@ -194,7 +194,7 @@
 	return NULL;
 }
 
-static void add_to_hash(metapage_t * mp, metapage_t ** hash_ptr)
+static void add_to_hash(struct metapage * mp, struct metapage ** hash_ptr)
 {
 	if (*hash_ptr)
 		(*hash_ptr)->hash_prev = mp;
@@ -204,7 +204,7 @@
 	*hash_ptr = mp;
 }
 
-static void remove_from_hash(metapage_t * mp, metapage_t ** hash_ptr)
+static void remove_from_hash(struct metapage * mp, struct metapage ** hash_ptr)
 {
 	if (mp->hash_prev)
 		mp->hash_prev->hash_next = mp->hash_next;
@@ -217,15 +217,15 @@
 		mp->hash_next->hash_prev = mp->hash_prev;
 }
 
-metapage_t *__get_metapage(struct inode *inode,
-			   unsigned long lblock, unsigned int size,
-			   int absolute, unsigned long new)
+struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
+				unsigned int size, int absolute,
+				unsigned long new)
 {
-	metapage_t **hash_ptr;
+	struct metapage **hash_ptr;
 	int l2BlocksPerPage;
 	int l2bsize;
 	struct address_space *mapping;
-	metapage_t *mp;
+	struct metapage *mp;
 	unsigned long page_index;
 	unsigned long page_offset;
 
@@ -289,7 +289,7 @@
 			}
 		}
 		if (!mp) {
-			metapage_t *mp2;
+			struct metapage *mp2;
 
 			spin_unlock(&meta_lock);
 			mp =  mempool_alloc(metapage_mempool, GFP_NOFS);
@@ -358,7 +358,7 @@
 	return NULL;
 }
 
-void hold_metapage(metapage_t * mp, int force)
+void hold_metapage(struct metapage * mp, int force)
 {
 	spin_lock(&meta_lock);
 
@@ -374,7 +374,7 @@
 	spin_unlock(&meta_lock);
 }
 
-static void __write_metapage(metapage_t * mp)
+static void __write_metapage(struct metapage * mp)
 {
 	int l2bsize = mp->mapping->host->i_blkbits;
 	int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
@@ -420,7 +420,7 @@
 	jFYI(1, ("__write_metapage done\n"));
 }
 
-static inline void sync_metapage(metapage_t *mp)
+static inline void sync_metapage(struct metapage *mp)
 {
 	struct page *page = mp->page;
 
@@ -435,9 +435,9 @@
 	page_cache_release(page);
 }
 
-void release_metapage(metapage_t * mp)
+void release_metapage(struct metapage * mp)
 {
-	log_t *log;
+	struct jfs_log *log;
 
 	jFYI(1,
 	     ("release_metapage: mp = 0x%p, flag = 0x%lx\n", mp,
@@ -502,11 +502,11 @@
 
 void __invalidate_metapages(struct inode *ip, s64 addr, int len)
 {
-	metapage_t **hash_ptr;
+	struct metapage **hash_ptr;
 	unsigned long lblock;
 	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
 	struct address_space *mapping = ip->i_mapping;
-	metapage_t *mp;
+	struct metapage *mp;
 	struct page *page;
 
 	/*
@@ -538,11 +538,11 @@
 void invalidate_inode_metapages(struct inode *inode)
 {
 	struct list_head *ptr;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	spin_lock(&meta_lock);
 	list_for_each(ptr, &JFS_IP(inode)->mp_list) {
-		mp = list_entry(ptr, metapage_t, inode_list);
+		mp = list_entry(ptr, struct metapage, inode_list);
 		clear_bit(META_dirty, &mp->flag);
 		set_bit(META_discard, &mp->flag);
 		kunmap(mp->page);
diff -Nru a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
--- a/fs/jfs/jfs_metapage.h	Sun Sep 15 19:19:51 2002
+++ b/fs/jfs/jfs_metapage.h	Sun Sep 15 19:19:51 2002
@@ -21,7 +21,7 @@
 
 #include <linux/pagemap.h>
 
-typedef struct metapage {
+struct metapage {
 	/* Common logsyncblk prefix (see jfs_logmgr.h) */
 	u16 xflag;
 	u16 unused;
@@ -55,7 +55,7 @@
 	int clsn;
 	atomic_t nohomeok;
 	struct jfs_log *log;
-} metapage_t;
+};
 
 /* metapage flag */
 #define META_locked	0
@@ -69,7 +69,7 @@
 #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
 
 /* function prototypes */
-extern metapage_t *__get_metapage(struct inode *inode,
+extern struct metapage *__get_metapage(struct inode *inode,
 				  unsigned long lblock, unsigned int size,
 				  int absolute, unsigned long new);
 
@@ -79,22 +79,22 @@
 #define get_metapage(inode, lblock, size, absolute)\
 	 __get_metapage(inode, lblock, size, absolute, TRUE)
 
-extern void release_metapage(metapage_t *);
-extern void hold_metapage(metapage_t *, int);
+extern void release_metapage(struct metapage *);
+extern void hold_metapage(struct metapage *, int);
 
-static inline void write_metapage(metapage_t *mp)
+static inline void write_metapage(struct metapage *mp)
 {
 	set_bit(META_dirty, &mp->flag);
 	release_metapage(mp);
 }
 
-static inline void flush_metapage(metapage_t *mp)
+static inline void flush_metapage(struct metapage *mp)
 {
 	set_bit(META_sync, &mp->flag);
 	write_metapage(mp);
 }
 
-static inline void discard_metapage(metapage_t *mp)
+static inline void discard_metapage(struct metapage *mp)
 {
 	clear_bit(META_dirty, &mp->flag);
 	set_bit(META_discard, &mp->flag);
diff -Nru a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
--- a/fs/jfs/jfs_mount.c	Sun Sep 15 19:19:29 2002
+++ b/fs/jfs/jfs_mount.c	Sun Sep 15 19:19:29 2002
@@ -249,7 +249,7 @@
 int jfs_mount_rw(struct super_block *sb, int remount)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);  
-	log_t *log;
+	struct jfs_log *log;
 	int rc;
 
 	/*
@@ -506,8 +506,8 @@
  */
 static int logMOUNT(struct super_block *sb)
 {
-	log_t *log = JFS_SBI(sb)->log;
-	lrd_t lrd;
+	struct jfs_log *log = JFS_SBI(sb)->log;
+	struct lrd lrd;
 
 	lrd.logtid = 0;
 	lrd.backchain = 0;
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Sun Sep 15 19:19:52 2002
+++ b/fs/jfs/jfs_txnmgr.c	Sun Sep 15 19:19:52 2002
@@ -61,18 +61,18 @@
  */
 static struct {
 	/* tblock */
-	int freetid;		/* 4: index of a free tid structure */
-	wait_queue_head_t freewait;	/* 4: eventlist of free tblock */
+	int freetid;		/* index of a free tid structure */
+	wait_queue_head_t freewait;	/* eventlist of free tblock */
 
 	/* tlock */
-	int freelock;		/* 4: index first free lock word */
-	wait_queue_head_t freelockwait;	/* 4: eventlist of free tlock */
-	wait_queue_head_t lowlockwait;	/* 4: eventlist of ample tlocks */
-	int tlocksInUse;	/* 4: Number of tlocks in use */
-	spinlock_t LazyLock;	/* 4: synchronize sync_queue & unlock_queue */
-/*	tblock_t *sync_queue;	 * 4: Transactions waiting for data sync */
-	tblock_t *unlock_queue;	/* 4: Transactions waiting to be released */
-	tblock_t *unlock_tail;	/* 4: Tail of unlock_queue */
+	int freelock;		/* index first free lock word */
+	wait_queue_head_t freelockwait;	/* eventlist of free tlock */
+	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */
+	int tlocksInUse;	/* Number of tlocks in use */
+	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue */
+/*	struct tblock *sync_queue; * Transactions waiting for data sync */
+	struct tblock *unlock_queue;	/* Txns waiting to be released */
+	struct tblock *unlock_tail;	/* Tail of unlock_queue */
 	struct list_head anon_list;	/* inodes having anonymous txns */
 	struct list_head anon_list2;	/* inodes having anonymous txns
 					   that couldn't be sync'ed */
@@ -142,8 +142,8 @@
 /*
  * external references
  */
-extern int lmGroupCommit(log_t * log, tblock_t * tblk);
-extern void lmSync(log_t *);
+extern int lmGroupCommit(struct jfs_log * log, struct tblock * tblk);
+extern void lmSync(struct jfs_log *);
 extern int jfs_commit_inode(struct inode *, int);
 extern int jfs_stop_threads;
 
@@ -153,22 +153,27 @@
 /*
  * forward references
  */
-int diLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck,
-	  commit_t * cd);
-int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
-void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
-void inlineLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
-void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
-void txAbortCommit(commit_t * cd, int exval);
-static void txAllocPMap(struct inode *ip, maplock_t * maplock,
-			tblock_t * tblk);
-void txForce(tblock_t * tblk);
-static int txLog(log_t * log, tblock_t * tblk, commit_t * cd);
+int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck, struct commit * cd);
+int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck);
+void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck);
+void inlineLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	       struct tlock * tlck);
+void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck);
+void txAbortCommit(struct commit * cd, int exval);
+static void txAllocPMap(struct inode *ip, struct maplock * maplock,
+			struct tblock * tblk);
+void txForce(struct tblock * tblk);
+static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd);
 int txMoreLock(void);
-static void txUpdateMap(tblock_t * tblk);
-static void txRelease(tblock_t * tblk);
-void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
-static void LogSyncRelease(metapage_t * mp);
+static void txUpdateMap(struct tblock * tblk);
+static void txRelease(struct tblock * tblk);
+void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck);
+static void LogSyncRelease(struct metapage * mp);
 
 /*
  *              transaction block/lock management
@@ -229,8 +234,8 @@
 	 * transaction id (tid) = tblock index
 	 * tid = 0 is reserved.
 	 */
-	size = sizeof(tblock_t) * nTxBlock;
-	TxBlock = (tblock_t *) vmalloc(size);
+	size = sizeof(struct tblock) * nTxBlock;
+	TxBlock = (struct tblock *) vmalloc(size);
 	if (TxBlock == NULL)
 		return ENOMEM;
 
@@ -254,8 +259,8 @@
 	 * transaction lock id = tlock index
 	 * tlock id = 0 is reserved.
 	 */
-	size = sizeof(tlock_t) * nTxLock;
-	TxLock = (tlock_t *) vmalloc(size);
+	size = sizeof(struct tlock) * nTxLock;
+	TxLock = (struct tlock *) vmalloc(size);
 	if (TxLock == NULL) {
 		vfree(TxBlock);
 		return ENOMEM;
@@ -308,11 +313,11 @@
 tid_t txBegin(struct super_block *sb, int flag)
 {
 	tid_t t;
-	tblock_t *tblk;
-	log_t *log;
+	struct tblock *tblk;
+	struct jfs_log *log;
 
 	jFYI(1, ("txBegin: flag = 0x%x\n", flag));
-	log = (log_t *) JFS_SBI(sb)->log;
+	log = JFS_SBI(sb)->log;
 
 	TXN_LOCK();
 
@@ -367,7 +372,7 @@
 	 * We can't zero the whole thing or we screw up another thread being
 	 * awakened after sleeping on tblk->waitor
 	 *
-	 * memset(tblk, 0, sizeof(tblock_t));
+	 * memset(tblk, 0, sizeof(struct tblock));
 	 */
 	tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
 
@@ -401,9 +406,9 @@
  */
 void txBeginAnon(struct super_block *sb)
 {
-	log_t *log;
+	struct jfs_log *log;
 
-	log = (log_t *) JFS_SBI(sb)->log;
+	log = JFS_SBI(sb)->log;
 
 	TXN_LOCK();
 
@@ -439,8 +444,8 @@
  */
 void txEnd(tid_t tid)
 {
-	tblock_t *tblk = tid_to_tblock(tid);
-	log_t *log;
+	struct tblock *tblk = tid_to_tblock(tid);
+	struct jfs_log *log;
 
 	jFYI(1, ("txEnd: tid = %d\n", tid));
 	TXN_LOCK();
@@ -451,7 +456,7 @@
 	 */
 	TXN_WAKEUP(&tblk->waitor);
 
-	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	log = JFS_SBI(tblk->sb)->log;
 
 	/*
 	 * Lazy commit thread can't free this guy until we mark it UNLOCKED,
@@ -525,17 +530,18 @@
  *
  * serialization:
  */
-tlock_t *txLock(tid_t tid, struct inode *ip, metapage_t * mp, int type)
+struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp,
+		     int type)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	int dir_xtree = 0;
 	lid_t lid;
 	tid_t xtid;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
-	linelock_t *linelock;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+	struct linelock *linelock;
 	xtpage_t *p;
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	TXN_LOCK();
 
@@ -695,7 +701,7 @@
 	}
 
 	/* initialize type dependent area for linelock */
-	linelock = (linelock_t *) & tlck->lock;
+	linelock = (struct linelock *) & tlck->lock;
 	linelock->next = 0;
 	linelock->flag = tlckLINELOCK;
 	linelock->maxcnt = TLOCKSHORT;
@@ -709,7 +715,7 @@
 	case tlckXTREE:
 		linelock->l2linesize = L2XTSLOTSIZE;
 
-		xtlck = (xtlock_t *) linelock;
+		xtlck = (struct xtlock *) linelock;
 		xtlck->header.offset = 0;
 		xtlck->header.length = 2;
 
@@ -761,10 +767,10 @@
 	if (jfs_ip->fileset != AGGREGATE_I) {
 		jERROR(1, ("txLock: trying to lock locked page!\n"));
 		dump_mem("ip", ip, sizeof(struct inode));
-		dump_mem("mp", mp, sizeof(metapage_t));
+		dump_mem("mp", mp, sizeof(struct metapage));
 		dump_mem("Locker's tblk", tid_to_tblock(tid),
-			 sizeof(tblock_t));
-		dump_mem("Tlock", tlck, sizeof(tlock_t));
+			 sizeof(struct tblock));
+		dump_mem("Tlock", tlck, sizeof(struct tlock));
 		BUG();
 	}
 	INCREMENT(stattx.waitlock);	/* statistics */
@@ -792,11 +798,11 @@
  *
  * RETURN:      Errors from subroutines.
  */
-static void txRelease(tblock_t * tblk)
+static void txRelease(struct tblock * tblk)
 {
-	metapage_t *mp;
+	struct metapage *mp;
 	lid_t lid;
-	tlock_t *tlck;
+	struct tlock *tlck;
 
 	TXN_LOCK();
 
@@ -825,17 +831,17 @@
  * FUNCTION:    Initiates pageout of pages modified by tid in journalled
  *              objects and frees their lockwords.
  */
-static void txUnlock(tblock_t * tblk)
+static void txUnlock(struct tblock * tblk)
 {
-	tlock_t *tlck;
-	linelock_t *linelock;
+	struct tlock *tlck;
+	struct linelock *linelock;
 	lid_t lid, next, llid, k;
-	metapage_t *mp;
-	log_t *log;
+	struct metapage *mp;
+	struct jfs_log *log;
 	int difft, diffp;
 
 	jFYI(1, ("txUnlock: tblk = 0x%p\n", tblk));
-	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	log = JFS_SBI(tblk->sb)->log;
 
 	/*
 	 * mark page under tlock homeok (its log has been written):
@@ -889,9 +895,9 @@
 		 */
 		TXN_LOCK();
 
-		llid = ((linelock_t *) & tlck->lock)->next;
+		llid = ((struct linelock *) & tlck->lock)->next;
 		while (llid) {
-			linelock = (linelock_t *) lid_to_tlock(llid);
+			linelock = (struct linelock *) lid_to_tlock(llid);
 			k = linelock->next;
 			txLockFree(llid);
 			llid = k;
@@ -922,13 +928,13 @@
  * function: allocate a transaction lock for freed page/entry;
  *      for freed page, maplock is used as xtlock/dtlock type;
  */
-tlock_t *txMaplock(tid_t tid, struct inode *ip, int type)
+struct tlock *txMaplock(tid_t tid, struct inode *ip, int type)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	lid_t lid;
-	tblock_t *tblk;
-	tlock_t *tlck;
-	maplock_t *maplock;
+	struct tblock *tblk;
+	struct tlock *tlck;
+	struct maplock *maplock;
 
 	TXN_LOCK();
 
@@ -980,7 +986,7 @@
 	TXN_UNLOCK();
 
 	/* initialize type dependent area for maplock */
-	maplock = (maplock_t *) & tlck->lock;
+	maplock = (struct maplock *) & tlck->lock;
 	maplock->next = 0;
 	maplock->maxcnt = 0;
 	maplock->index = 0;
@@ -994,11 +1000,11 @@
  *
  * function: allocate a transaction lock for log vector list
  */
-linelock_t *txLinelock(linelock_t * tlock)
+struct linelock *txLinelock(struct linelock * tlock)
 {
 	lid_t lid;
-	tlock_t *tlck;
-	linelock_t *linelock;
+	struct tlock *tlck;
+	struct linelock *linelock;
 
 	TXN_LOCK();
 
@@ -1009,7 +1015,7 @@
 	TXN_UNLOCK();
 
 	/* initialize linelock */
-	linelock = (linelock_t *) tlck;
+	linelock = (struct linelock *) tlck;
 	linelock->next = 0;
 	linelock->flag = tlckLINELOCK;
 	linelock->maxcnt = TLOCKLONG;
@@ -1067,10 +1073,10 @@
 	     int flag)
 {
 	int rc = 0, rc1 = 0;
-	commit_t cd;
-	log_t *log;
-	tblock_t *tblk;
-	lrd_t *lrd;
+	struct commit cd;
+	struct jfs_log *log;
+	struct tblock *tblk;
+	struct lrd *lrd;
 	int lsn;
 	struct inode *ip;
 	struct jfs_inode_info *jfs_ip;
@@ -1095,7 +1101,7 @@
 	/*
 	 * initialize commit structure
 	 */
-	log = (log_t *) JFS_SBI(sb)->log;
+	log = JFS_SBI(sb)->log;
 	cd.log = log;
 
 	/* initialize log record descriptor in commit */
@@ -1293,13 +1299,13 @@
  *
  * RETURN :
  */
-static int txLog(log_t * log, tblock_t * tblk, commit_t * cd)
+static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd)
 {
 	int rc = 0;
 	struct inode *ip;
 	lid_t lid;
-	tlock_t *tlck;
-	lrd_t *lrd = &cd->lrd;
+	struct tlock *tlck;
+	struct lrd *lrd = &cd->lrd;
 
 	/*
 	 * write log record(s) for each tlock of transaction,
@@ -1356,13 +1362,13 @@
  *
  * function:    log inode tlock and format maplock to update bmap;
  */
-int diLog(log_t * log,
-	  tblock_t * tblk, lrd_t * lrd, tlock_t * tlck, commit_t * cd)
+int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	  struct tlock * tlck, struct commit * cd)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	pxd_t *pxd;
-	pxdlock_t *pxdlock;
+	struct pxd_lock *pxdlock;
 
 	mp = tlck->mp;
 
@@ -1418,7 +1424,7 @@
 		lrd->log.noredoinoext.inoext_idx =
 		    cpu_to_le32((u32) (size_t) cd->iplist[2]);
 
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		*pxd = pxdlock->pxd;
 		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
 
@@ -1444,7 +1450,7 @@
 		 * alloc of new (and free of old) external EA extent;
 		 */
 		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		nlock = pxdlock->index;
 		for (i = 0; i < nlock; i++, pxdlock++) {
 			if (pxdlock->flag & mlckALLOCPXD)
@@ -1473,9 +1479,10 @@
  *
  * function:    log data tlock
  */
-int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck)
 {
-	metapage_t *mp;
+	struct metapage *mp;
 	pxd_t *pxd;
 	int rc;
 	s64 xaddr;
@@ -1528,11 +1535,12 @@
  *
  * function:    log dtree tlock and format maplock to update bmap;
  */
-void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck)
 {
 	struct inode *ip;
-	metapage_t *mp;
-	pxdlock_t *pxdlock;
+	struct metapage *mp;
+	struct pxd_lock *pxdlock;
 	pxd_t *pxd;
 
 	ip = tlck->ip;
@@ -1575,7 +1583,7 @@
 		if (tlck->type & tlckBTROOT)
 			return;
 		tlck->flag |= tlckUPDATEMAP;
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		pxdlock->flag = mlckALLOCPXD;
 		pxdlock->pxd = *pxd;
 
@@ -1616,7 +1624,7 @@
 		 * of the deletd page
 		 */
 		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		*pxd = pxdlock->pxd;
 		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
 
@@ -1634,15 +1642,16 @@
  *
  * function:    log xtree tlock and format maplock to update bmap;
  */
-void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	   struct tlock * tlck)
 {
 	struct inode *ip;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
-	xtlock_t *xtlck;
-	maplock_t *maplock;
-	xdlistlock_t *xadlock;
-	pxdlock_t *pxdlock;
+	struct xtlock *xtlck;
+	struct maplock *maplock;
+	struct xdlistlock *xadlock;
+	struct pxd_lock *pxdlock;
 	pxd_t *pxd;
 	int next, lwm, hwm;
 
@@ -1665,10 +1674,10 @@
 		p = (xtpage_t *) mp->data;
 	next = le16_to_cpu(p->header.nextindex);
 
-	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck = (struct xtlock *) & tlck->lock;
 
-	maplock = (maplock_t *) & tlck->lock;
-	xadlock = (xdlistlock_t *) maplock;
+	maplock = (struct maplock *) & tlck->lock;
+	xadlock = (struct xdlistlock *) maplock;
 
 	/*
 	 *      entry insertion/extension;
@@ -1786,7 +1795,7 @@
 		 */
 		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
 		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		hwm = xtlck->hwm.offset;
 		lrd->log.updatemap.nxd =
 		    cpu_to_le16(hwm - XTENTRYSTART + 1);
@@ -1905,7 +1914,7 @@
 			 * entry XAD[next - 1]:
 			 * (xtlck->pxdlock = truncated delta extent);
 			 */
-			pxdlock = (pxdlock_t *) & xtlck->pxdlock;
+			pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
 			/* assert(pxdlock->type & tlckTRUNCATE); */
 			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
 			lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
@@ -1927,7 +1936,7 @@
 			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
 			lrd->log.updatemap.type =
 			    cpu_to_le16(LOG_FREEXADLIST);
-			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck = (struct xtlock *) & tlck->lock;
 			hwm = xtlck->hwm.offset;
 			lrd->log.updatemap.nxd =
 			    cpu_to_le16(hwm - next + 1);
@@ -1969,7 +1978,7 @@
 		 * truncate entry XAD[twm == next - 1]:
 		 */
 		if (twm == next - 1) {
-			pxdlock_t *pxdlock;
+			struct pxd_lock *pxdlock;
 
 			/* format a maplock for txUpdateMap() to update bmap
 			 * to free truncated delta extent of the truncated
@@ -1977,7 +1986,7 @@
 			 * (xtlck->pxdlock = truncated delta extent);
 			 */
 			tlck->flag |= tlckUPDATEMAP;
-			pxdlock = (pxdlock_t *) xadlock;
+			pxdlock = (struct pxd_lock *) xadlock;
 			pxdlock->flag = mlckFREEPXD;
 			pxdlock->count = 1;
 			pxdlock->pxd = tpxd;
@@ -2020,9 +2029,10 @@
  *
  * function:    log from maplock of freed data extents;
  */
-void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+	    struct tlock * tlck)
 {
-	pxdlock_t *pxdlock;
+	struct pxd_lock *pxdlock;
 	int i, nlock;
 	pxd_t *pxd;
 
@@ -2038,7 +2048,7 @@
 		 * for logredo() to start NoRedoPage filter;
 		 */
 		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		pxd = &lrd->log.redopage.pxd;
 		*pxd = pxdlock->pxd;
 		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
@@ -2077,7 +2087,7 @@
 		 * from xtTailgate();
 		 */
 		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
-		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock = (struct pxd_lock *) & tlck->lock;
 		nlock = pxdlock->index;
 		for (i = 0; i < nlock; i++, pxdlock++) {
 			if (pxdlock->flag & mlckALLOCPXD)
@@ -2109,8 +2119,8 @@
  */
 void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
 {
-	tlock_t *tlck = NULL;
-	pxdlock_t *maplock = NULL, *pxdlock = NULL;
+	struct tlock *tlck = NULL;
+	struct pxd_lock *maplock = NULL, *pxdlock = NULL;
 
 	/*
 	 * format maplock for alloc of new EA extent
@@ -2122,8 +2132,8 @@
 		 */
 		if (newea->flag & DXD_EXTENT) {
 			tlck = txMaplock(tid, ip, tlckMAP);
-			maplock = (pxdlock_t *) & tlck->lock;
-			pxdlock = (pxdlock_t *) maplock;
+			maplock = (struct pxd_lock *) & tlck->lock;
+			pxdlock = (struct pxd_lock *) maplock;
 			pxdlock->flag = mlckALLOCPXD;
 			PXDaddress(&pxdlock->pxd, addressDXD(newea));
 			PXDlength(&pxdlock->pxd, lengthDXD(newea));
@@ -2142,8 +2152,8 @@
 	if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) {
 		if (tlck == NULL) {
 			tlck = txMaplock(tid, ip, tlckMAP);
-			maplock = (pxdlock_t *) & tlck->lock;
-			pxdlock = (pxdlock_t *) maplock;
+			maplock = (struct pxd_lock *) & tlck->lock;
+			pxdlock = (struct pxd_lock *) maplock;
 			maplock->index = 0;
 		}
 		pxdlock->flag = mlckFREEPXD;
@@ -2160,11 +2170,11 @@
  * function: synchronously write pages locked by transaction
  *              after txLog() but before txUpdateMap();
  */
-void txForce(tblock_t * tblk)
+void txForce(struct tblock * tblk)
 {
-	tlock_t *tlck;
+	struct tlock *tlck;
 	lid_t lid, next;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	/*
 	 * reverse the order of transaction tlocks in
@@ -2215,17 +2225,17 @@
  *
  * parameter:
  */
-static void txUpdateMap(tblock_t * tblk)
+static void txUpdateMap(struct tblock * tblk)
 {
 	struct inode *ip;
 	struct inode *ipimap;
 	lid_t lid;
-	tlock_t *tlck;
-	maplock_t *maplock;
-	pxdlock_t pxdlock;
+	struct tlock *tlck;
+	struct maplock *maplock;
+	struct pxd_lock pxdlock;
 	int maptype;
 	int k, nlock;
-	metapage_t *mp = 0;
+	struct metapage *mp = 0;
 
 	ipimap = JFS_SBI(tblk->sb)->ipimap;
 
@@ -2268,7 +2278,7 @@
 		 * . in-line PXD list:
 		 * . out-of-line XAD list:
 		 */
-		maplock = (maplock_t *) & tlck->lock;
+		maplock = (struct maplock *) & tlck->lock;
 		nlock = maplock->index;
 
 		for (k = 0; k < nlock; k++, maplock++) {
@@ -2339,7 +2349,7 @@
 		pxdlock.flag = mlckALLOCPXD;
 		pxdlock.pxd = JFS_IP(ip)->ixpxd;
 		pxdlock.index = 1;
-		txAllocPMap(ip, (maplock_t *) & pxdlock, tblk);
+		txAllocPMap(ip, (struct maplock *) & pxdlock, tblk);
 		iput(ip);
 	} else if (tblk->xflag & COMMIT_DELETE) {
 		ip = tblk->ip;
@@ -2374,16 +2384,16 @@
  *
  *      lsn     - log sequence number;
  */
-static void txAllocPMap(struct inode *ip, maplock_t * maplock,
-			tblock_t * tblk)
+static void txAllocPMap(struct inode *ip, struct maplock * maplock,
+			struct tblock * tblk)
 {
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	xdlistlock_t *xadlistlock;
+	struct xdlistlock *xadlistlock;
 	xad_t *xad;
 	s64 xaddr;
 	int xlen;
-	pxdlock_t *pxdlock;
-	xdlistlock_t *pxdlistlock;
+	struct pxd_lock *pxdlock;
+	struct xdlistlock *pxdlistlock;
 	pxd_t *pxd;
 	int n;
 
@@ -2391,7 +2401,7 @@
 	 * allocate from persistent map;
 	 */
 	if (maplock->flag & mlckALLOCXADLIST) {
-		xadlistlock = (xdlistlock_t *) maplock;
+		xadlistlock = (struct xdlistlock *) maplock;
 		xad = xadlistlock->xdlist;
 		for (n = 0; n < xadlistlock->count; n++, xad++) {
 			if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
@@ -2406,7 +2416,7 @@
 			}
 		}
 	} else if (maplock->flag & mlckALLOCPXD) {
-		pxdlock = (pxdlock_t *) maplock;
+		pxdlock = (struct pxd_lock *) maplock;
 		xaddr = addressPXD(&pxdlock->pxd);
 		xlen = lengthPXD(&pxdlock->pxd);
 		dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
@@ -2415,7 +2425,7 @@
 		      xlen));
 	} else {		/* (maplock->flag & mlckALLOCPXDLIST) */
 
-		pxdlistlock = (xdlistlock_t *) maplock;
+		pxdlistlock = (struct xdlistlock *) maplock;
 		pxd = pxdlistlock->xdlist;
 		for (n = 0; n < pxdlistlock->count; n++, pxd++) {
 			xaddr = addressPXD(pxd);
@@ -2438,15 +2448,15 @@
  * todo: optimization
  */
 void txFreeMap(struct inode *ip,
-	       maplock_t * maplock, tblock_t * tblk, int maptype)
+	       struct maplock * maplock, struct tblock * tblk, int maptype)
 {
 	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
-	xdlistlock_t *xadlistlock;
+	struct xdlistlock *xadlistlock;
 	xad_t *xad;
 	s64 xaddr;
 	int xlen;
-	pxdlock_t *pxdlock;
-	xdlistlock_t *pxdlistlock;
+	struct pxd_lock *pxdlock;
+	struct xdlistlock *pxdlistlock;
 	pxd_t *pxd;
 	int n;
 
@@ -2459,7 +2469,7 @@
 	 */
 	if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) {
 		if (maplock->flag & mlckFREEXADLIST) {
-			xadlistlock = (xdlistlock_t *) maplock;
+			xadlistlock = (struct xdlistlock *) maplock;
 			xad = xadlistlock->xdlist;
 			for (n = 0; n < xadlistlock->count; n++, xad++) {
 				if (!(xad->flag & XAD_NEW)) {
@@ -2473,7 +2483,7 @@
 				}
 			}
 		} else if (maplock->flag & mlckFREEPXD) {
-			pxdlock = (pxdlock_t *) maplock;
+			pxdlock = (struct pxd_lock *) maplock;
 			xaddr = addressPXD(&pxdlock->pxd);
 			xlen = lengthPXD(&pxdlock->pxd);
 			dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
@@ -2483,7 +2493,7 @@
 			      (ulong) xaddr, xlen));
 		} else {	/* (maplock->flag & mlckALLOCPXDLIST) */
 
-			pxdlistlock = (xdlistlock_t *) maplock;
+			pxdlistlock = (struct xdlistlock *) maplock;
 			pxd = pxdlistlock->xdlist;
 			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
 				xaddr = addressPXD(pxd);
@@ -2502,7 +2512,7 @@
 	 */
 	if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) {
 		if (maplock->flag & mlckFREEXADLIST) {
-			xadlistlock = (xdlistlock_t *) maplock;
+			xadlistlock = (struct xdlistlock *) maplock;
 			xad = xadlistlock->xdlist;
 			for (n = 0; n < xadlistlock->count; n++, xad++) {
 				xaddr = addressXAD(xad);
@@ -2514,7 +2524,7 @@
 				      (ulong) xaddr, xlen));
 			}
 		} else if (maplock->flag & mlckFREEPXD) {
-			pxdlock = (pxdlock_t *) maplock;
+			pxdlock = (struct pxd_lock *) maplock;
 			xaddr = addressPXD(&pxdlock->pxd);
 			xlen = lengthPXD(&pxdlock->pxd);
 			dbFree(ip, xaddr, (s64) xlen);
@@ -2523,7 +2533,7 @@
 			      (ulong) xaddr, xlen));
 		} else {	/* (maplock->flag & mlckFREEPXDLIST) */
 
-			pxdlistlock = (xdlistlock_t *) maplock;
+			pxdlistlock = (struct xdlistlock *) maplock;
 			pxd = pxdlistlock->xdlist;
 			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
 				xaddr = addressPXD(pxd);
@@ -2546,13 +2556,13 @@
 void txFreelock(struct inode *ip)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
-	tlock_t *xtlck, *tlck;
+	struct tlock *xtlck, *tlck;
 	lid_t xlid = 0, lid;
 
 	if (!jfs_ip->atlhead)
 		return;
 
-	xtlck = (tlock_t *) &jfs_ip->atlhead;
+	xtlck = (struct tlock *) &jfs_ip->atlhead;
 
 	while ((lid = xtlck->next)) {
 		tlck = lid_to_tlock(lid);
@@ -2593,8 +2603,8 @@
 void txAbort(tid_t tid, int dirty)
 {
 	lid_t lid, next;
-	metapage_t *mp;
-	tblock_t *tblk = tid_to_tblock(tid);
+	struct metapage *mp;
+	struct tblock *tblk = tid_to_tblock(tid);
 
 	jEVENT(1, ("txAbort: tid:%d dirty:0x%x\n", tid, dirty));
 
@@ -2651,12 +2661,12 @@
  * log age of page-frames in memory for which caller has
  * are reset to 0 (to avoid logwarap).
  */
-void txAbortCommit(commit_t * cd, int exval)
+void txAbortCommit(struct commit * cd, int exval)
 {
-	tblock_t *tblk;
+	struct tblock *tblk;
 	tid_t tid;
 	lid_t lid, next;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	assert(exval == EIO || exval == ENOMEM);
 	jEVENT(1, ("txAbortCommit: cd:0x%p\n", cd));
@@ -2706,9 +2716,9 @@
  *	allocation maps are updated in order.  For synchronous transactions,
  *	let the user thread finish processing after txUpdateMap() is called.
  */
-void txLazyCommit(tblock_t * tblk)
+void txLazyCommit(struct tblock * tblk)
 {
-	log_t *log;
+	struct jfs_log *log;
 
 	while (((tblk->flag & tblkGC_READY) == 0) &&
 	       ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
@@ -2723,7 +2733,7 @@
 
 	txUpdateMap(tblk);
 
-	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;
 
 	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
 
@@ -2756,7 +2766,7 @@
 int jfs_lazycommit(void *arg)
 {
 	int WorkDone;
-	tblock_t *tblk;
+	struct tblock *tblk;
 	unsigned long flags;
 
 	lock_kernel();
@@ -2831,7 +2841,7 @@
 	return 0;
 }
 
-void txLazyUnlock(tblock_t * tblk)
+void txLazyUnlock(struct tblock * tblk)
 {
 	unsigned long flags;
 
@@ -2847,9 +2857,9 @@
 	wake_up(&jfs_commit_thread_wait);
 }
 
-static void LogSyncRelease(metapage_t * mp)
+static void LogSyncRelease(struct metapage * mp)
 {
-	log_t *log = mp->log;
+	struct jfs_log *log = mp->log;
 
 	assert(atomic_read(&mp->nohomeok));
 	assert(log);
@@ -2885,7 +2895,7 @@
 {
 	struct inode *ip;
 	struct jfs_inode_info *jfs_ip;
-	log_t *log = JFS_SBI(sb)->log;
+	struct jfs_log *log = JFS_SBI(sb)->log;
 	int rc;
 	tid_t tid;
 
@@ -2936,7 +2946,7 @@
  */
 void txResume(struct super_block *sb)
 {
-	log_t *log = JFS_SBI(sb)->log;
+	struct jfs_log *log = JFS_SBI(sb)->log;
 
 	clear_bit(log_QUIESCE, &log->flag);
 	TXN_WAKEUP(&log->syncwait);
diff -Nru a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
--- a/fs/jfs/jfs_txnmgr.h	Sun Sep 15 19:20:18 2002
+++ b/fs/jfs/jfs_txnmgr.h	Sun Sep 15 19:20:18 2002
@@ -30,9 +30,9 @@
 /*
  *	transaction block
  */
-typedef struct tblock {
+struct tblock {
 	/*
-	 * tblock_t and jbuf_t common area: struct logsyncblk
+	 * tblock and jbuf_t common area: struct logsyncblk
 	 *
 	 * the following 5 fields are the same as struct logsyncblk
 	 * which is common to tblock and jbuf to form logsynclist
@@ -44,28 +44,26 @@
 	struct list_head synclist;	/* logsynclist link */
 
 	/* lock management */
-	struct super_block *sb;	/* 4: super block */
-	lid_t next;		/* 2: index of first tlock of tid */
-	lid_t last;		/* 2: index of last tlock of tid */
-	wait_queue_head_t waitor;	/* 4: tids waiting on this tid */
+	struct super_block *sb;	/* super block */
+	lid_t next;		/* index of first tlock of tid */
+	lid_t last;		/* index of last tlock of tid */
+	wait_queue_head_t waitor;	/* tids waiting on this tid */
 
 	/* log management */
-	u32 logtid;		/* 4: log transaction id */
-				/* (32) */
+	u32 logtid;		/* log transaction id */
 
 	/* commit management */
-	struct tblock *cqnext;	/* 4: commit queue link */
-	s32 clsn;		/* 4: commit lsn */
-	struct lbuf *bp;	/* 4: */
-	s32 pn;			/* 4: commit record log page number */
-	s32 eor;		/* 4: commit record eor */
-	wait_queue_head_t gcwait;	/* 4: group commit event list:
-					 *    ready transactions wait on this
-					 *    event for group commit completion.
+	struct tblock *cqnext;	/* commit queue link */
+	s32 clsn;		/* commit lsn */
+	struct lbuf *bp;
+	s32 pn;			/* commit record log page number */
+	s32 eor;		/* commit record eor */
+	wait_queue_head_t gcwait;	/* group commit event list:
+					 * ready transactions wait on this
+					 * event for group commit completion.
 					 */
-	struct inode *ip;	/* 4: inode being created or deleted */
-	s32 rsrvd;		/* 4: */
-} tblock_t;			/* (64) */
+	struct inode *ip;	/* inode being created or deleted */
+};
 
 extern struct tblock *TxBlock;	/* transaction block table */
 
@@ -90,7 +88,7 @@
 /*
  *	transaction lock
  */
-typedef struct tlock {
+struct tlock {
 	lid_t next;		/* index next lockword on tid locklist
 				 *          next lockword on freelist
 				 */
@@ -104,7 +102,7 @@
 	/* (16) */
 
 	s16 lock[24];		/* 48: overlay area */
-} tlock_t;			/* (64) */
+};				/* (64) */
 
 extern struct tlock *TxLock;	/* transaction lock table */
 
@@ -153,18 +151,18 @@
 /*
  *	linelock for lmLog()
  *
- * note: linelock_t and its variations are overlaid
+ * note: linelock and its variations are overlaid
  * at tlock.lock: watch for alignment;
  */
-typedef struct {
+struct lv {
 	u8 offset;		/* 1: */
 	u8 length;		/* 1: */
-} lv_t;				/* (2) */
+};				/* (2) */
 
 #define	TLOCKSHORT	20
 #define	TLOCKLONG	28
 
-typedef struct {
+struct linelock {
 	u16 next;		/* 2: next linelock */
 
 	s8 maxcnt;		/* 1: */
@@ -175,13 +173,12 @@
 	u8 l2linesize;		/* 1: log2 of linesize */
 	/* (8) */
 
-	lv_t lv[20];		/* 40: */
-} linelock_t;			/* (48) */
+	struct lv lv[20];	/* 40: */
+}; 				/* (48) */
 
-#define dtlock_t	linelock_t
-#define itlock_t	linelock_t
+#define dt_lock	linelock
 
-typedef struct {
+struct xtlock {
 	u16 next;		/* 2: */
 
 	s8 maxcnt;		/* 1: */
@@ -192,27 +189,27 @@
 	u8 l2linesize;		/* 1: log2 of linesize */
 				/* (8) */
 
-	lv_t header;		/* 2: */
-	lv_t lwm;		/* 2: low water mark */
-	lv_t hwm;		/* 2: high water mark */
-	lv_t twm;		/* 2: */
+	struct lv header;	/* 2: */
+	struct lv lwm;		/* 2: low water mark */
+	struct lv hwm;		/* 2: high water mark */
+	struct lv twm;		/* 2: */
 				/* (16) */
 
 	s32 pxdlock[8];		/* 32: */
-} xtlock_t;			/* (48) */
+};				/* (48) */
 
 
 /*
  *	maplock for txUpdateMap()
  *
- * note: maplock_t and its variations are overlaid
+ * note: maplock and its variations are overlaid
  * at tlock.lock/linelock: watch for alignment;
  * N.B. next field may be set by linelock, and should not
  * be modified by maplock;
  * N.B. index of the first pxdlock specifies index of next 
  * free maplock (i.e., number of maplock) in the tlock; 
  */
-typedef struct {
+struct maplock {
 	u16 next;		/* 2: */
 
 	u8 maxcnt;		/* 2: */
@@ -224,7 +221,7 @@
 				/* (8) */
 
 	pxd_t pxd;		/* 8: */
-} maplock_t;			/* (16): */
+};				/* (16): */
 
 /* maplock flag */
 #define	mlckALLOC		0x00f0
@@ -238,9 +235,9 @@
 #define	mlckFREEXAD		0x0002
 #define	mlckFREEPXD		0x0001
 
-#define	pxdlock_t	maplock_t
+#define	pxd_lock	maplock
 
-typedef struct {
+struct xdlistlock {
 	u16 next;		/* 2: */
 
 	u8 maxcnt;		/* 2: */
@@ -252,14 +249,14 @@
 				/* (8) */
 
 	/*
-	 * We need xdlistlock_t to be 64 bits (8 bytes), regardless of
+	 * We need xdlist to be 64 bits (8 bytes), regardless of
 	 * whether void * is 32 or 64 bits
 	 */
 	union {
 		void *_xdlist;	/* pxd/xad list */
 		s64 pad;	/* 8: Force 64-bit xdlist size */
 	} union64;
-} xdlistlock_t;			/* (16): */
+};				/* (16): */
 
 #define xdlist union64._xdlist
 
@@ -268,26 +265,26 @@
  *
  * parameter to the commit manager routines
  */
-typedef struct commit {
-	tid_t tid;		/* 4: tid = index of tblock */
-	int flag;		/* 4: flags */
-	log_t *log;		/* 4: log */
-	struct super_block *sb;	/* 4: superblock */
-
-	int nip;		/* 4: number of entries in iplist */
-	struct inode **iplist;	/* 4: list of pointers to inodes */
-				/* (32) */
+struct commit {
+	tid_t tid;		/* tid = index of tblock */
+	int flag;		/* flags */
+	struct jfs_log *log;	/* log */
+	struct super_block *sb;	/* superblock */
+
+	int nip;		/* number of entries in iplist */
+	struct inode **iplist;	/* list of pointers to inodes */
 
 	/* log record descriptor on 64-bit boundary */
-	lrd_t lrd;		/* : log record descriptor */
-} commit_t;
+	struct lrd lrd;		/* : log record descriptor */
+};
 
 /*
  * external declarations
  */
-extern tlock_t *txLock(tid_t tid, struct inode *ip, struct metapage *mp, int flag);
+extern struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage *mp,
+			    int flag);
 
-extern tlock_t *txMaplock(tid_t tid, struct inode *ip, int flag);
+extern struct tlock *txMaplock(tid_t tid, struct inode *ip, int flag);
 
 extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag);
 
@@ -299,16 +296,17 @@
 
 extern void txAbort(tid_t tid, int dirty);
 
-extern linelock_t *txLinelock(linelock_t * tlock);
+extern struct linelock *txLinelock(struct linelock * tlock);
 
-extern void txFreeMap(struct inode *ip,
-		      maplock_t * maplock, tblock_t * tblk, int maptype);
+extern void txFreeMap(struct inode *ip, struct maplock * maplock,
+		      struct tblock * tblk, int maptype);
 
 extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea);
 
 extern void txFreelock(struct inode *ip);
 
-extern int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+extern int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
+		 struct tlock * tlck);
 
 extern void txQuiesce(struct super_block *sb);
 
diff -Nru a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h
--- a/fs/jfs/jfs_types.h	Sun Sep 15 19:19:45 2002
+++ b/fs/jfs/jfs_types.h	Sun Sep 15 19:19:45 2002
@@ -81,11 +81,11 @@
 	( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
 
 /* lxd list */
-typedef struct {
+struct lxdlist {
 	s16 maxnlxd;
 	s16 nlxd;
 	lxd_t *lxd;
-} lxdlist_t;
+};
 
 /*
  *	physical xd (pxd)
@@ -111,11 +111,11 @@
 	( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2))
 
 /* pxd list */
-typedef struct {
+struct pxdlist {
 	s16 maxnpxd;
 	s16 npxd;
 	pxd_t pxd[8];
-} pxdlist_t;
+};
 
 
 /*
@@ -150,16 +150,16 @@
 /*
  *      directory entry argument
  */
-typedef struct component_name {
+struct component_name {
 	int namlen;
 	wchar_t *name;
-} component_t;
+};
 
 
 /*
  *	DASD limit information - stored in directory inode
  */
-typedef struct dasd {
+struct dasd {
 	u8 thresh;		/* Alert Threshold (in percent) */
 	u8 delta;		/* Alert Threshold delta (in percent)   */
 	u8 rsrvd1;
@@ -168,7 +168,7 @@
 	u8 rsrvd2[3];
 	u8 used_hi;		/* DASD usage (in logical blocks)       */
 	u32 used_lo;		/* DASD usage (in logical blocks)       */
-} dasd_t;
+};
 
 #define DASDLIMIT(dasdp) \
 	(((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo))
diff -Nru a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
--- a/fs/jfs/jfs_umount.c	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/jfs_umount.c	Sun Sep 15 19:19:28 2002
@@ -55,7 +55,7 @@
 	struct inode *ipimap = sbi->ipimap;
 	struct inode *ipaimap = sbi->ipaimap;
 	struct inode *ipaimap2 = sbi->ipaimap2;
-	log_t *log;
+	struct jfs_log *log;
 	int rc = 0;
 
 	jFYI(1, ("\n	UnMount JFS: sb:0x%p\n", sb));
@@ -143,7 +143,7 @@
 {
 	struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping;
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
-	log_t *log = sbi->log;
+	struct jfs_log *log = sbi->log;
 
 	if (!log)
 		return 0;
diff -Nru a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c
--- a/fs/jfs/jfs_unicode.c	Sun Sep 15 19:20:20 2002
+++ b/fs/jfs/jfs_unicode.c	Sun Sep 15 19:20:20 2002
@@ -89,7 +89,7 @@
  * FUNCTION:	Allocate and translate to unicode string
  *
  */
-int get_UCSname(component_t * uniName, struct dentry *dentry,
+int get_UCSname(struct component_name * uniName, struct dentry *dentry,
 		struct nls_table *nls_tab)
 {
 	int length = dentry->d_name.len;
diff -Nru a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
--- a/fs/jfs/jfs_unicode.h	Sun Sep 15 19:19:28 2002
+++ b/fs/jfs/jfs_unicode.h	Sun Sep 15 19:19:28 2002
@@ -30,7 +30,8 @@
 
 extern signed char UniUpperTable[512];
 extern UNICASERANGE UniUpperRange[];
-extern int get_UCSname(component_t *, struct dentry *, struct nls_table *);
+extern int get_UCSname(struct component_name *, struct dentry *,
+		       struct nls_table *);
 extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
 
 #define free_UCSname(COMP) kfree((COMP)->name)
diff -Nru a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
--- a/fs/jfs/jfs_xattr.h	Sun Sep 15 19:19:30 2002
+++ b/fs/jfs/jfs_xattr.h	Sun Sep 15 19:19:30 2002
@@ -52,7 +52,11 @@
 #define	END_EALIST(ealist) \
 	((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist)))
 
-extern int jfs_setxattr(struct dentry *, const char *, void *, size_t, int);
+extern int __jfs_setxattr(struct inode *, const char *, void *, size_t,
+			int);
+extern int jfs_setxattr(struct dentry *, const char *, void *, size_t,
+			int);
+extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t);
 extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
 extern int jfs_removexattr(struct dentry *, const char *);
diff -Nru a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c	Sun Sep 15 19:19:46 2002
+++ b/fs/jfs/jfs_xtree.c	Sun Sep 15 19:19:46 2002
@@ -84,15 +84,15 @@
 #define XT_GETSEARCH(IP, LEAF, BN, MP,  P, INDEX) \
 	BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot)
 /* xtree entry parameter descriptor */
-typedef struct {
-	metapage_t *mp;
+struct xtsplit {
+	struct metapage *mp;
 	s16 index;
 	u8 flag;
 	s64 off;
 	s64 addr;
 	int len;
-	pxdlist_t *pxdlist;
-} xtsplit_t;
+	struct pxdlist *pxdlist;
+};
 
 
 /*
@@ -111,29 +111,25 @@
  * forward references
  */
 static int xtSearch(struct inode *ip,
-		    s64 xoff, int *cmpp, btstack_t * btstack, int flag);
+		    s64 xoff, int *cmpp, struct btstack * btstack, int flag);
 
 static int xtSplitUp(tid_t tid,
 		     struct inode *ip,
-		     xtsplit_t * split, btstack_t * btstack);
+		     struct xtsplit * split, struct btstack * btstack);
 
-static int xtSplitPage(tid_t tid,
-		       struct inode *ip,
-		       xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp);
-
-static int xtSplitRoot(tid_t tid,
-		       struct inode *ip,
-		       xtsplit_t * split, metapage_t ** rmpp);
+static int xtSplitPage(tid_t tid, struct inode *ip, struct xtsplit * split,
+		       struct metapage ** rmpp, s64 * rbnp);
+
+static int xtSplitRoot(tid_t tid, struct inode *ip,
+		       struct xtsplit * split, struct metapage ** rmpp);
 
 #ifdef _STILL_TO_PORT
-static int xtDeleteUp(tid_t tid,
-		      struct inode *ip,
-		      metapage_t * fmp,
-		      xtpage_t * fp, btstack_t * btstack);
+static int xtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp,
+		      xtpage_t * fp, struct btstack * btstack);
 
 static int xtSearchNode(struct inode *ip,
 			xad_t * xad,
-			int *cmpp, btstack_t * btstack, int flag);
+			int *cmpp, struct btstack * btstack, int flag);
 
 static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp);
 #endif				/*  _STILL_TO_PORT */
@@ -155,10 +151,10 @@
 	     s64 llen, int *pflag, s64 * paddr, s32 * plen, int no_check)
 {
 	int rc = 0;
-	btstack_t btstack;
+	struct btstack btstack;
 	int cmp;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	int index;
 	xad_t *xad;
@@ -240,8 +236,8 @@
  *
  * parameter:
  *      struct inode    *ip,
- *      lxdlist_t       *lxdlist,       lxd list (in)
- *      xadlist_t       *xadlist,       xad list (in/out)
+ *      struct lxdlist  *lxdlist,       lxd list (in)
+ *      struct xadlist  *xadlist,       xad list (in/out)
  *      int		flag)
  *
  * coverage of lxd by xad under assumption of
@@ -256,15 +252,14 @@
  *      required to cover the last byte;
  *      the extent backing a page is fully contained within an xad;
  */
-int xtLookupList(struct inode *ip, lxdlist_t * lxdlist,	/* lxd list (in) */
-		 xadlist_t * xadlist,	/* xad list (in/out) */
-		 int flag)
+int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
+		 struct xadlist * xadlist, int flag)
 {
 	int rc = 0;
-	btstack_t btstack;
+	struct btstack btstack;
 	int cmp;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	int index;
 	lxd_t *lxd;
@@ -509,17 +504,17 @@
  *      the page containing the entry is pinned at exit.
  */
 static int xtSearch(struct inode *ip, s64 xoff,	/* offset of extent */
-		    int *cmpp, btstack_t * btstack, int flag)
+		    int *cmpp, struct btstack * btstack, int flag)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	int rc = 0;
 	int cmp = 1;		/* init for empty page */
 	s64 bn;			/* block number */
-	metapage_t *mp;		/* page buffer */
+	struct metapage *mp;	/* page buffer */
 	xtpage_t *p;		/* page */
 	xad_t *xad;
 	int base, index, lim, btindex;
-	btframe_t *btsp;
+	struct btframe *btsp;
 	int nsplit = 0;		/* number of pages to split */
 	s64 t64;
 
@@ -796,16 +791,16 @@
 {
 	int rc = 0;
 	s64 xaddr, hint;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* base B+-tree index page */
 	s64 bn;
 	int index, nextindex;
-	btstack_t btstack;	/* traverse stack */
-	xtsplit_t split;	/* split information */
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
 	xad_t *xad;
 	int cmp;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 
 	jFYI(1,
 	     ("xtInsert: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
@@ -903,7 +898,7 @@
 	/* Don't log it if there are no links to the file */
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset =
 		    (xtlck->lwm.offset) ? min(index,
 					      (int)xtlck->lwm.offset) : index;
@@ -937,27 +932,27 @@
  */
 static int
 xtSplitUp(tid_t tid,
-	  struct inode *ip, xtsplit_t * split, btstack_t * btstack)
+	  struct inode *ip, struct xtsplit * split, struct btstack * btstack)
 {
 	int rc = 0;
-	metapage_t *smp;
+	struct metapage *smp;
 	xtpage_t *sp;		/* split page */
-	metapage_t *rmp;
+	struct metapage *rmp;
 	s64 rbn;		/* new right page block number */
-	metapage_t *rcmp;
+	struct metapage *rcmp;
 	xtpage_t *rcp;		/* right child page */
 	s64 rcbn;		/* right child page block number */
 	int skip;		/* index of entry of insertion */
 	int nextindex;		/* next available entry index of p */
-	btframe_t *parent;	/* parent page entry on traverse stack */
+	struct btframe *parent;	/* parent page entry on traverse stack */
 	xad_t *xad;
 	s64 xaddr;
 	int xlen;
 	int nsplit;		/* number of pages split */
-	pxdlist_t pxdlist;
+	struct pxdlist pxdlist;
 	pxd_t *pxd;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 
 	smp = split->mp;
 	sp = XT_PAGE(ip, smp);
@@ -995,7 +990,7 @@
 		/* Don't log it if there are no links to the file */
 		if (!test_cflag(COMMIT_Nolink, ip)) {
 			tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
-			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck = (struct xtlock *) & tlck->lock;
 			xtlck->lwm.offset = (xtlck->lwm.offset) ?
 			    min(skip, (int)xtlck->lwm.offset) : skip;
 			xtlck->lwm.length =
@@ -1163,7 +1158,7 @@
 			if (!test_cflag(COMMIT_Nolink, ip)) {
 				tlck = txLock(tid, ip, smp,
 					      tlckXTREE | tlckGROW);
-				xtlck = (xtlock_t *) & tlck->lock;
+				xtlck = (struct xtlock *) & tlck->lock;
 				xtlck->lwm.offset = (xtlck->lwm.offset) ?
 				    min(skip, (int)xtlck->lwm.offset) : skip;
 				xtlck->lwm.length =
@@ -1210,8 +1205,8 @@
  * parameter:
  *      int		tid,
  *      struct inode    *ip,
- *      xtsplit_t       *split,
- *      metapage_t	**rmpp,
+ *      struct xtsplit  *split,
+ *      struct metapage	**rmpp,
  *      u64		*rbnp,
  *
  * return:
@@ -1219,23 +1214,23 @@
  */
 static int
 xtSplitPage(tid_t tid, struct inode *ip,
-	    xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp)
+	    struct xtsplit * split, struct metapage ** rmpp, s64 * rbnp)
 {
 	int rc = 0;
-	metapage_t *smp;
+	struct metapage *smp;
 	xtpage_t *sp;
-	metapage_t *rmp;
+	struct metapage *rmp;
 	xtpage_t *rp;		/* new right page allocated */
 	s64 rbn;		/* new right page block number */
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	s64 nextbn;
 	int skip, maxentry, middle, righthalf, n;
 	xad_t *xad;
-	pxdlist_t *pxdlist;
+	struct pxdlist *pxdlist;
 	pxd_t *pxd;
-	tlock_t *tlck;
-	xtlock_t *sxtlck = 0, *rxtlck = 0;
+	struct tlock *tlck;
+	struct xtlock *sxtlck = 0, *rxtlck = 0;
 
 	smp = split->mp;
 	sp = XT_PAGE(ip, smp);
@@ -1274,13 +1269,13 @@
 		 * acquire a transaction lock on the new right page;
 		 */
 		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
-		rxtlck = (xtlock_t *) & tlck->lock;
+		rxtlck = (struct xtlock *) & tlck->lock;
 		rxtlck->lwm.offset = XTENTRYSTART;
 		/*
 		 * acquire a transaction lock on the split page
 		 */
 		tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
-		sxtlck = (xtlock_t *) & tlck->lock;
+		sxtlck = (struct xtlock *) & tlck->lock;
 	}
 
 	/*
@@ -1465,26 +1460,26 @@
  * parameter:
  *      int		tid,
  *      struct inode    *ip,
- *      xtsplit_t       *split,
- *      metapage_t	**rmpp)
+ *      struct xtsplit  *split,
+ *      struct metapage	**rmpp)
  *
  * return:
  *      Pointer to page in which to insert or NULL on error.
  */
 static int
 xtSplitRoot(tid_t tid,
-	    struct inode *ip, xtsplit_t * split, metapage_t ** rmpp)
+	    struct inode *ip, struct xtsplit * split, struct metapage ** rmpp)
 {
 	xtpage_t *sp;
-	metapage_t *rmp;
+	struct metapage *rmp;
 	xtpage_t *rp;
 	s64 rbn;
 	int skip, nextindex;
 	xad_t *xad;
 	pxd_t *pxd;
-	pxdlist_t *pxdlist;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct pxdlist *pxdlist;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 
 	sp = &JFS_IP(ip)->i_xtroot;
 
@@ -1546,7 +1541,7 @@
 
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset = XTENTRYSTART;
 		xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
 		    XTENTRYSTART;
@@ -1577,7 +1572,7 @@
 
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->lwm.offset = XTENTRYSTART;
 		xtlck->lwm.length = 1;
 	}
@@ -1608,16 +1603,16 @@
 {
 	int rc = 0;
 	int cmp;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* base B+-tree index page */
 	s64 bn;
 	int index, nextindex, len;
-	btstack_t btstack;	/* traverse stack */
-	xtsplit_t split;	/* split information */
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
 	xad_t *xad;
 	s64 xaddr;
-	tlock_t *tlck;
-	xtlock_t *xtlck = 0;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
 	int rootsplit = 0;
 
 	jFYI(1,
@@ -1646,7 +1641,7 @@
 	BT_MARK_DIRTY(mp, ip);
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 	}
 
 	/* extend will overflow extent ? */
@@ -1701,7 +1696,7 @@
 					tlck = txLock(tid, ip, mp,
 						      tlckXTREE |
 						      tlckGROW);
-					xtlck = (xtlock_t *) & tlck->lock;
+					xtlck = (struct xtlock *) & tlck->lock;
 				}
 			}
 		} else
@@ -1768,17 +1763,17 @@
 {
 	int rc = 0;
 	int cmp;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* base B+-tree index page */
 	s64 bn;
 	int index, nextindex, llen, rlen;
-	btstack_t btstack;	/* traverse stack */
-	xtsplit_t split;	/* split information */
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
 	xad_t *xad;
-	tlock_t *tlck;
-	xtlock_t *xtlck = 0;
-	tlock_t *mtlck;
-	maplock_t *pxdlock;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
+	struct tlock *mtlck;
+	struct maplock *pxdlock;
 	int rootsplit = 0;
 
 /*
@@ -1804,7 +1799,7 @@
 	 */
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 	}
 
 	/* completely replace extent ? */
@@ -1859,7 +1854,7 @@
 					tlck = txLock(tid, ip, mp,
 						      tlckXTREE |
 						      tlckGROW);
-					xtlck = (xtlock_t *) & tlck->lock;
+					xtlck = (struct xtlock *) & tlck->lock;
 				}
 			}
 		} else
@@ -1892,7 +1887,7 @@
 		/* free from PWMAP at commit */
 		if (!test_cflag(COMMIT_Nolink, ip)) {
 			mtlck = txMaplock(tid, ip, tlckMAP);
-			pxdlock = (maplock_t *) & mtlck->lock;
+			pxdlock = (struct maplock *) & mtlck->lock;
 			pxdlock->flag = mlckFREEPXD;
 			PXDaddress(&pxdlock->pxd, addressXAD(xad) + llen);
 			PXDlength(&pxdlock->pxd, rlen);
@@ -1944,19 +1939,19 @@
 {				/* new XAD */
 	int rc = 0;
 	int cmp;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* base B+-tree index page */
 	s64 bn;
 	int index0, index, newindex, nextindex;
-	btstack_t btstack;	/* traverse stack */
-	xtsplit_t split;	/* split information */
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
 	xad_t *xad, *lxad, *rxad;
 	int xflag;
 	s64 nxoff, xoff;
 	int nxlen, xlen, lxlen, rxlen;
 	s64 nxaddr, xaddr;
-	tlock_t *tlck;
-	xtlock_t *xtlck = 0;
+	struct tlock *tlck;
+	struct xtlock *xtlck = 0;
 	int rootsplit = 0, newpage = 0;
 
 	/* there must exist extent to be tailgated */
@@ -1980,7 +1975,7 @@
 	 */
 	if (!test_cflag(COMMIT_Nolink, ip)) {
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 	}
 
 	xad = &p->xad[index0];
@@ -2192,7 +2187,7 @@
 					tlck = txLock(tid, ip, mp,
 						      tlckXTREE |
 						      tlckGROW);
-					xtlck = (xtlock_t *) & tlck->lock;
+					xtlck = (struct xtlock *) & tlck->lock;
 				}
 			}
 		} else {
@@ -2255,7 +2250,7 @@
 		BT_MARK_DIRTY(mp, ip);
 		if (!test_cflag(COMMIT_Nolink, ip)) {
 			tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck = (struct xtlock *) & tlck->lock;
 		}
 
 		index0 = index = newindex;
@@ -2337,7 +2332,7 @@
 					tlck = txLock(tid, ip, mp,
 						      tlckXTREE |
 						      tlckGROW);
-					xtlck = (xtlock_t *) & tlck->lock;
+					xtlck = (struct xtlock *) & tlck->lock;
 				}
 			}
 		} else
@@ -2397,18 +2392,18 @@
 	     int flag)
 {
 	int rc = 0;
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* base B+-tree index page */
 	s64 bn, xaddr;
 	int index, nextindex;
-	btstack_t btstack;	/* traverse stack */
-	xtsplit_t split;	/* split information */
+	struct btstack btstack;	/* traverse stack */
+	struct xtsplit split;	/* split information */
 	xad_t *xad;
 	int cmp;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 	int nsplit, nblocks, xlen;
-	pxdlist_t pxdlist;
+	struct pxdlist pxdlist;
 	pxd_t *pxd;
 
 	xaddr = *xaddrp;
@@ -2516,7 +2511,7 @@
 	 * action: xad insertion/extension;
 	 */
 	tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
-	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck = (struct xtlock *) & tlck->lock;
 
 	/* insert the new entry: mark the entry NEW */
 	xad = &p->xad[index];
@@ -2561,14 +2556,14 @@
 int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
 {
 	int rc = 0;
-	btstack_t btstack;
+	struct btstack btstack;
 	int cmp;
 	s64 bn;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	int index, nextindex;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 
 	/*
 	 * find the matching entry; xtSearch() pins the page
@@ -2603,7 +2598,7 @@
 	 * action:xad deletion;
 	 */
 	tlck = txLock(tid, ip, mp, tlckXTREE);
-	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck = (struct xtlock *) & tlck->lock;
 	xtlck->lwm.offset =
 	    (xtlck->lwm.offset) ? min(index, xtlck->lwm.offset) : index;
 
@@ -2630,19 +2625,18 @@
  * return:
  */
 static int
-xtDeleteUp(tid_t tid,
-	   struct inode *ip,
-	   metapage_t * fmp, xtpage_t * fp, btstack_t * btstack)
+xtDeleteUp(tid_t tid, struct inode *ip,
+	   struct metapage * fmp, xtpage_t * fp, struct btstack * btstack)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	int index, nextindex;
 	s64 xaddr;
 	int xlen;
-	btframe_t *parent;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
+	struct btframe *parent;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
 
 	/*
 	 * keep root leaf page which has become empty
@@ -2736,7 +2730,7 @@
 			 * action:xad deletion;
 			 */
 			tlck = txLock(tid, ip, mp, tlckXTREE);
-			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck = (struct xtlock *) & tlck->lock;
 			xtlck->lwm.offset =
 			    (xtlck->lwm.offset) ? min(index,
 						      xtlck->lwm.
@@ -2785,10 +2779,10 @@
 	   int xtype)
 {				/* extent type: XTPAGE or DATAEXT */
 	int rc = 0;
-	tblock_t *tblk;
-	tlock_t *tlck;
-	xtlock_t *xtlck;
-	metapage_t *mp, *pmp, *lmp, *rmp;	/* meta-page buffer */
+	struct tblock *tblk;
+	struct tlock *tlck;
+	struct xtlock *xtlck;
+	struct metapage *mp, *pmp, *lmp, *rmp;	/* meta-page buffer */
 	xtpage_t *p, *pp, *rp, *lp;	/* base B+-tree index page */
 	xad_t *xad;
 	pxd_t *pxd;
@@ -2801,8 +2795,8 @@
 	s64 bn;
 	int cmp;
 	int index;
-	pxdlock_t *pxdlock;
-	btstack_t btstack;	/* traverse stack */
+	struct pxd_lock *pxdlock;
+	struct btstack btstack;	/* traverse stack */
 
 	xtype = xtype & EXTENT_TYPE;
 
@@ -3016,7 +3010,7 @@
 		BT_MARK_DIRTY(mp, ip);
 		/* tlckNEW init  xtlck->lwm.offset = XTENTRYSTART; */
 		tlck = txLock(tid, ip, mp, tlckXTREE | tlckNEW);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 
 		/* update the self address in the xtpage header */
 		pxd = &p->header.self;
@@ -3060,7 +3054,7 @@
 	else			/* (xtype  == XTPAGE) */
 		tlck = txMaplock(tid, ip, tlckMAP | tlckRELOCATE);
 
-	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock = (struct pxd_lock *) & tlck->lock;
 	pxdlock->flag = mlckFREEPXD;
 	PXDaddress(&pxdlock->pxd, oxaddr);
 	PXDlength(&pxdlock->pxd, xlen);
@@ -3076,7 +3070,7 @@
 	jEVENT(0, ("xtRelocate: update parent xad entry.\n"));
 	BT_MARK_DIRTY(pmp, ip);
 	tlck = txLock(tid, ip, pmp, tlckXTREE | tlckGROW);
-	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck = (struct xtlock *) & tlck->lock;
 
 	/* update the XAD with the new destination extent; */
 	xad = &pp->xad[index];
@@ -3113,17 +3107,17 @@
  *      the page containing the entry is pinned at exit.
  */
 static int xtSearchNode(struct inode *ip, xad_t * xad,	/* required XAD entry */
-			int *cmpp, btstack_t * btstack, int flag)
+			int *cmpp, struct btstack * btstack, int flag)
 {
 	int rc = 0;
 	s64 xoff, xaddr;
 	int xlen;
 	int cmp = 1;		/* init for empty page */
 	s64 bn;			/* block number */
-	metapage_t *mp;		/* meta-page buffer */
+	struct metapage *mp;	/* meta-page buffer */
 	xtpage_t *p;		/* page */
 	int base, index, lim;
-	btframe_t *btsp;
+	struct btframe *btsp;
 	s64 t64;
 
 	BT_CLR(btstack);
@@ -3233,9 +3227,9 @@
 static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * p)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	s64 nextbn, prevbn;
-	tlock_t *tlck;
+	struct tlock *tlck;
 
 	nextbn = le64_to_cpu(p->header.next);
 	prevbn = le64_to_cpu(p->header.prev);
@@ -3295,14 +3289,14 @@
 void xtInitRoot(tid_t tid, struct inode *ip)
 {
 	xtpage_t *p;
-	tlock_t *tlck;
+	struct tlock *tlck;
 
 	/*
 	 * acquire a transaction lock on the root
 	 *
 	 * action:
 	 */
-	tlck = txLock(tid, ip, (metapage_t *) &JFS_IP(ip)->bxflag,
+	tlck = txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
 		      tlckXTREE | tlckNEW);
 	p = &JFS_IP(ip)->i_xtroot;
 
@@ -3386,20 +3380,20 @@
 {
 	int rc = 0;
 	s64 teof;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	s64 bn;
 	int index, nextindex;
 	xad_t *xad;
 	s64 xoff, xaddr;
 	int xlen, len, freexlen;
-	btstack_t btstack;
-	btframe_t *parent;
-	tblock_t *tblk = 0;
-	tlock_t *tlck = 0;
-	xtlock_t *xtlck = 0;
-	xdlistlock_t xadlock;	/* maplock for COMMIT_WMAP */
-	pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+	struct btstack btstack;
+	struct btframe *parent;
+	struct tblock *tblk = 0;
+	struct tlock *tlck = 0;
+	struct xtlock *xtlck = 0;
+	struct xdlistlock xadlock;	/* maplock for COMMIT_WMAP */
+	struct pxd_lock *pxdlock;		/* maplock for COMMIT_WMAP */
 	s64 nfreed;
 	int freed, log;
 	int locked_leaves = 0;
@@ -3509,7 +3503,7 @@
 		}
 		tlck = txLock(tid, ip, mp, tlckXTREE);
 		tlck->type = tlckXTREE | tlckTRUNCATE;
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
 	}
 	BT_MARK_DIRTY(mp, ip);
@@ -3574,7 +3568,7 @@
 				xtlck->lwm.length = index + 1 -
 				    xtlck->lwm.offset;
 				xtlck->twm.offset = index;
-				pxdlock = (pxdlock_t *) & xtlck->pxdlock;
+				pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
 				pxdlock->flag = mlckFREEPXD;
 				PXDaddress(&pxdlock->pxd, xaddr);
 				PXDlength(&pxdlock->pxd, freexlen);
@@ -3582,7 +3576,7 @@
 			/* free truncated extent */
 			else {	/* COMMIT_WMAP */
 
-				pxdlock = (pxdlock_t *) & xadlock;
+				pxdlock = (struct pxd_lock *) & xadlock;
 				pxdlock->flag = mlckFREEPXD;
 				PXDaddress(&pxdlock->pxd, xaddr);
 				PXDlength(&pxdlock->pxd, freexlen);
@@ -3614,7 +3608,7 @@
 				xadlock.count =
 				    le16_to_cpu(p->header.nextindex) -
 				    nextindex;
-				txFreeMap(ip, (maplock_t *) & xadlock, 0,
+				txFreeMap(ip, (struct maplock *) & xadlock, 0,
 					  COMMIT_WMAP);
 			}
 			p->header.nextindex = cpu_to_le16(nextindex);
@@ -3644,7 +3638,7 @@
 		xadlock.xdlist = &p->xad[XTENTRYSTART];
 		xadlock.count =
 		    le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
-		txFreeMap(ip, (maplock_t *) & xadlock, 0, COMMIT_WMAP);
+		txFreeMap(ip, (struct maplock *) & xadlock, 0, COMMIT_WMAP);
 	}
 
 	if (p->header.flag & BT_ROOT) {
@@ -3704,7 +3698,7 @@
 				 * free child extents covered by parent [);
 				 */
 				tlck = txLock(tid, ip, mp, tlckXTREE);
-				xtlck = (xtlock_t *) & tlck->lock;
+				xtlck = (struct xtlock *) & tlck->lock;
 				if (!(tlck->type & tlckTRUNCATE)) {
 					xtlck->hwm.offset =
 					    le16_to_cpu(p->header.
@@ -3719,7 +3713,7 @@
 				xadlock.count =
 				    le16_to_cpu(p->header.nextindex) -
 				    index - 1;
-				txFreeMap(ip, (maplock_t *) & xadlock, 0,
+				txFreeMap(ip, (struct maplock *) & xadlock, 0,
 					  COMMIT_WMAP);
 			}
 			BT_MARK_DIRTY(mp, ip);
@@ -3751,7 +3745,7 @@
 	if (log && mp->lid && (tblk->last != mp->lid) &&
 	    lid_to_tlock(mp->lid)->tid) {
 		lid_t lid = mp->lid;
-		tlock_t *prev;
+		struct tlock *prev;
 
 		tlck = lid_to_tlock(lid);
 
@@ -3780,7 +3774,7 @@
 			 * invalidate parent if COMMIT_PWMAP;
 			 */
 			tlck = txLock(tid, ip, mp, tlckXTREE);
-			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck = (struct xtlock *) & tlck->lock;
 			xtlck->hwm.offset =
 			    le16_to_cpu(p->header.nextindex) - 1;
 			tlck->type = tlckXTREE | tlckFREE;
@@ -3791,7 +3785,7 @@
 			xadlock.count =
 			    le16_to_cpu(p->header.nextindex) -
 			    XTENTRYSTART;
-			txFreeMap(ip, (maplock_t *) & xadlock, 0,
+			txFreeMap(ip, (struct maplock *) & xadlock, 0,
 				  COMMIT_WMAP);
 		}
 		BT_MARK_DIRTY(mp, ip);
@@ -3919,20 +3913,20 @@
 s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
 {
 	s64 bn;
-	btstack_t btstack;
+	struct btstack btstack;
 	int cmp;
 	int index;
 	int locked_leaves = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
-	btframe_t *parent;
+	struct btframe *parent;
 	int rc;
-	tblock_t *tblk;
-	tlock_t *tlck = 0;
+	struct tblock *tblk;
+	struct tlock *tlck = 0;
 	xad_t *xad;
 	int xlen;
 	s64 xoff;
-	xtlock_t *xtlck = 0;
+	struct xtlock *xtlck = 0;
 
 	/* save object truncation type */
 	tblk = tid_to_tblock(tid);
@@ -3988,7 +3982,7 @@
 	}
 	tlck = txLock(tid, ip, mp, tlckXTREE);
 	tlck->type = tlckXTREE | tlckFREE;
-	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck = (struct xtlock *) & tlck->lock;
 	xtlck->hwm.offset = index;
 
 
@@ -4020,7 +4014,7 @@
 		 * invalidate parent if COMMIT_PWMAP;
 		 */
 		tlck = txLock(tid, ip, mp, tlckXTREE);
-		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck = (struct xtlock *) & tlck->lock;
 		xtlck->hwm.offset =
 		    le16_to_cpu(p->header.nextindex) - 1;
 		tlck->type = tlckXTREE | tlckFREE;
@@ -4074,14 +4068,14 @@
 int xtDisplayTree(struct inode *ip)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	xtpage_t *p;
 	s64 bn, pbn;
 	int index, lastindex, v, h;
 	xad_t *xad;
-	btstack_t btstack;
-	btframe_t *btsp;
-	btframe_t *parent;
+	struct btstack btstack;
+	struct btframe *btsp;
+	struct btframe *parent;
 
 	printk("display B+-tree.\n");
 
@@ -4195,7 +4189,7 @@
 int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p)
 {
 	int rc = 0;
-	metapage_t *mp;
+	struct metapage *mp;
 	xad_t *xad;
 	s64 xaddr, xoff;
 	int xlen, i, j;
@@ -4254,7 +4248,7 @@
 	u64 bn;
 	int index;
 	btentry_t *e;
-	btstack_t btstack;
+	struct btstack btstack;
 	struct btsf *parent;
 
 	/* clear stack */
diff -Nru a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
--- a/fs/jfs/jfs_xtree.h	Sun Sep 15 19:20:24 2002
+++ b/fs/jfs/jfs_xtree.h	Sun Sep 15 19:20:24 2002
@@ -64,11 +64,11 @@
 #define lengthXAD(xad)  __le24_to_cpu((xad)->len)
 
 /* xad list */
-typedef struct {
+struct xadlist {
 	s16 maxnxad;
 	s16 nxad;
 	xad_t *xad;
-} xadlist_t;
+};
 
 /* xad_t flags */
 #define XAD_NEW         0x01	/* new */
@@ -110,8 +110,8 @@
  */
 extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
 		    int *pflag, s64 * paddr, int *plen, int flag);
-extern int xtLookupList(struct inode *ip, lxdlist_t * lxdlist,
-			xadlist_t * xadlist, int flag);
+extern int xtLookupList(struct inode *ip, struct lxdlist * lxdlist,
+			struct xadlist * xadlist, int flag);
 extern void xtInitRoot(tid_t tid, struct inode *ip);
 extern int xtInsert(tid_t tid, struct inode *ip,
 		    int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Sun Sep 15 19:20:14 2002
+++ b/fs/jfs/namei.c	Sun Sep 15 19:20:14 2002
@@ -63,10 +63,10 @@
 	tid_t tid;		/* transaction id */
 	struct inode *ip = NULL;	/* child directory inode */
 	ino_t ino;
-	component_t dname;	/* child directory name */
-	btstack_t btstack;
+	struct component_name dname;	/* child directory name */
+	struct btstack btstack;
 	struct inode *iplist[2];
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name));
 
@@ -178,10 +178,10 @@
 	tid_t tid;		/* transaction id */
 	struct inode *ip = NULL;	/* child directory inode */
 	ino_t ino;
-	component_t dname;	/* child directory name */
-	btstack_t btstack;
+	struct component_name dname;	/* child directory name */
+	struct btstack btstack;
 	struct inode *iplist[2];
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
 
@@ -306,9 +306,9 @@
 	tid_t tid;		/* transaction id */
 	struct inode *ip = dentry->d_inode;
 	ino_t ino;
-	component_t dname;
+	struct component_name dname;
 	struct inode *iplist[2];
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
 
@@ -429,9 +429,9 @@
 	tid_t tid;		/* transaction id */
 	struct inode *ip = dentry->d_inode;
 	ino_t ino;
-	component_t dname;	/* object name */
+	struct component_name dname;	/* object name */
 	struct inode *iplist[2];
-	tblock_t *tblk;
+	struct tblock *tblk;
 	s64 new_size = 0;
 	int commit_flag;
 
@@ -580,7 +580,7 @@
 s64 commitZeroLink(tid_t tid, struct inode *ip)
 {
 	int filetype;
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	jFYI(1, ("commitZeroLink: tid = %d, ip = 0x%p\n", tid, ip));
 
@@ -675,15 +675,15 @@
 	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
 		s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
 		int xlen = lengthDXD(&JFS_IP(ip)->ea);
-		maplock_t maplock;	/* maplock for COMMIT_WMAP */
-		pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+		struct maplock maplock;	/* maplock for COMMIT_WMAP */
+		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
 
 		/* free EA pages from cache */
 		invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
 
 		/* free EA extent from working block map */
 		maplock.index = 1;
-		pxdlock = (pxdlock_t *) & maplock;
+		pxdlock = (struct pxd_lock *) & maplock;
 		pxdlock->flag = mlckFREEPXD;
 		PXDaddress(&pxdlock->pxd, xaddr);
 		PXDlength(&pxdlock->pxd, xlen);
@@ -696,14 +696,14 @@
 	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
 		s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
 		int xlen = lengthDXD(&JFS_IP(ip)->acl);
-		maplock_t maplock;	/* maplock for COMMIT_WMAP */
-		pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+		struct maplock maplock;	/* maplock for COMMIT_WMAP */
+		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
 
 		invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
 
 		/* free ACL extent from working block map */
 		maplock.index = 1;
-		pxdlock = (pxdlock_t *) & maplock;
+		pxdlock = (struct pxd_lock *) & maplock;
 		pxdlock->flag = mlckFREEPXD;
 		PXDaddress(&pxdlock->pxd, xaddr);
 		PXDlength(&pxdlock->pxd, xlen);
@@ -752,8 +752,8 @@
 	tid_t tid;
 	struct inode *ip = old_dentry->d_inode;
 	ino_t ino;
-	component_t dname;
-	btstack_t btstack;
+	struct component_name dname;
+	struct btstack btstack;
 	struct inode *iplist[2];
 
 	jFYI(1,
@@ -830,17 +830,17 @@
 	int rc;
 	tid_t tid;
 	ino_t ino = 0;
-	component_t dname;
+	struct component_name dname;
 	int ssize;		/* source pathname size */
-	btstack_t btstack;
+	struct btstack btstack;
 	struct inode *ip = dentry->d_inode;
 	unchar *i_fastsymlink;
 	s64 xlen = 0;
 	int bmask = 0, xsize;
 	s64 xaddr;
-	metapage_t *mp;
+	struct metapage *mp;
 	struct super_block *sb;
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	struct inode *iplist[2];
 
@@ -1030,20 +1030,20 @@
 int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	       struct inode *new_dir, struct dentry *new_dentry)
 {
-	btstack_t btstack;
+	struct btstack btstack;
 	ino_t ino;
-	component_t new_dname;
+	struct component_name new_dname;
 	struct inode *new_ip;
-	component_t old_dname;
+	struct component_name old_dname;
 	struct inode *old_ip;
 	int rc;
 	tid_t tid;
-	tlock_t *tlck;
-	dtlock_t *dtlck;
-	lv_t *lv;
+	struct tlock *tlck;
+	struct dt_lock *dtlck;
+	struct lv *lv;
 	int ipcount;
 	struct inode *iplist[4];
-	tblock_t *tblk;
+	struct tblock *tblk;
 	s64 new_size = 0;
 	int commit_flag;
 
@@ -1194,11 +1194,11 @@
 
 			/* Linelock header of dtree */
 			tlck = txLock(tid, old_ip,
-				      (metapage_t *) & JFS_IP(old_ip)->bxflag,
+				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
 				      tlckDTREE | tlckBTROOT);
-			dtlck = (dtlock_t *) & tlck->lock;
+			dtlck = (struct dt_lock *) & tlck->lock;
 			ASSERT(dtlck->index == 0);
-			lv = (lv_t *) & dtlck->lv[0];
+			lv = & dtlck->lv[0];
 			lv->offset = 0;
 			lv->length = 1;
 			dtlck->index++;
@@ -1301,14 +1301,14 @@
  */
 int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
-	btstack_t btstack;
-	component_t dname;
+	struct btstack btstack;
+	struct component_name dname;
 	ino_t ino;
 	struct inode *ip;
 	struct inode *iplist[2];
 	int rc;
 	tid_t tid;
-	tblock_t *tblk;
+	struct tblock *tblk;
 
 	jFYI(1, ("jfs_mknod: %s\n", dentry->d_name.name));
 
@@ -1371,10 +1371,10 @@
 
 static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry)
 {
-	btstack_t btstack;
+	struct btstack btstack;
 	ino_t inum;
 	struct inode *ip;
-	component_t key;
+	struct component_name key;
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
 	int rc;
diff -Nru a/fs/jfs/resize.c b/fs/jfs/resize.c
--- a/fs/jfs/resize.c	Sun Sep 15 19:19:58 2002
+++ b/fs/jfs/resize.c	Sun Sep 15 19:19:58 2002
@@ -65,8 +65,8 @@
 	struct inode *ipbmap = sbi->ipbmap;
 	struct inode *ipbmap2;
 	struct inode *ipimap = sbi->ipimap;
-	log_t *log = sbi->log;
-	bmap_t *bmp = sbi->bmap;
+	struct jfs_log *log = sbi->log;
+	struct bmap *bmp = sbi->bmap;
 	s64 newLogAddress, newFSCKAddress;
 	int newFSCKSize;
 	s64 newMapSize = 0, mapSize;
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Sun Sep 15 19:19:37 2002
+++ b/fs/jfs/super.c	Sun Sep 15 19:19:37 2002
@@ -101,7 +101,7 @@
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	s64 maxinodes;
-	imap_t *imap = JFS_IP(sbi->ipimap)->i_imap;
+	struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
 
 	jFYI(1, ("In jfs_statfs\n"));
 	buf->f_type = JFS_SUPER_MAGIC;
@@ -337,7 +337,7 @@
 static void jfs_write_super_lockfs(struct super_block *sb)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
-	log_t *log = sbi->log;
+	struct jfs_log *log = sbi->log;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		txQuiesce(sb);
@@ -348,7 +348,7 @@
 static void jfs_unlockfs(struct super_block *sb)
 {
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
-	log_t *log = sbi->log;
+	struct jfs_log *log = sbi->log;
 	int rc = 0;
 
 	if (!(sb->s_flags & MS_RDONLY)) {
diff -Nru a/fs/jfs/xattr.c b/fs/jfs/xattr.c
--- a/fs/jfs/xattr.c	Sun Sep 15 19:19:34 2002
+++ b/fs/jfs/xattr.c	Sun Sep 15 19:19:34 2002
@@ -174,7 +174,7 @@
 	char *cp;
 	s32 nbytes, nb;
 	s32 bytes_to_write;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	/*
 	 * Quick check to see if this is an in-linable EA.  Short EAs
@@ -247,7 +247,7 @@
 
 	/* Free up INLINE area */
 	if (ji->ea.flag & DXD_INLINE)
-		ip->i_mode |= INLINEEA;
+		ji->mode2 |= INLINEEA;
 
 	return 0;
 
@@ -311,7 +311,7 @@
 	int i;
 	int nbytes, nb;
 	s32 bytes_to_read;
-	metapage_t *mp;
+	struct metapage *mp;
 
 	/* quick check for in-line EA */
 	if (ji->ea.flag & DXD_INLINE)
@@ -577,10 +577,24 @@
 	return rc;
 }
 
-int jfs_setxattr(struct dentry *dentry, const char *name,
-		 void *value, size_t value_len, int flags)
+static int can_set_xattr(struct inode *inode, const char *name)
+{
+	if (IS_RDONLY(inode))
+		return -EROFS;
+
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
+		return -EPERM;
+
+	if (!S_ISREG(inode->i_mode) &&
+	    (!S_ISDIR(inode->i_mode) || inode->i_mode &S_ISVTX))
+		return -EPERM;
+
+	return permission(inode, MAY_WRITE);
+}
+
+int __jfs_setxattr(struct inode *inode, const char *name, void *value,
+		   size_t value_len, int flags)
 {
-	struct inode *inode = dentry->d_inode;
 	struct jfs_ea_list *ealist;
 	struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL;
 	struct ea_buffer ea_buf;
@@ -589,18 +603,16 @@
 	int new_size;
 	int namelen = strlen(name);
 	int found = 0;
-	int rc = 0;
+	int rc;
 	int length;
 
-	if (!value)
-		value_len = 0;
-
-	IWRITE_LOCK(inode);
+	if ((rc = can_set_xattr(inode, name)))
+		return rc;
 
 	xattr_size = ea_get(inode, &ea_buf, 0);
 	if (xattr_size < 0) {
 		rc = xattr_size;
-		goto unlock;
+		goto out;
 	}
 
       again:
@@ -630,12 +642,12 @@
 			rc = -ENODATA;
 			goto release;
 		}
-		if (value_len == 0) {
+		if (value == NULL) {
 			rc = 0;
 			goto release;
 		}
 	}
-	if (value_len)
+	if (value)
 		new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len;
 
 	if (new_size > ea_buf.max_size) {
@@ -647,7 +659,7 @@
 		xattr_size = ea_get(inode, &ea_buf, new_size);
 		if (xattr_size < 0) {
 			rc = xattr_size;
-			goto unlock;
+			goto out;
 		}
 		goto again;
 	}
@@ -662,7 +674,7 @@
 	}
 
 	/* Add new entry to the end */
-	if (value_len) {
+	if (value) {
 		if (xattr_size == 0)
 			/* Completely new ea list */
 			xattr_size = sizeof (struct jfs_ea_list);
@@ -673,7 +685,8 @@
 		ea->valuelen = (cpu_to_le16(value_len));
 		memcpy(ea->name, name, namelen);
 		ea->name[namelen] = 0;
-		memcpy(&ea->name[namelen + 1], value, value_len);
+		if (value_len)
+			memcpy(&ea->name[namelen + 1], value, value_len);
 		xattr_size += EA_SIZE(ea);
 	}
 
@@ -683,46 +696,66 @@
 		       "jfs_xsetattr: xattr_size = %d, new_size = %d\n",
 		       xattr_size, new_size);
 
-		rc = EINVAL;
+		rc = -EINVAL;
 		goto release;
 	}
 
+	/*
+	 * If we're left with an empty list, there's no ea
+	 */
+	if (new_size == sizeof (struct jfs_ea_list))
+		new_size = 0;
+
 	ealist->size = cpu_to_le32(new_size);
 
 	rc = ea_put(inode, &ea_buf, new_size);
 
-	goto unlock;
+	goto out;
       release:
 	ea_release(inode, &ea_buf);
-      unlock:
-	IWRITE_UNLOCK(inode);
+      out:
 	return rc;
 }
 
-ssize_t jfs_getxattr(struct dentry * dentry, const char *name,
-		     void *data, size_t buf_size)
+int jfs_setxattr(struct dentry *dentry, const char *name, void *value,
+		 size_t value_len, int flags)
+{
+	if (value == NULL) {	/* empty EA, do not remove */
+		value = "";
+		value_len = 0;
+	}
+
+	return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags);
+}
+
+static int can_get_xattr(struct inode *inode, const char *name)
+{
+	return permission(inode, MAY_READ);
+}
+
+ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
+		       size_t buf_size)
 {
-	struct inode *inode = dentry->d_inode;
 	struct jfs_ea_list *ealist;
 	struct jfs_ea *ea;
 	struct ea_buffer ea_buf;
 	int xattr_size;
 	ssize_t size;
 	int namelen = strlen(name);
+	int rc;
 	char *value;
 
-	IREAD_LOCK(inode);
+	if ((rc = can_get_xattr(inode, name)))
+		return rc;
 
 	xattr_size = ea_get(inode, &ea_buf, 0);
 	if (xattr_size < 0) {
 		size = xattr_size;
-		goto unlock;
+		goto out;
 	}
 
-	if (xattr_size == 0) {
-		size = 0;
-		goto release;
-	}
+	if (xattr_size == 0)
+		goto not_found;
 
 	ealist = (struct jfs_ea_list *) ea_buf.xattr;
 
@@ -742,16 +775,21 @@
 			memcpy(data, value, size);
 			goto release;
 		}
-	/* not found */
+      not_found:
 	size = -ENODATA;
       release:
 	ea_release(inode, &ea_buf);
-      unlock:
-	IREAD_UNLOCK(inode);
+      out:
 
 	return size;
 }
 
+ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
+		     size_t buf_size)
+{
+	return __jfs_getxattr(dentry->d_inode, name, data, buf_size);
+}
+
 ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
 {
 	struct inode *inode = dentry->d_inode;
@@ -762,12 +800,10 @@
 	struct jfs_ea *ea;
 	struct ea_buffer ea_buf;
 
-	IREAD_LOCK(inode);
-
 	xattr_size = ea_get(inode, &ea_buf, 0);
 	if (xattr_size < 0) {
 		size = xattr_size;
-		goto unlock;
+		goto out;
 	}
 
 	if (xattr_size == 0)
@@ -797,12 +833,11 @@
 
       release:
 	ea_release(inode, &ea_buf);
-      unlock:
-	IREAD_UNLOCK(inode);
+      out:
 	return size;
 }
 
 int jfs_removexattr(struct dentry *dentry, const char *name)
 {
-	return jfs_setxattr(dentry, name, 0, 0, XATTR_REPLACE);
+	return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE);
 }
diff -Nru a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
--- a/fs/lockd/clntlock.c	Sun Sep 15 19:20:24 2002
+++ b/fs/lockd/clntlock.c	Sun Sep 15 19:20:24 2002
@@ -188,7 +188,7 @@
 		nlmclnt_prepare_reclaim(host, newstate);
 		nlm_get_host(host);
 		MOD_INC_USE_COUNT;
-		kernel_thread(reclaimer, host, CLONE_SIGNAL);
+		kernel_thread(reclaimer, host, CLONE_KERNEL);
 	}
 }
 
diff -Nru a/fs/lockd/host.c b/fs/lockd/host.c
--- a/fs/lockd/host.c	Sun Sep 15 19:19:50 2002
+++ b/fs/lockd/host.c	Sun Sep 15 19:19:50 2002
@@ -22,7 +22,6 @@
 #define NLM_HOST_MAX		64
 #define NLM_HOST_NRHASH		32
 #define NLM_ADDRHASH(addr)	(ntohl(addr) & (NLM_HOST_NRHASH-1))
-#define NLM_PTRHASH(ptr)	((((u32)(unsigned long) ptr) / 32) & (NLM_HOST_NRHASH-1))
 #define NLM_HOST_REBIND		(60 * HZ)
 #define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
 #define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
@@ -42,7 +41,7 @@
 struct nlm_host *
 nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
 {
-	return nlm_lookup_host(NULL, sin, proto, version);
+	return nlm_lookup_host(0, sin, proto, version);
 }
 
 /*
@@ -51,45 +50,25 @@
 struct nlm_host *
 nlmsvc_lookup_host(struct svc_rqst *rqstp)
 {
-	return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr,
+	return nlm_lookup_host(1, &rqstp->rq_addr,
 			       rqstp->rq_prot, rqstp->rq_vers);
 }
 
 /*
- * Match the given host against client/address
- */
-static inline int
-nlm_match_host(struct nlm_host *host, struct svc_client *clnt,
-					struct sockaddr_in *sin)
-{
-	if (clnt)
-		return host->h_exportent == clnt;
-	return nlm_cmp_addr(&host->h_addr, sin);
-}
-
-/*
  * Common host lookup routine for server & client
  */
 struct nlm_host *
-nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
+nlm_lookup_host(int server, struct sockaddr_in *sin,
 					int proto, int version)
 {
 	struct nlm_host	*host, **hp;
 	u32		addr;
 	int		hash;
 
-	if (!clnt && !sin) {
-		printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
-		return NULL;
-	}
-
 	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
 			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
 
-	if (clnt)
-		hash = NLM_PTRHASH(clnt);
-	else
-		hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
+	hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
 
 	/* Lock hash table */
 	down(&nlm_host_sema);
@@ -98,12 +77,14 @@
 		nlm_gc_hosts();
 
 	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
-		if (proto && host->h_proto != proto)
+		if (host->h_proto != proto)
+			continue;
+		if (host->h_version != version)
 			continue;
-		if (version && host->h_version != version)
+		if (host->h_server != server)
 			continue;
 
-		if (nlm_match_host(host, clnt, sin)) {
+		if (nlm_cmp_addr(&host->h_addr, sin)) {
 			if (hp != nlm_hosts + hash) {
 				*hp = host->h_next;
 				host->h_next = nlm_hosts[hash];
@@ -115,10 +96,6 @@
 		}
 	}
 
-	/* special hack for nlmsvc_invalidate_client */
-	if (sin == NULL)
-		goto nohost;
-
 	/* Ooops, no host found, create it */
 	dprintk("lockd: creating host entry\n");
 
@@ -146,8 +123,7 @@
 	init_waitqueue_head(&host->h_gracewait);
 	host->h_state      = 0;			/* pseudo NSM state */
 	host->h_nsmstate   = 0;			/* real NSM state */
-	host->h_exportent  = clnt;
-
+	host->h_server	   = server;
 	host->h_next       = nlm_hosts[hash];
 	nlm_hosts[hash]    = host;
 
@@ -159,6 +135,30 @@
 	return host;
 }
 
+struct nlm_host *
+nlm_find_client(void)
+{
+	/* find a nlm_host for a client for which h_killed == 0.
+	 * and return it
+	 */
+	int hash;
+	down(&nlm_host_sema);
+	for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
+		struct nlm_host *host, **hp;
+		for (hp = &nlm_hosts[hash]; (host = *hp) ; hp = &host->h_next) {
+			if (host->h_server &&
+			    host->h_killed == 0) {
+				nlm_get_host(host);
+				up(&nlm_host_sema);
+				return host;
+			}
+		}
+	}
+	up(&nlm_host_sema);
+	return NULL;
+}
+
+				
 /*
  * Create the NLM RPC client for an NLM peer
  */
diff -Nru a/fs/lockd/lockd_syms.c b/fs/lockd/lockd_syms.c
--- a/fs/lockd/lockd_syms.c	Sun Sep 15 19:19:50 2002
+++ b/fs/lockd/lockd_syms.c	Sun Sep 15 19:19:50 2002
@@ -32,7 +32,6 @@
 EXPORT_SYMBOL(nlmclnt_proc);
 
 /* NFS server entry points/hooks */
-EXPORT_SYMBOL(nlmsvc_invalidate_client);
 EXPORT_SYMBOL(nlmsvc_ops);
 
 #endif /* CONFIG_MODULES */
diff -Nru a/fs/lockd/mon.c b/fs/lockd/mon.c
--- a/fs/lockd/mon.c	Sun Sep 15 19:19:29 2002
+++ b/fs/lockd/mon.c	Sun Sep 15 19:19:29 2002
@@ -42,6 +42,7 @@
 		goto out;
 
 	args.addr = host->h_addr.sin_addr.s_addr;
+	args.proto= (host->h_proto<<1) | host->h_server;
 	args.prog = NLM_PROGRAM;
 	args.vers = host->h_version;
 	args.proc = NLMPROC_NSM_NOTIFY;
@@ -167,8 +168,8 @@
 	/* This is the private part. Needed only for SM_MON call */
 	if (rqstp->rq_task->tk_msg.rpc_proc == SM_MON) {
 		*p++ = argp->addr;
-		*p++ = 0;
-		*p++ = 0;
+		*p++ = argp->vers;
+		*p++ = argp->proto;
 		*p++ = 0;
 	}
 
@@ -206,61 +207,60 @@
 
 static struct rpc_procinfo	nsm_procedures[] = {
         {
-		p_procname:	"sm_null",
-		p_encode:	(kxdrproc_t) xdr_error,
-		p_decode:	(kxdrproc_t) xdr_error,
+		.p_procname	= "sm_null",
+		.p_encode	= (kxdrproc_t) xdr_error,
+		.p_decode	= (kxdrproc_t) xdr_error,
 	},
         {
-		p_procname:	"sm_stat",
-		p_encode:	(kxdrproc_t) xdr_error,
-		p_decode:	(kxdrproc_t) xdr_error,
+		.p_procname	= "sm_stat",
+		.p_encode	= (kxdrproc_t) xdr_error,
+		.p_decode	= (kxdrproc_t) xdr_error,
 	},
         {
-		p_procname:	"sm_mon",
-		p_encode:	(kxdrproc_t) xdr_encode_mon,
-		p_decode:	(kxdrproc_t) xdr_decode_stat_res,
-		p_bufsiz:	MAX(SM_mon_sz, SM_monres_sz) << 2,
+		.p_procname	= "sm_mon",
+		.p_encode	= (kxdrproc_t) xdr_encode_mon,
+		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
+		.p_bufsiz	= MAX(SM_mon_sz, SM_monres_sz) << 2,
 	},
         {
-		p_procname:	"sm_unmon",
-		p_encode:	(kxdrproc_t) xdr_encode_mon,
-		p_decode:	(kxdrproc_t) xdr_decode_stat,
-		p_bufsiz:	MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
+		.p_procname	= "sm_unmon",
+		.p_encode	= (kxdrproc_t) xdr_encode_mon,
+		.p_decode	= (kxdrproc_t) xdr_decode_stat,
+		.p_bufsiz	= MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
 	},
         {
-		p_procname:	"sm_unmon_all",
-		p_encode:	(kxdrproc_t) xdr_error,
-		p_decode:	(kxdrproc_t) xdr_error,
+		.p_procname	= "sm_unmon_all",
+		.p_encode	= (kxdrproc_t) xdr_error,
+		.p_decode	= (kxdrproc_t) xdr_error,
 	},
         {
-		p_procname:	"sm_simu_crash",
-		p_encode:	(kxdrproc_t) xdr_error,
-		p_decode:	(kxdrproc_t) xdr_error, 0, 0
+		.p_procname	= "sm_simu_crash",
+		.p_encode	= (kxdrproc_t) xdr_error,
+		.p_decode	= (kxdrproc_t) xdr_error,
 	},
         {
-		p_procname:	"sm_notify",
-		p_encode:	(kxdrproc_t) xdr_error,
-		p_decode:	(kxdrproc_t) xdr_error,
+		.p_procname	= "sm_notify",
+		.p_encode	= (kxdrproc_t) xdr_error,
+		.p_decode	= (kxdrproc_t) xdr_error,
 	},
 };
 
 static struct rpc_version	nsm_version1 = {
-		number:		1, 
-		nrprocs:	sizeof(nsm_procedures)/sizeof(nsm_procedures[0]),
-		procs:		nsm_procedures
+		.number		= 1, 
+		.nrprocs	= sizeof(nsm_procedures)/sizeof(nsm_procedures[0]),
+		.procs		= nsm_procedures
 };
 
 static struct rpc_version *	nsm_version[] = {
-	NULL,
-	&nsm_version1,
+	[1] = &nsm_version1,
 };
 
 static struct rpc_stat		nsm_stats;
 
 struct rpc_program		nsm_program = {
-		name:		"statd",
-		number:		SM_PROGRAM,
-		nrvers:		sizeof(nsm_version)/sizeof(nsm_version[0]),
-		version:	nsm_version,
-		stats:		&nsm_stats
+		.name		= "statd",
+		.number		= SM_PROGRAM,
+		.nrvers		= sizeof(nsm_version)/sizeof(nsm_version[0]),
+		.version	= nsm_version,
+		.stats		= &nsm_stats
 };
diff -Nru a/fs/lockd/svc.c b/fs/lockd/svc.c
--- a/fs/lockd/svc.c	Sun Sep 15 19:19:56 2002
+++ b/fs/lockd/svc.c	Sun Sep 15 19:19:56 2002
@@ -130,7 +130,7 @@
 			flush_signals(current);
 			spin_unlock_irq(&current->sigmask_lock);
 			if (nlmsvc_ops) {
-				nlmsvc_ops->detach();
+				nlmsvc_invalidate_all();
 				grace_period_expire = set_grace_period();
 			}
 		}
@@ -163,22 +163,8 @@
 		dprintk("lockd: request from %08x\n",
 			(unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
 
-		/*
-		 * Look up the NFS client handle. The handle is needed for
-		 * all but the GRANTED callback RPCs.
-		 */
-		rqstp->rq_client = NULL;
-		if (nlmsvc_ops) {
-			nlmsvc_ops->exp_readlock();
-			rqstp->rq_client =
-				nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
-		}
-
 		svc_process(serv, rqstp);
 
-		/* Unlock export hash tables */
-		if (nlmsvc_ops)
-			nlmsvc_ops->exp_unlock();
 	}
 
 	/*
@@ -187,7 +173,7 @@
 	 */
 	if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
 		if (nlmsvc_ops)
-			nlmsvc_ops->detach();
+			nlmsvc_invalidate_all();
 		nlm_shutdown_hosts();
 		nlmsvc_pid = 0;
 	} else
@@ -369,29 +355,27 @@
  * Define NLM program and procedures
  */
 static struct svc_version	nlmsvc_version1 = {
-		vs_vers:	1,
-		vs_nproc:	17,
-		vs_proc:	nlmsvc_procedures,
+		.vs_vers	= 1,
+		.vs_nproc	= 17,
+		.vs_proc	= nlmsvc_procedures,
 };
 static struct svc_version	nlmsvc_version3 = {
-		vs_vers:	3,
-		vs_nproc:	24,
-		vs_proc:	nlmsvc_procedures,
+		.vs_vers	= 3,
+		.vs_nproc	= 24,
+		.vs_proc	= nlmsvc_procedures,
 };
 #ifdef CONFIG_LOCKD_V4
 static struct svc_version	nlmsvc_version4 = {
-		vs_vers:	4,
-		vs_nproc:	24,
-		vs_proc:	nlmsvc_procedures4,
+		.vs_vers	= 4,
+		.vs_nproc	= 24,
+		.vs_proc	= nlmsvc_procedures4,
 };
 #endif
 static struct svc_version *	nlmsvc_version[] = {
-	NULL,
-	&nlmsvc_version1,
-	NULL,
-	&nlmsvc_version3,
+	[1] = &nlmsvc_version1,
+	[3] = &nlmsvc_version3,
 #ifdef CONFIG_LOCKD_V4
-	&nlmsvc_version4,
+	[4] = &nlmsvc_version4,
 #endif
 };
 
@@ -399,11 +383,11 @@
 
 #define NLM_NRVERS	(sizeof(nlmsvc_version)/sizeof(nlmsvc_version[0]))
 struct svc_program	nlmsvc_program = {
-	pg_prog:	NLM_PROGRAM,		/* program number */
-	pg_lovers:	1,			// version
-	pg_hivers:	NLM_NRVERS-1,		// range
-	pg_nvers:	NLM_NRVERS,		/* number of entries in nlmsvc_version */
-	pg_vers:	nlmsvc_version,		/* version table */
-	pg_name:	"lockd",		/* service name */
-	pg_stats:	&nlmsvc_stats,		/* stats table */
+	.pg_prog	= NLM_PROGRAM,		/* program number */
+	.pg_lovers	= 1,			/* version */
+	.pg_hivers	= NLM_NRVERS-1,		/* range */
+	.pg_nvers	= NLM_NRVERS,		/* number of entries in nlmsvc_version */
+	.pg_vers	= nlmsvc_version,	/* version table */
+	.pg_name	= "lockd",		/* service name */
+	.pg_stats	= &nlmsvc_stats,	/* stats table */
 };
diff -Nru a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
--- a/fs/lockd/svc4proc.c	Sun Sep 15 19:19:34 2002
+++ b/fs/lockd/svc4proc.c	Sun Sep 15 19:19:34 2002
@@ -40,15 +40,6 @@
 	if (!nlmsvc_ops)
 		return nlm_lck_denied_nolocks;
 
-	/* Obtain handle for client host */
-	if (rqstp->rq_client == NULL) {
-		printk(KERN_NOTICE
-			"lockd: unauthenticated request from (%08x:%d)\n",
-			ntohl(rqstp->rq_addr.sin_addr.s_addr),
-			ntohs(rqstp->rq_addr.sin_port));
-		return nlm_lck_denied_nolocks;
-	}
-
 	/* Obtain host handle */
 	if (!(host = nlmsvc_lookup_host(rqstp))
 	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
@@ -420,8 +411,9 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
-	int			vers = rqstp->rq_vers;
-	int			prot = rqstp->rq_prot;
+	int			vers = argp->vers;
+	int			prot = argp->proto >> 1;
+
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -438,24 +430,20 @@
 	 * reclaim all locks we hold on this server.
 	 */
 	saddr.sin_addr.s_addr = argp->addr;
-	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
-		nlmclnt_recovery(host, argp->state);
-		nlm_release_host(host);
-	}
 
-	/* If we run on an NFS server, delete all locks held by the client */
-	if (nlmsvc_ops != NULL) {
-		struct svc_client	*clnt;
-		saddr.sin_addr.s_addr = argp->addr;
-		nlmsvc_ops->exp_readlock();
-		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+	if ((argp->proto & 1)==0) {
+		if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
+			nlmclnt_recovery(host, argp->state);
+			nlm_release_host(host);
+		}
+	} else {
+		/* If we run on an NFS server, delete all locks held by the client */
+
+		if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
 			nlmsvc_free_host_resources(host);
+			nlm_release_host(host);
 		}
-		nlm_release_host(host);
-		nlmsvc_ops->exp_unlock();
 	}
-
 	return rpc_success;
 }
 
@@ -527,15 +515,13 @@
 struct nlm_void			{ int dummy; };
 
 #define PROC(name, xargt, xrest, argt, rest, respsize)	\
- { (svc_procfunc) nlm4svc_proc_##name,	\
-   (kxdrproc_t) nlm4svc_decode_##xargt,	\
-   (kxdrproc_t) nlm4svc_encode_##xrest,	\
-   NULL,				\
-   sizeof(struct nlm_##argt),		\
-   sizeof(struct nlm_##rest),		\
-   0,					\
-   0,					\
-   respsize,				\
+ { .pc_func	= (svc_procfunc) nlm4svc_proc_##name,	\
+   .pc_decode	= (kxdrproc_t) nlm4svc_decode_##xargt,	\
+   .pc_encode	= (kxdrproc_t) nlm4svc_encode_##xrest,	\
+   .pc_release	= NULL,					\
+   .pc_argsize	= sizeof(struct nlm_##argt),		\
+   .pc_ressize	= sizeof(struct nlm_##rest),		\
+   .pc_xdrressize = respsize,				\
  }
 #define	Ck	(1+8)	/* cookie */
 #define	No	(1+1024/4)	/* netobj */
diff -Nru a/fs/lockd/svclock.c b/fs/lockd/svclock.c
--- a/fs/lockd/svclock.c	Sun Sep 15 19:19:29 2002
+++ b/fs/lockd/svclock.c	Sun Sep 15 19:19:29 2002
@@ -237,17 +237,8 @@
 
 	/* Remove block from list */
 	nlmsvc_remove_block(block);
-
-	/* If granted, unlock it, else remove from inode block list */
-	if (unlock && block->b_granted) {
-		dprintk("lockd: deleting granted lock\n");
-		fl->fl_type = F_UNLCK;
-		posix_lock_file(&block->b_file->f_file, fl, 0);
-		block->b_granted = 0;
-	} else {
-		dprintk("lockd: unblocking blocked lock\n");
-		posix_unblock_lock(fl);
-	}
+	posix_unblock_lock(&file->f_file, fl);
+	block->b_granted = 0;
 
 	/* If the block is in the middle of a GRANT callback,
 	 * don't kill it yet. */
@@ -324,7 +315,7 @@
 
 again:
 	if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
-		error = posix_lock_file(&file->f_file, &lock->fl, 0);
+		error = posix_lock_file(&file->f_file, &lock->fl);
 
 		if (block)
 			nlmsvc_delete_block(block, 0);
@@ -428,7 +419,7 @@
 	nlmsvc_cancel_blocked(file, lock);
 
 	lock->fl.fl_type = F_UNLCK;
-	error = posix_lock_file(&file->f_file, &lock->fl, 0);
+	error = posix_lock_file(&file->f_file, &lock->fl);
 
 	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
 }
@@ -532,7 +523,7 @@
 	 * following yields an error, this is most probably due to low
 	 * memory. Retry the lock in a few seconds.
 	 */
-	if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
+	if ((error = posix_lock_file(&file->f_file, &lock->fl)) < 0) {
 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 				-error, __FUNCTION__);
 		nlmsvc_insert_block(block, 10 * HZ);
diff -Nru a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
--- a/fs/lockd/svcproc.c	Sun Sep 15 19:20:00 2002
+++ b/fs/lockd/svcproc.c	Sun Sep 15 19:20:00 2002
@@ -69,15 +69,6 @@
 	if (!nlmsvc_ops)
 		return nlm_lck_denied_nolocks;
 
-	/* Obtain handle for client host */
-	if (rqstp->rq_client == NULL) {
-		printk(KERN_NOTICE
-			"lockd: unauthenticated request from (%08x:%d)\n",
-			ntohl(rqstp->rq_addr.sin_addr.s_addr),
-			ntohs(rqstp->rq_addr.sin_port));
-		return nlm_lck_denied_nolocks;
-	}
-
 	/* Obtain host handle */
 	if (!(host = nlmsvc_lookup_host(rqstp))
 	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
@@ -448,8 +439,8 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
-	int			vers = rqstp->rq_vers;
-	int			prot = rqstp->rq_prot;
+	int			vers = argp->vers;
+	int			prot = argp->proto >> 1;
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -466,22 +457,17 @@
 	 * reclaim all locks we hold on this server.
 	 */
 	saddr.sin_addr.s_addr = argp->addr;
-	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
-		nlmclnt_recovery(host, argp->state);
-		nlm_release_host(host);
-	}
-
-	/* If we run on an NFS server, delete all locks held by the client */
-	if (nlmsvc_ops != NULL) {
-		struct svc_client	*clnt;
-		saddr.sin_addr.s_addr = argp->addr;	
-		nlmsvc_ops->exp_readlock();
-		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+	if ((argp->proto & 1)==0) {
+		if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
+			nlmclnt_recovery(host, argp->state);
+			nlm_release_host(host);
+		}
+	} else {
+		/* If we run on an NFS server, delete all locks held by the client */
+		if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
 			nlmsvc_free_host_resources(host);
+			nlm_release_host(host);
 		}
-		nlm_release_host(host);
-		nlmsvc_ops->exp_unlock();
 	}
 
 	return rpc_success;
@@ -555,15 +541,13 @@
 struct nlm_void			{ int dummy; };
 
 #define PROC(name, xargt, xrest, argt, rest, respsize)	\
- { (svc_procfunc) nlmsvc_proc_##name,	\
-   (kxdrproc_t) nlmsvc_decode_##xargt,	\
-   (kxdrproc_t) nlmsvc_encode_##xrest,	\
-   NULL,				\
-   sizeof(struct nlm_##argt),		\
-   sizeof(struct nlm_##rest),		\
-   0,					\
-   0,					\
-   respsize,				\
+ { .pc_func	= (svc_procfunc) nlmsvc_proc_##name,	\
+   .pc_decode	= (kxdrproc_t) nlmsvc_decode_##xargt,	\
+   .pc_encode	= (kxdrproc_t) nlmsvc_encode_##xrest,	\
+   .pc_release	= NULL,					\
+   .pc_argsize	= sizeof(struct nlm_##argt),		\
+   .pc_ressize	= sizeof(struct nlm_##rest),		\
+   .pc_xdrressize = respsize,				\
  }
 
 #define	Ck	(1+8)	/* cookie */
diff -Nru a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
--- a/fs/lockd/svcsubs.c	Sun Sep 15 19:19:29 2002
+++ b/fs/lockd/svcsubs.c	Sun Sep 15 19:19:29 2002
@@ -176,7 +176,7 @@
 			lock.fl_type  = F_UNLCK;
 			lock.fl_start = 0;
 			lock.fl_end   = OFFSET_MAX;
-			if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
+			if (posix_lock_file(&file->f_file, &lock) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
 				return 1;
@@ -294,15 +294,13 @@
 }
 
 /*
- * Delete a client when the nfsd entry is removed.
+ * delete all hosts structs for clients
  */
 void
-nlmsvc_invalidate_client(struct svc_client *clnt)
+nlmsvc_invalidate_all(void)
 {
-	struct nlm_host	*host;
-
-	if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
-		dprintk("lockd: invalidating client for %s\n", host->h_name);
+	struct nlm_host *host;
+	while ((host = nlm_find_client()) != NULL) {
 		nlmsvc_free_host_resources(host);
 		host->h_expires = 0;
 		host->h_killed = 1;
diff -Nru a/fs/lockd/xdr.c b/fs/lockd/xdr.c
--- a/fs/lockd/xdr.c	Sun Sep 15 19:19:28 2002
+++ b/fs/lockd/xdr.c	Sun Sep 15 19:19:28 2002
@@ -369,6 +369,8 @@
 	argp->state = ntohl(*p++);
 	/* Preserve the address in network byte order */
 	argp->addr = *p++;
+	argp->vers = *p++;
+	argp->proto = *p++;
 	return xdr_argsize_check(rqstp, p);
 }
 
@@ -602,15 +604,15 @@
 };
 
 static struct rpc_version	nlm_version1 = {
-		number:		1,
-		nrprocs:	16,
-		procs:		nlm_procedures,
+		.number		= 1,
+		.nrprocs	= 16,
+		.procs		= nlm_procedures,
 };
 
 static struct rpc_version	nlm_version3 = {
-		number:		3,
-		nrprocs:	24,
-		procs:		nlm_procedures,
+		.number		= 3,
+		.nrprocs	= 24,
+		.procs		= nlm_procedures,
 };
 
 #ifdef 	CONFIG_LOCKD_V4
@@ -618,23 +620,21 @@
 #endif
 
 static struct rpc_version *	nlm_versions[] = {
-	NULL,
-	&nlm_version1,
-	NULL,
-	&nlm_version3,
+	[1] = &nlm_version1,
+	[3] = &nlm_version3,
 #ifdef 	CONFIG_LOCKD_V4
-	&nlm_version4,
+	[4] = &nlm_version4,
 #endif
 };
 
 static struct rpc_stat		nlm_stats;
 
 struct rpc_program		nlm_program = {
-		name:		"lockd",
-		number:		NLM_PROGRAM,
-		nrvers:		sizeof(nlm_versions) / sizeof(nlm_versions[0]),
-		version:	nlm_versions,
-		stats:		&nlm_stats,
+		.name		= "lockd",
+		.number		= NLM_PROGRAM,
+		.nrvers		= sizeof(nlm_versions) / sizeof(nlm_versions[0]),
+		.version	= nlm_versions,
+		.stats		= &nlm_stats,
 };
 
 #ifdef LOCKD_DEBUG
diff -Nru a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
--- a/fs/lockd/xdr4.c	Sun Sep 15 19:19:28 2002
+++ b/fs/lockd/xdr4.c	Sun Sep 15 19:19:28 2002
@@ -608,7 +608,7 @@
 };
 
 struct rpc_version	nlm_version4 = {
-	number:		4,
-	nrprocs:	24,
-	procs:		nlm4_procedures,
+	.number		= 4,
+	.nrprocs	= 24,
+	.procs		= nlm4_procedures,
 };
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Sun Sep 15 19:20:24 2002
+++ b/fs/locks.c	Sun Sep 15 19:20:24 2002
@@ -404,15 +404,14 @@
 }
 
 /*
- * Check whether two locks have the same owner
- * N.B. Do we need the test on PID as well as owner?
- * (Clone tasks should be considered as one "owner".)
+ * Check whether two locks have the same owner.  The apparently superfluous
+ * check for fl_pid enables us to distinguish between locks set by lockd.
  */
 static inline int
-locks_same_owner(struct file_lock *fl1, struct file_lock *fl2)
+posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 {
 	return (fl1->fl_owner == fl2->fl_owner) &&
-	       (fl1->fl_pid   == fl2->fl_pid);
+		(fl1->fl_pid == fl2->fl_pid);
 }
 
 /* Remove waiter from blocker's block list.
@@ -531,7 +530,7 @@
 	/* POSIX locks owned by the same process do not conflict with
 	 * each other.
 	 */
-	if (!IS_POSIX(sys_fl) || locks_same_owner(caller_fl, sys_fl))
+	if (!IS_POSIX(sys_fl) || posix_same_owner(caller_fl, sys_fl))
 		return (0);
 
 	/* Check whether they overlap */
@@ -575,15 +574,6 @@
 	return result;
 }
 
-static int locks_block_on(struct file_lock *blocker, struct file_lock *waiter)
-{
-	int result;
-	locks_insert_block(blocker, waiter);
-	result = interruptible_sleep_on_locked(&waiter->fl_wait, 0);
-	locks_delete_block(waiter);
-	return result;
-}
-
 static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *waiter, int time)
 {
 	int result;
@@ -675,56 +665,37 @@
 			 struct file *filp, loff_t offset,
 			 size_t count)
 {
-	struct file_lock *fl;
-	struct file_lock *new_fl = locks_alloc_lock(0);
+	struct file_lock fl;
 	int error;
 
-	if (new_fl == NULL)
-		return -ENOMEM;
-
-	new_fl->fl_owner = current->files;
-	new_fl->fl_pid = current->pid;
-	new_fl->fl_file = filp;
-	new_fl->fl_flags = FL_POSIX | FL_ACCESS;
-	new_fl->fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
-	new_fl->fl_start = offset;
-	new_fl->fl_end = offset + count - 1;
-
-	error = 0;
-	lock_kernel();
-
-repeat:
-	/* Search the lock list for this inode for locks that conflict with
-	 * the proposed read/write.
-	 */
-	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (!IS_POSIX(fl))
-			continue;
-		if (fl->fl_start > new_fl->fl_end)
+	fl.fl_owner = current->files;
+	fl.fl_pid = current->pid;
+	fl.fl_file = filp;
+	fl.fl_flags = FL_POSIX | FL_ACCESS | FL_SLEEP;
+	fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
+	fl.fl_start = offset;
+	fl.fl_end = offset + count - 1;
+
+	for (;;) {
+		error = posix_lock_file(filp, &fl);
+		if (error != -EAGAIN)
 			break;
-		if (posix_locks_conflict(new_fl, fl)) {
-			error = -EAGAIN;
-			if (filp && (filp->f_flags & O_NONBLOCK))
-				break;
-			error = -EDEADLK;
-			if (posix_locks_deadlock(new_fl, fl))
-				break;
-	
-			error = locks_block_on(fl, new_fl);
-			if (error != 0)
-				break;
-	
+		error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
+		if (!error) {
 			/*
 			 * If we've been sleeping someone might have
 			 * changed the permissions behind our back.
 			 */
-			if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
-				break;
-			goto repeat;
+			if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+				continue;
 		}
+
+		lock_kernel();
+		locks_delete_block(&fl);
+		unlock_kernel();
+		break;
 	}
-	locks_free_lock(new_fl);
-	unlock_kernel();
+
 	return error;
 }
 
@@ -732,8 +703,7 @@
  * at the head of the list, but that's secret knowledge known only to
  * flock_lock_file and posix_lock_file.
  */
-static int flock_lock_file(struct file *filp, struct file_lock *new_fl,
-			   unsigned int wait)
+static int flock_lock_file(struct file *filp, struct file_lock *new_fl)
 {
 	struct file_lock **before;
 	struct inode * inode = filp->f_dentry->d_inode;
@@ -764,7 +734,6 @@
 		return 0;
 
 	lock_kernel();
-repeat:
 	for_each_lock(inode, before) {
 		struct file_lock *fl = *before;
 		if (IS_POSIX(fl))
@@ -774,12 +743,10 @@
 		if (!flock_locks_conflict(new_fl, fl))
 			continue;
 		error = -EAGAIN;
-		if (!wait)
-			goto out;
-		error = locks_block_on(fl, new_fl);
-		if (error != 0)
-			goto out;
-		goto repeat;
+		if (new_fl->fl_flags & FL_SLEEP) {
+			locks_insert_block(fl, new_fl);
+		}
+		goto out;
 	}
 	locks_insert_lock(&inode->i_flock, new_fl);
 	error = 0;
@@ -807,8 +774,7 @@
  * To all purists: Yes, I use a few goto's. Just pass on to the next function.
  */
 
-int posix_lock_file(struct file *filp, struct file_lock *caller,
-			   unsigned int wait)
+int posix_lock_file(struct file *filp, struct file_lock *request)
 {
 	struct file_lock *fl;
 	struct file_lock *new_fl, *new_fl2;
@@ -829,27 +795,29 @@
 		goto out_nolock;
 
 	lock_kernel();
-	if (caller->fl_type != F_UNLCK) {
-  repeat:
-		for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+	if (request->fl_type != F_UNLCK) {
+		for_each_lock(inode, before) {
+			struct file_lock *fl = *before;
 			if (!IS_POSIX(fl))
 				continue;
-			if (!posix_locks_conflict(caller, fl))
+			if (!posix_locks_conflict(request, fl))
 				continue;
 			error = -EAGAIN;
-			if (!wait)
+			if (!(request->fl_flags & FL_SLEEP))
 				goto out;
 			error = -EDEADLK;
-			if (posix_locks_deadlock(caller, fl))
+			if (posix_locks_deadlock(request, fl))
 				goto out;
-
-			error = locks_block_on(fl, caller);
-			if (error != 0)
-				goto out;
-			goto repeat;
+			error = -EAGAIN;
+			locks_insert_block(fl, request);
+			goto out;
   		}
   	}
 
+	/* If we're just looking for a conflict, we're done. */
+	if (request->fl_flags & FL_ACCESS)
+		goto out;
+
 	/*
 	 * We've allocated the new locks in advance, so there are no
 	 * errors possible (and no blocking operations) from here on.
@@ -859,25 +827,23 @@
 	
 	before = &inode->i_flock;
 
-	/* First skip locks owned by other processes.
-	 */
+	/* First skip locks owned by other processes.  */
 	while ((fl = *before) && (!IS_POSIX(fl) ||
-				  !locks_same_owner(caller, fl))) {
+				  !posix_same_owner(request, fl))) {
 		before = &fl->fl_next;
 	}
 
-	/* Process locks with this owner.
-	 */
-	while ((fl = *before) && locks_same_owner(caller, fl)) {
+	/* Process locks with this owner.  */
+	while ((fl = *before) && posix_same_owner(request, fl)) {
 		/* Detect adjacent or overlapping regions (if same lock type)
 		 */
-		if (caller->fl_type == fl->fl_type) {
-			if (fl->fl_end < caller->fl_start - 1)
+		if (request->fl_type == fl->fl_type) {
+			if (fl->fl_end < request->fl_start - 1)
 				goto next_lock;
 			/* If the next lock in the list has entirely bigger
 			 * addresses than the new one, insert the lock here.
 			 */
-			if (fl->fl_start > caller->fl_end + 1)
+			if (fl->fl_start > request->fl_end + 1)
 				break;
 
 			/* If we come here, the new and old lock are of the
@@ -885,41 +851,41 @@
 			 * lock yielding from the lower start address of both
 			 * locks to the higher end address.
 			 */
-			if (fl->fl_start > caller->fl_start)
-				fl->fl_start = caller->fl_start;
+			if (fl->fl_start > request->fl_start)
+				fl->fl_start = request->fl_start;
 			else
-				caller->fl_start = fl->fl_start;
-			if (fl->fl_end < caller->fl_end)
-				fl->fl_end = caller->fl_end;
+				request->fl_start = fl->fl_start;
+			if (fl->fl_end < request->fl_end)
+				fl->fl_end = request->fl_end;
 			else
-				caller->fl_end = fl->fl_end;
+				request->fl_end = fl->fl_end;
 			if (added) {
 				locks_delete_lock(before);
 				continue;
 			}
-			caller = fl;
+			request = fl;
 			added = 1;
 		}
 		else {
 			/* Processing for different lock types is a bit
 			 * more complex.
 			 */
-			if (fl->fl_end < caller->fl_start)
+			if (fl->fl_end < request->fl_start)
 				goto next_lock;
-			if (fl->fl_start > caller->fl_end)
+			if (fl->fl_start > request->fl_end)
 				break;
-			if (caller->fl_type == F_UNLCK)
+			if (request->fl_type == F_UNLCK)
 				added = 1;
-			if (fl->fl_start < caller->fl_start)
+			if (fl->fl_start < request->fl_start)
 				left = fl;
 			/* If the next lock in the list has a higher end
 			 * address than the new one, insert the new one here.
 			 */
-			if (fl->fl_end > caller->fl_end) {
+			if (fl->fl_end > request->fl_end) {
 				right = fl;
 				break;
 			}
-			if (fl->fl_start >= caller->fl_start) {
+			if (fl->fl_start >= request->fl_start) {
 				/* The new lock completely replaces an old
 				 * one (This may happen several times).
 				 */
@@ -933,11 +899,11 @@
 				 * their needs.
 				 */
 				locks_wake_up_blocks(fl);
-				fl->fl_start = caller->fl_start;
-				fl->fl_end = caller->fl_end;
-				fl->fl_type = caller->fl_type;
-				fl->fl_u = caller->fl_u;
-				caller = fl;
+				fl->fl_start = request->fl_start;
+				fl->fl_end = request->fl_end;
+				fl->fl_type = request->fl_type;
+				fl->fl_u = request->fl_u;
+				request = fl;
 				added = 1;
 			}
 		}
@@ -949,9 +915,9 @@
 
 	error = 0;
 	if (!added) {
-		if (caller->fl_type == F_UNLCK)
+		if (request->fl_type == F_UNLCK)
 			goto out;
-		locks_copy_lock(new_fl, caller);
+		locks_copy_lock(new_fl, request);
 		locks_insert_lock(before, new_fl);
 		new_fl = NULL;
 	}
@@ -965,11 +931,11 @@
 			locks_copy_lock(left, right);
 			locks_insert_lock(before, left);
 		}
-		right->fl_start = caller->fl_end + 1;
+		right->fl_start = request->fl_end + 1;
 		locks_wake_up_blocks(right);
 	}
 	if (left) {
-		left->fl_end = caller->fl_start - 1;
+		left->fl_end = request->fl_start - 1;
 		locks_wake_up_blocks(left);
 	}
 out:
@@ -1315,22 +1281,35 @@
 		goto out_putf;
 
 	error = flock_make_lock(filp, &lock, cmd);
-	if (error < 0)
+	if (error)
 		goto out_putf;
 
-	error = security_ops->file_lock(filp, lock->fl_type);
+	error = security_ops->file_lock(filp, cmd);
 	if (error)
-		goto out_putf;
+		goto out_free;
 
-	error = flock_lock_file(filp, lock,
-				(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+	for (;;) {
+		error = flock_lock_file(filp, lock);
+		if ((error != -EAGAIN) || (cmd & LOCK_NB))
+			break;
+		error = wait_event_interruptible(lock->fl_wait, !lock->fl_next);
+		if (!error)
+			continue;
 
-	if (error)
+		lock_kernel();
+		locks_delete_block(lock);
+		unlock_kernel();
+		break;
+	}
+
+ out_free:
+	if (error) {
 		locks_free_lock(lock);
+	}
 
-out_putf:
+ out_putf:
 	fput(filp);
-out:
+ out:
 	return error;
 }
 
@@ -1434,6 +1413,9 @@
 	error = flock_to_posix_lock(filp, file_lock, &flock);
 	if (error)
 		goto out;
+	if (cmd == F_SETLKW) {
+		file_lock->fl_flags |= FL_SLEEP;
+	}
 	
 	error = -EBADF;
 	switch (flock.l_type) {
@@ -1461,10 +1443,26 @@
 		if (error < 0)
 			goto out;
 	}
-	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
+
+	for (;;) {
+		error = posix_lock_file(filp, file_lock);
+		if ((error != -EAGAIN) || (cmd == F_SETLK))
+			break;
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		lock_kernel();
+		locks_delete_block(file_lock);
+		unlock_kernel();
+		break;
+	}
 
 out:
-	locks_free_lock(file_lock);
+	if (error) {
+		locks_free_lock(file_lock);
+	}
 	return error;
 }
 
@@ -1557,6 +1555,9 @@
 	error = flock64_to_posix_lock(filp, file_lock, &flock);
 	if (error)
 		goto out;
+	if (cmd == F_SETLKW64) {
+		file_lock->fl_flags |= FL_SLEEP;
+	}
 	
 	error = -EBADF;
 	switch (flock.l_type) {
@@ -1584,10 +1585,27 @@
 		if (error < 0)
 			goto out;
 	}
-	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64);
+
+	for (;;) {
+		error = posix_lock_file(filp, file_lock);
+		if ((error != -EAGAIN) || (cmd == F_SETLK64))
+			break;
+		error = wait_event_interruptible(file_lock->fl_wait,
+				!file_lock->fl_next);
+		if (!error)
+			continue;
+
+		lock_kernel();
+		locks_delete_block(file_lock);
+		unlock_kernel();
+		break;
+	}
+
 
 out:
-	locks_free_lock(file_lock);
+	if (error) {
+		locks_free_lock(file_lock);
+	}
 	return error;
 }
 #endif /* BITS_PER_LONG == 32 */
@@ -1622,7 +1640,7 @@
 		/* Ignore any error -- we must remove the locks anyway */
 	}
 
-	posix_lock_file(filp, &lock, 0);
+	posix_lock_file(filp, &lock);
 }
 
 /*
@@ -1676,10 +1694,21 @@
  *	lockd needs to block waiting for locks.
  */
 void
-posix_unblock_lock(struct file_lock *waiter)
+posix_unblock_lock(struct file *filp, struct file_lock *waiter)
 {
-	if (!list_empty(&waiter->fl_block))
+	/* 
+	 * A remote machine may cancel the lock request after it's been
+	 * granted locally.  If that happens, we need to delete the lock.
+	 */
+	lock_kernel();
+	if (waiter->fl_next) {
 		locks_delete_block(waiter);
+		unlock_kernel();
+	} else {
+		unlock_kernel();
+		waiter->fl_type = F_UNLCK;
+		posix_lock_file(filp, waiter);
+	}
 }
 
 static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
@@ -1725,21 +1754,28 @@
 			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
 			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
 	}
-	/*
-	 *	NOTE: it should be inode->i_sb->s_id, not kdevname(...).
-	 */
-	out += sprintf(out, "%d %s:%ld ",
-		     fl->fl_pid,
-		     inode ? kdevname(to_kdev_t(inode->i_dev)) : "<none>",
-		     inode ? inode->i_ino : 0);
-	out += sprintf(out, "%Ld ", fl->fl_start);
-	if (fl->fl_end == OFFSET_MAX)
-		out += sprintf(out, "EOF ");
-	else
-		out += sprintf(out, "%Ld ", fl->fl_end);
-	sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",
-		(long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next,
-		(long)fl->fl_next, (long)fl->fl_block.next);
+#if WE_CAN_BREAK_LSLK_NOW
+	if (inode) {
+		out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
+				inode->i_sb->s_id, inode->i_ino);
+	} else {
+		out += sprintf(out, "%d <none>:0 ", fl->fl_pid);
+	}
+#else
+	/* kdevname is a broken interface.  but we expose it to userspace */
+	out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
+			inode ? kdevname(to_kdev_t(inode->i_dev)) : "<none>",
+			inode ? inode->i_ino : 0);
+#endif
+	if (IS_POSIX(fl)) {
+		if (fl->fl_end == OFFSET_MAX)
+			out += sprintf(out, "%Ld EOF\n", fl->fl_start);
+		else
+			out += sprintf(out, "%Ld %Ld\n", fl->fl_start,
+					fl->fl_end);
+	} else {
+		out += sprintf(out, "0 EOF\n");
+	}
 }
 
 static void move_lock_status(char **p, off_t* pos, off_t offset)
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Sun Sep 15 19:19:29 2002
+++ b/fs/mpage.c	Sun Sep 15 19:19:29 2002
@@ -460,6 +460,9 @@
 			clear_buffer_dirty(bh);
 			bh = bh->b_this_page;
 		} while (bh != head);
+
+		if (buffer_heads_over_limit)
+			try_to_free_buffers(page);
 	}
 
 	bvec = &bio->bi_io_vec[bio->bi_idx++];
@@ -571,7 +574,7 @@
 			wait_on_page_writeback(page);
 
 		if (page->mapping && !PageWriteback(page) &&
-					TestClearPageDirty(page)) {
+					test_clear_page_dirty(page)) {
 			if (writepage) {
 				ret = (*writepage)(page);
 			} else {
@@ -599,9 +602,8 @@
 		write_lock(&mapping->page_lock);
 	}
 	/*
-	 * Put the rest back, in the correct order.
+	 * Leave any remaining dirty pages on ->io_pages
 	 */
-	list_splice_init(&mapping->io_pages, mapping->dirty_pages.prev);
 	write_unlock(&mapping->page_lock);
 	pagevec_deactivate_inactive(&pvec);
 	if (bio)
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Sun Sep 15 19:19:57 2002
+++ b/fs/namespace.c	Sun Sep 15 19:19:57 2002
@@ -883,11 +883,11 @@
 
 static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	struct fs_struct *fs;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		task_lock(p);
 		fs = p->fs;
 		if (fs) {
@@ -900,7 +900,7 @@
 			put_fs_struct(fs);
 		} else
 			task_unlock(p);
-	}
+	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 }
 
@@ -1012,7 +1012,7 @@
 {
 	struct vfsmount *mnt;
 	struct namespace *namespace;
-	struct task_struct *p;
+	struct task_struct *g, *p;
 
 	mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
 	if (IS_ERR(mnt))
@@ -1028,10 +1028,10 @@
 
 	init_task.namespace = namespace;
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		get_namespace(namespace);
 		p->namespace = namespace;
-	}
+	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
 	set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Sun Sep 15 19:19:46 2002
+++ b/fs/nfs/dir.c	Sun Sep 15 19:19:46 2002
@@ -50,25 +50,25 @@
 		      struct inode *, struct dentry *);
 
 struct file_operations nfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	nfs_readdir,
-	open:		nfs_open,
-	release:	nfs_release,
+	.read		= generic_read_dir,
+	.readdir	= nfs_readdir,
+	.open		= nfs_open,
+	.release	= nfs_release,
 };
 
 struct inode_operations nfs_dir_inode_operations = {
-	create:		nfs_create,
-	lookup:		nfs_lookup,
-	link:		nfs_link,
-	unlink:		nfs_unlink,
-	symlink:	nfs_symlink,
-	mkdir:		nfs_mkdir,
-	rmdir:		nfs_rmdir,
-	mknod:		nfs_mknod,
-	rename:		nfs_rename,
-	permission:	nfs_permission,
-	getattr:	nfs_getattr,
-	setattr:	nfs_setattr,
+	.create		= nfs_create,
+	.lookup		= nfs_lookup,
+	.link		= nfs_link,
+	.unlink		= nfs_unlink,
+	.symlink	= nfs_symlink,
+	.mkdir		= nfs_mkdir,
+	.rmdir		= nfs_rmdir,
+	.mknod		= nfs_mknod,
+	.rename		= nfs_rename,
+	.permission	= nfs_permission,
+	.getattr	= nfs_getattr,
+	.setattr	= nfs_setattr,
 };
 
 typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
@@ -607,9 +607,9 @@
 }
 
 struct dentry_operations nfs_dentry_operations = {
-	d_revalidate:	nfs_lookup_revalidate,
-	d_delete:	nfs_dentry_delete,
-	d_iput:		nfs_dentry_iput,
+	.d_revalidate	= nfs_lookup_revalidate,
+	.d_delete	= nfs_dentry_delete,
+	.d_iput		= nfs_dentry_iput,
 };
 
 static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Sun Sep 15 19:19:57 2002
+++ b/fs/nfs/file.c	Sun Sep 15 19:19:57 2002
@@ -41,21 +41,21 @@
 static int  nfs_fsync(struct file *, struct dentry *dentry, int datasync);
 
 struct file_operations nfs_file_operations = {
-	llseek:		remote_llseek,
-	read:		nfs_file_read,
-	write:		nfs_file_write,
-	mmap:		nfs_file_mmap,
-	open:		nfs_open,
-	flush:		nfs_file_flush,
-	release:	nfs_release,
-	fsync:		nfs_fsync,
-	lock:		nfs_lock,
+	.llseek		= remote_llseek,
+	.read		= nfs_file_read,
+	.write		= nfs_file_write,
+	.mmap		= nfs_file_mmap,
+	.open		= nfs_open,
+	.flush		= nfs_file_flush,
+	.release	= nfs_release,
+	.fsync		= nfs_fsync,
+	.lock		= nfs_lock,
 };
 
 struct inode_operations nfs_file_inode_operations = {
-	permission:	nfs_permission,
-	getattr:	nfs_getattr,
-	setattr:	nfs_setattr,
+	.permission	= nfs_permission,
+	.getattr	= nfs_getattr,
+	.setattr	= nfs_setattr,
 };
 
 /* Hack for future NFS swap support */
@@ -195,11 +195,11 @@
 }
 
 struct address_space_operations nfs_file_aops = {
-	readpage: nfs_readpage,
-	sync_page: nfs_sync_page,
-	writepage: nfs_writepage,
-	prepare_write: nfs_prepare_write,
-	commit_write: nfs_commit_write
+	.readpage = nfs_readpage,
+	.sync_page = nfs_sync_page,
+	.writepage = nfs_writepage,
+	.prepare_write = nfs_prepare_write,
+	.commit_write = nfs_commit_write
 };
 
 /* 
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Sun Sep 15 19:20:18 2002
+++ b/fs/nfs/inode.c	Sun Sep 15 19:20:18 2002
@@ -55,22 +55,22 @@
 static int  nfs_show_options(struct seq_file *, struct vfsmount *);
 
 static struct super_operations nfs_sops = { 
-	alloc_inode:	nfs_alloc_inode,
-	destroy_inode:	nfs_destroy_inode,
-	write_inode:	nfs_write_inode,
-	delete_inode:	nfs_delete_inode,
-	put_super:	nfs_put_super,
-	statfs:		nfs_statfs,
-	clear_inode:	nfs_clear_inode,
-	umount_begin:	nfs_umount_begin,
-	show_options:	nfs_show_options,
+	.alloc_inode	= nfs_alloc_inode,
+	.destroy_inode	= nfs_destroy_inode,
+	.write_inode	= nfs_write_inode,
+	.delete_inode	= nfs_delete_inode,
+	.put_super	= nfs_put_super,
+	.statfs		= nfs_statfs,
+	.clear_inode	= nfs_clear_inode,
+	.umount_begin	= nfs_umount_begin,
+	.show_options	= nfs_show_options,
 };
 
 /*
  * RPC cruft for NFS
  */
 struct rpc_stat			nfs_rpcstat = {
-	program:		&nfs_program
+	.program		= &nfs_program
 };
 static struct rpc_version *	nfs_version[] = {
 	NULL,
@@ -82,11 +82,11 @@
 };
 
 struct rpc_program		nfs_program = {
-	name:			"nfs",
-	number:			NFS_PROGRAM,
-	nrvers:			sizeof(nfs_version) / sizeof(nfs_version[0]),
-	version:		nfs_version,
-	stats:			&nfs_rpcstat,
+	.name			= "nfs",
+	.number			= NFS_PROGRAM,
+	.nrvers			= sizeof(nfs_version) / sizeof(nfs_version[0]),
+	.version		= nfs_version,
+	.stats			= &nfs_rpcstat,
 };
 
 static inline unsigned long
@@ -654,8 +654,8 @@
 __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
 	struct nfs_find_desc desc = {
-		fh:	fh,
-		fattr:	fattr
+		.fh	= fh,
+		.fattr	= fattr
 	};
 	struct inode *inode = NULL;
 	unsigned long hash;
@@ -1261,11 +1261,11 @@
 }
 
 static struct file_system_type nfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"nfs",
-	get_sb:		nfs_get_sb,
-	kill_sb:	nfs_kill_super,
-	fs_flags:	FS_ODD_RENAME,
+	.owner		= THIS_MODULE,
+	.name		= "nfs",
+	.get_sb		= nfs_get_sb,
+	.kill_sb	= nfs_kill_super,
+	.fs_flags	= FS_ODD_RENAME,
 };
 
 extern int nfs_init_nfspagecache(void);
diff -Nru a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
--- a/fs/nfs/mount_clnt.c	Sun Sep 15 19:19:28 2002
+++ b/fs/nfs/mount_clnt.c	Sun Sep 15 19:19:28 2002
@@ -59,7 +59,7 @@
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = {
-		fh:		fh
+		.fh		= fh
 	};
 	char			hostname[32];
 	int			status;
@@ -152,40 +152,40 @@
 #define MNT_fhstatus_sz		(1 + 8)
 
 static struct rpc_procinfo	mnt_procedures[2] = {
-	{ p_procname:		"mnt_null",
-	  p_encode:		(kxdrproc_t) xdr_error,	
-	  p_decode:		(kxdrproc_t) xdr_error,
+	{ .p_procname		= "mnt_null",
+	  .p_encode		= (kxdrproc_t) xdr_error,	
+	  .p_decode		= (kxdrproc_t) xdr_error,
 	},
-	{ p_procname:		"mnt_mount",
-	  p_encode:		(kxdrproc_t) xdr_encode_dirpath,	
-	  p_decode:		(kxdrproc_t) xdr_decode_fhstatus,
-	  p_bufsiz:		MNT_dirpath_sz << 2,
+	{ .p_procname		= "mnt_mount",
+	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,	
+	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus,
+	  .p_bufsiz		= MNT_dirpath_sz << 2,
 	},
 };
 
 static struct rpc_procinfo mnt3_procedures[2] = {
-	{ p_procname:		"mnt3_null",
-	  p_encode:		(kxdrproc_t) xdr_error,
-	  p_decode:		(kxdrproc_t) xdr_error,
+	{ .p_procname		= "mnt3_null",
+	  .p_encode		= (kxdrproc_t) xdr_error,
+	  .p_decode		= (kxdrproc_t) xdr_error,
 	},
-	{ p_procname:		"mnt3_mount",
-	  p_encode:		(kxdrproc_t) xdr_encode_dirpath,
-	  p_decode:		(kxdrproc_t) xdr_decode_fhstatus3,
-	  p_bufsiz:		MNT_dirpath_sz << 2,
+	{ .p_procname		= "mnt3_mount",
+	  .p_encode		= (kxdrproc_t) xdr_encode_dirpath,
+	  .p_decode		= (kxdrproc_t) xdr_decode_fhstatus3,
+	  .p_bufsiz		= MNT_dirpath_sz << 2,
 	},
 };
 
 
 static struct rpc_version	mnt_version1 = {
-		number:		1,
-		nrprocs: 	2,
-		procs: 		mnt_procedures
+		.number		= 1,
+		.nrprocs 	= 2,
+		.procs 		= mnt_procedures
 };
 
 static struct rpc_version       mnt_version3 = {
-		number:		3,
-		nrprocs:	2,
-		procs:		mnt3_procedures
+		.number		= 3,
+		.nrprocs	= 2,
+		.procs		= mnt3_procedures
 };
 
 static struct rpc_version *	mnt_version[] = {
@@ -198,9 +198,9 @@
 static struct rpc_stat		mnt_stats;
 
 struct rpc_program	mnt_program = {
-	name:		"mount",
-	number:		NFS_MNT_PROGRAM,
-	nrvers:		sizeof(mnt_version)/sizeof(mnt_version[0]),
-	version:	mnt_version,
-	stats:		&mnt_stats,
+	.name		= "mount",
+	.number		= NFS_MNT_PROGRAM,
+	.nrvers		= sizeof(mnt_version)/sizeof(mnt_version[0]),
+	.version	= mnt_version,
+	.stats		= &mnt_stats,
 };
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Sun Sep 15 19:19:34 2002
+++ b/fs/nfs/nfs2xdr.c	Sun Sep 15 19:19:34 2002
@@ -724,7 +724,7 @@
 };
 
 struct rpc_version		nfs_version2 = {
-	number:			2,
-	nrprocs:		sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
-	procs:			nfs_procedures
+	.number			= 2,
+	.nrprocs		= sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
+	.procs			= nfs_procedures
 };
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Sun Sep 15 19:19:46 2002
+++ b/fs/nfs/nfs3proc.c	Sun Sep 15 19:19:46 2002
@@ -41,9 +41,9 @@
 nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
 {
 	struct rpc_message msg = {
-		rpc_proc:	proc,
-		rpc_argp:	argp,
-		rpc_resp:	resp,
+		.rpc_proc	= proc,
+		.rpc_argp	= argp,
+		.rpc_resp	= resp,
 	};
 	return nfs3_rpc_wrapper(clnt, &msg, flags);
 }
@@ -90,8 +90,8 @@
 			struct iattr *sattr)
 {
 	struct nfs3_sattrargs	arg = {
-		fh:		NFS_FH(inode),
-		sattr:		sattr,
+		.fh		= NFS_FH(inode),
+		.sattr		= sattr,
 	};
 	int	status;
 
@@ -108,14 +108,14 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	struct nfs3_diropres	res = {
-		dir_attr:	&dir_attr,
-		fh:		fhandle,
-		fattr:		fattr
+		.dir_attr	= &dir_attr,
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -180,9 +180,9 @@
 {
 	struct nfs_fattr	fattr;
 	struct nfs3_readlinkargs args = {
-		fh:		NFS_FH(inode),
-		count:		PAGE_CACHE_SIZE,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.count		= PAGE_CACHE_SIZE,
+		.pages		= &page
 	};
 	int			status;
 
@@ -203,21 +203,21 @@
 {
 	u64			offset = page_offset(page) + base;
 	struct nfs_readargs	arg = {
-		fh:		NFS_FH(inode),
-		offset:		offset,
-		count:		count,
-		pgbase:		base,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.offset		= offset,
+		.count		= count,
+		.pgbase		= base,
+		.pages		= &page
 	};
 	struct nfs_readres	res = {
-		fattr:		fattr,
-		count:		count,
+		.fattr		= fattr,
+		.count		= count,
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFS3PROC_READ,
-		rpc_argp:	&arg,
-		rpc_resp:	&res,
-		rpc_cred:	cred
+		.rpc_proc	= NFS3PROC_READ,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &res,
+		.rpc_cred	= cred
 	};
 	int			status;
 
@@ -237,22 +237,22 @@
 {
 	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = {
-		fh:		NFS_FH(inode),
-		offset:		offset,
-		count:		count,
-		stable:		NFS_FILE_SYNC,
-		pgbase:		base,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.offset		= offset,
+		.count		= count,
+		.stable		= NFS_FILE_SYNC,
+		.pgbase		= base,
+		.pages		= &page
 	};
 	struct nfs_writeres	res = {
-		fattr:		fattr,
-		verf:		verf,
+		.fattr		= fattr,
+		.verf		= verf,
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFS3PROC_WRITE,
-		rpc_argp:	&arg,
-		rpc_resp:	&res,
-		rpc_cred:	cred
+		.rpc_proc	= NFS3PROC_WRITE,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &res,
+		.rpc_cred	= cred
 	};
 	int			status, rpcflags = 0;
 
@@ -278,15 +278,15 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_createargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr,
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr,
 	};
 	struct nfs3_diropres	res = {
-		dir_attr:	&dir_attr,
-		fh:		fhandle,
-		fattr:		fattr
+		.dir_attr	= &dir_attr,
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -329,8 +329,8 @@
 	 * sure we set the attributes afterwards. */
 	if (status == 0 && arg.createmode == NFS3_CREATE_EXCLUSIVE) {
 		struct nfs3_sattrargs	arg = {
-			fh:		fhandle,
-			sattr:		sattr,
+			.fh		= fhandle,
+			.sattr		= sattr,
 		};
 		dprintk("NFS call  setattr (post-create)\n");
 
@@ -351,14 +351,14 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFS3PROC_REMOVE,
-		rpc_argp:	&arg,
-		rpc_resp:	&dir_attr,
+		.rpc_proc	= NFS3PROC_REMOVE,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &dir_attr,
 	};
 	int			status;
 
@@ -408,16 +408,16 @@
 {
 	struct nfs_fattr	old_dir_attr, new_dir_attr;
 	struct nfs3_renameargs	arg = {
-		fromfh:		NFS_FH(old_dir),
-		fromname:	old_name->name,
-		fromlen:	old_name->len,
-		tofh:		NFS_FH(new_dir),
-		toname:		new_name->name,
-		tolen:		new_name->len
+		.fromfh		= NFS_FH(old_dir),
+		.fromname	= old_name->name,
+		.fromlen	= old_name->len,
+		.tofh		= NFS_FH(new_dir),
+		.toname		= new_name->name,
+		.tolen		= new_name->len
 	};
 	struct nfs3_renameres	res = {
-		fromattr:	&old_dir_attr,
-		toattr:		&new_dir_attr
+		.fromattr	= &old_dir_attr,
+		.toattr		= &new_dir_attr
 	};
 	int			status;
 
@@ -436,14 +436,14 @@
 {
 	struct nfs_fattr	dir_attr, fattr;
 	struct nfs3_linkargs	arg = {
-		fromfh:		NFS_FH(inode),
-		tofh:		NFS_FH(dir),
-		toname:		name->name,
-		tolen:		name->len
+		.fromfh		= NFS_FH(inode),
+		.tofh		= NFS_FH(dir),
+		.toname		= name->name,
+		.tolen		= name->len
 	};
 	struct nfs3_linkres	res = {
-		dir_attr:	&dir_attr,
-		fattr:		&fattr
+		.dir_attr	= &dir_attr,
+		.fattr		= &fattr
 	};
 	int			status;
 
@@ -464,17 +464,17 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_symlinkargs	arg = {
-		fromfh:		NFS_FH(dir),
-		fromname:	name->name,
-		fromlen:	name->len,
-		topath:		path->name,
-		tolen:		path->len,
-		sattr:		sattr
+		.fromfh		= NFS_FH(dir),
+		.fromname	= name->name,
+		.fromlen	= name->len,
+		.topath		= path->name,
+		.tolen		= path->len,
+		.sattr		= sattr
 	};
 	struct nfs3_diropres	res = {
-		dir_attr:	&dir_attr,
-		fh:		fhandle,
-		fattr:		fattr
+		.dir_attr	= &dir_attr,
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -493,15 +493,15 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_mkdirargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr
 	};
 	struct nfs3_diropres	res = {
-		dir_attr:	&dir_attr,
-		fh:		fhandle,
-		fattr:		fattr
+		.dir_attr	= &dir_attr,
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -519,9 +519,9 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	int			status;
 
@@ -549,23 +549,23 @@
 	struct nfs_fattr	dir_attr;
 	u32			*verf = NFS_COOKIEVERF(dir);
 	struct nfs3_readdirargs	arg = {
-		fh:		NFS_FH(dir),
-		cookie:		cookie,
-		verf:		{verf[0], verf[1]},
-		plus:		plus,
-		count:		count,
-		pages:		&page
+		.fh		= NFS_FH(dir),
+		.cookie		= cookie,
+		.verf		= {verf[0], verf[1]},
+		.plus		= plus,
+		.count		= count,
+		.pages		= &page
 	};
 	struct nfs3_readdirres	res = {
-		dir_attr:	&dir_attr,
-		verf:		verf,
-		plus:		plus
+		.dir_attr	= &dir_attr,
+		.verf		= verf,
+		.plus		= plus
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFS3PROC_READDIR,
-		rpc_argp:	&arg,
-		rpc_resp:	&res,
-		rpc_cred:	cred
+		.rpc_proc	= NFS3PROC_READDIR,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &res,
+		.rpc_cred	= cred
 	};
 	int			status;
 
@@ -591,16 +591,16 @@
 {
 	struct nfs_fattr	dir_attr;
 	struct nfs3_mknodargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr,
-		rdev:		rdev
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr,
+		.rdev		= rdev
 	};
 	struct nfs3_diropres	res = {
-		dir_attr:	&dir_attr,
-		fh:		fh,
-		fattr:		fattr
+		.dir_attr	= &dir_attr,
+		.fh		= fh,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -645,26 +645,26 @@
 extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
 
 struct nfs_rpc_ops	nfs_v3_clientops = {
-	version:	3,			/* protocol version */
-	getroot:	nfs3_proc_get_root,
-	getattr:	nfs3_proc_getattr,
-	setattr:	nfs3_proc_setattr,
-	lookup:		nfs3_proc_lookup,
-	access:		nfs3_proc_access,
-	readlink:	nfs3_proc_readlink,
-	read:		nfs3_proc_read,
-	write:		nfs3_proc_write,
-	create:		nfs3_proc_create,
-	remove:		nfs3_proc_remove,
-	unlink_setup:	nfs3_proc_unlink_setup,
-	unlink_done:	nfs3_proc_unlink_done,
-	rename:		nfs3_proc_rename,
-	link:		nfs3_proc_link,
-	symlink:	nfs3_proc_symlink,
-	mkdir:		nfs3_proc_mkdir,
-	rmdir:		nfs3_proc_rmdir,
-	readdir:	nfs3_proc_readdir,
-	mknod:		nfs3_proc_mknod,
-	statfs:		nfs3_proc_statfs,
-	decode_dirent:	nfs3_decode_dirent,
+	.version	= 3,			/* protocol version */
+	.getroot	= nfs3_proc_get_root,
+	.getattr	= nfs3_proc_getattr,
+	.setattr	= nfs3_proc_setattr,
+	.lookup		= nfs3_proc_lookup,
+	.access		= nfs3_proc_access,
+	.readlink	= nfs3_proc_readlink,
+	.read		= nfs3_proc_read,
+	.write		= nfs3_proc_write,
+	.create		= nfs3_proc_create,
+	.remove		= nfs3_proc_remove,
+	.unlink_setup	= nfs3_proc_unlink_setup,
+	.unlink_done	= nfs3_proc_unlink_done,
+	.rename		= nfs3_proc_rename,
+	.link		= nfs3_proc_link,
+	.symlink	= nfs3_proc_symlink,
+	.mkdir		= nfs3_proc_mkdir,
+	.rmdir		= nfs3_proc_rmdir,
+	.readdir	= nfs3_proc_readdir,
+	.mknod		= nfs3_proc_mknod,
+	.statfs		= nfs3_proc_statfs,
+	.decode_dirent	= nfs3_decode_dirent,
 };
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Sun Sep 15 19:20:24 2002
+++ b/fs/nfs/nfs3xdr.c	Sun Sep 15 19:20:24 2002
@@ -1039,8 +1039,8 @@
 };
 
 struct rpc_version		nfs_version3 = {
-	number:			3,
-	nrprocs:		sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
-	procs:			nfs3_procedures
+	.number			= 3,
+	.nrprocs		= sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
+	.procs			= nfs3_procedures
 };
 
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Sun Sep 15 19:19:34 2002
+++ b/fs/nfs/proc.c	Sun Sep 15 19:19:34 2002
@@ -82,8 +82,8 @@
 		 struct iattr *sattr)
 {
 	struct nfs_sattrargs	arg = { 
-		fh:	NFS_FH(inode),
-		sattr:	sattr
+		.fh	= NFS_FH(inode),
+		.sattr	= sattr
 	};
 	int	status;
 
@@ -99,13 +99,13 @@
 		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	struct nfs_diropok	res = {
-		fh:		fhandle,
-		fattr:		fattr
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -120,9 +120,9 @@
 nfs_proc_readlink(struct inode *inode, struct page *page)
 {
 	struct nfs_readlinkargs	args = {
-		fh:		NFS_FH(inode),
-		count:		PAGE_CACHE_SIZE,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.count		= PAGE_CACHE_SIZE,
+		.pages		= &page
 	};
 	int			status;
 
@@ -140,21 +140,21 @@
 {
 	u64			offset = page_offset(page) + base;
 	struct nfs_readargs	arg = {
-		fh:		NFS_FH(inode),
-		offset:		offset,
-		count:		count,
-		pgbase:		base,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.offset		= offset,
+		.count		= count,
+		.pgbase		= base,
+		.pages		= &page
 	};
 	struct nfs_readres	res = {
-		fattr:		fattr,
-		count:		count
+		.fattr		= fattr,
+		.count		= count
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFSPROC_READ,
-		rpc_argp:	&arg,
-		rpc_resp:	&res,
-		rpc_cred:	cred
+		.rpc_proc	= NFSPROC_READ,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &res,
+		.rpc_cred	= cred
 	};
 	int			status;
 
@@ -175,23 +175,23 @@
 {
 	u64			offset = page_offset(page) + base;
 	struct nfs_writeargs	arg = {
-		fh:		NFS_FH(inode),
-		offset:		offset,
-		count:		count,
-		stable:		NFS_FILE_SYNC,
-		pgbase:		base,
-		pages:		&page
+		.fh		= NFS_FH(inode),
+		.offset		= offset,
+		.count		= count,
+		.stable		= NFS_FILE_SYNC,
+		.pgbase		= base,
+		.pages		= &page
 	};
 	struct nfs_writeres     res = {
-		fattr:		fattr,
-		verf:		verf,
-		count:		count
+		.fattr		= fattr,
+		.verf		= verf,
+		.count		= count
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFSPROC_WRITE,
-		rpc_argp:	&arg,
-		rpc_resp:	&res,
-		rpc_cred:	cred
+		.rpc_proc	= NFSPROC_WRITE,
+		.rpc_argp	= &arg,
+		.rpc_resp	= &res,
+		.rpc_cred	= cred
 	};
 	int			status, flags = 0;
 
@@ -211,14 +211,14 @@
 		int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_createargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr
 	};
 	struct nfs_diropok	res = {
-		fh:		fhandle,
-		fattr:		fattr
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -237,14 +237,14 @@
 	       dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_createargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr
 	};
 	struct nfs_diropok	res = {
-		fh:		fhandle,
-		fattr:		fattr
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status, mode;
 
@@ -275,15 +275,15 @@
 nfs_proc_remove(struct inode *dir, struct qstr *name)
 {
 	struct nfs_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	struct rpc_message	msg = { 
-		rpc_proc:	NFSPROC_REMOVE,
-		rpc_argp:	&arg,
-		rpc_resp:	NULL,
-		rpc_cred:	NULL
+		.rpc_proc	= NFSPROC_REMOVE,
+		.rpc_argp	= &arg,
+		.rpc_resp	= NULL,
+		.rpc_cred	= NULL
 	};
 	int			status;
 
@@ -324,12 +324,12 @@
 		struct inode *new_dir, struct qstr *new_name)
 {
 	struct nfs_renameargs	arg = {
-		fromfh:		NFS_FH(old_dir),
-		fromname:	old_name->name,
-		fromlen:	old_name->len,
-		tofh:		NFS_FH(new_dir),
-		toname:		new_name->name,
-		tolen:		new_name->len
+		.fromfh		= NFS_FH(old_dir),
+		.fromname	= old_name->name,
+		.fromlen	= old_name->len,
+		.tofh		= NFS_FH(new_dir),
+		.toname		= new_name->name,
+		.tolen		= new_name->len
 	};
 	int			status;
 
@@ -343,10 +343,10 @@
 nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
 	struct nfs_linkargs	arg = {
-		fromfh:		NFS_FH(inode),
-		tofh:		NFS_FH(dir),
-		toname:		name->name,
-		tolen:		name->len
+		.fromfh		= NFS_FH(inode),
+		.tofh		= NFS_FH(dir),
+		.toname		= name->name,
+		.tolen		= name->len
 	};
 	int			status;
 
@@ -362,12 +362,12 @@
 		 struct nfs_fattr *fattr)
 {
 	struct nfs_symlinkargs	arg = {
-		fromfh:		NFS_FH(dir),
-		fromname:	name->name,
-		fromlen:	name->len,
-		topath:		path->name,
-		tolen:		path->len,
-		sattr:		sattr
+		.fromfh		= NFS_FH(dir),
+		.fromname	= name->name,
+		.fromlen	= name->len,
+		.topath		= path->name,
+		.tolen		= path->len,
+		.sattr		= sattr
 	};
 	int			status;
 
@@ -383,14 +383,14 @@
 	       struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
 	struct nfs_createargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len,
-		sattr:		sattr
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len,
+		.sattr		= sattr
 	};
 	struct nfs_diropok	res = {
-		fh:		fhandle,
-		fattr:		fattr
+		.fh		= fhandle,
+		.fattr		= fattr
 	};
 	int			status;
 
@@ -405,9 +405,9 @@
 nfs_proc_rmdir(struct inode *dir, struct qstr *name)
 {
 	struct nfs_diropargs	arg = {
-		fh:		NFS_FH(dir),
-		name:		name->name,
-		len:		name->len
+		.fh		= NFS_FH(dir),
+		.name		= name->name,
+		.len		= name->len
 	};
 	int			status;
 
@@ -429,16 +429,16 @@
 		 u64 cookie, struct page *page, unsigned int count, int plus)
 {
 	struct nfs_readdirargs	arg = {
-		fh:		NFS_FH(dir),
-		cookie:		cookie,
-		count:		count,
-		pages:		&page
+		.fh		= NFS_FH(dir),
+		.cookie		= cookie,
+		.count		= count,
+		.pages		= &page
 	};
 	struct rpc_message	msg = {
-		rpc_proc:	NFSPROC_READDIR,
-		rpc_argp:	&arg,
-		rpc_resp:	NULL,
-		rpc_cred:	cred
+		.rpc_proc	= NFSPROC_READDIR,
+		.rpc_argp	= &arg,
+		.rpc_resp	= NULL,
+		.rpc_cred	= cred
 	};
 	int			status;
 
@@ -468,27 +468,27 @@
 extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
 
 struct nfs_rpc_ops	nfs_v2_clientops = {
-	version:	2,		       /* protocol version */
-	getroot:	nfs_proc_get_root,
-	getattr:	nfs_proc_getattr,
-	setattr:	nfs_proc_setattr,
-	lookup:		nfs_proc_lookup,
-	access:		NULL,		       /* access */
-	readlink:	nfs_proc_readlink,
-	read:		nfs_proc_read,
-	write:		nfs_proc_write,
-	commit:		NULL,		       /* commit */
-	create:		nfs_proc_create,
-	remove:		nfs_proc_remove,
-	unlink_setup:	nfs_proc_unlink_setup,
-	unlink_done:	nfs_proc_unlink_done,
-	rename:		nfs_proc_rename,
-	link:		nfs_proc_link,
-	symlink:	nfs_proc_symlink,
-	mkdir:		nfs_proc_mkdir,
-	rmdir:		nfs_proc_rmdir,
-	readdir:	nfs_proc_readdir,
-	mknod:		nfs_proc_mknod,
-	statfs:		nfs_proc_statfs,
-	decode_dirent:	nfs_decode_dirent,
+	.version	= 2,		       /* protocol version */
+	.getroot	= nfs_proc_get_root,
+	.getattr	= nfs_proc_getattr,
+	.setattr	= nfs_proc_setattr,
+	.lookup		= nfs_proc_lookup,
+	.access		= NULL,		       /* access */
+	.readlink	= nfs_proc_readlink,
+	.read		= nfs_proc_read,
+	.write		= nfs_proc_write,
+	.commit		= NULL,		       /* commit */
+	.create		= nfs_proc_create,
+	.remove		= nfs_proc_remove,
+	.unlink_setup	= nfs_proc_unlink_setup,
+	.unlink_done	= nfs_proc_unlink_done,
+	.rename		= nfs_proc_rename,
+	.link		= nfs_proc_link,
+	.symlink	= nfs_proc_symlink,
+	.mkdir		= nfs_proc_mkdir,
+	.rmdir		= nfs_proc_rmdir,
+	.readdir	= nfs_proc_readdir,
+	.mknod		= nfs_proc_mknod,
+	.statfs		= nfs_proc_statfs,
+	.decode_dirent	= nfs_decode_dirent,
 };
diff -Nru a/fs/nfs/symlink.c b/fs/nfs/symlink.c
--- a/fs/nfs/symlink.c	Sun Sep 15 19:19:28 2002
+++ b/fs/nfs/symlink.c	Sun Sep 15 19:19:28 2002
@@ -103,8 +103,8 @@
  * symlinks can't do much...
  */
 struct inode_operations nfs_symlink_inode_operations = {
-	readlink:	nfs_readlink,
-	follow_link:	nfs_follow_link,
-	getattr:	nfs_getattr,
-	setattr:	nfs_setattr,
+	.readlink	= nfs_readlink,
+	.follow_link	= nfs_follow_link,
+	.getattr	= nfs_getattr,
+	.setattr	= nfs_setattr,
 };
diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c	Sun Sep 15 19:19:51 2002
+++ b/fs/nfsd/export.c	Sun Sep 15 19:19:51 2002
@@ -35,10 +35,6 @@
 typedef struct svc_client	svc_client;
 typedef struct svc_export	svc_export;
 
-static svc_export *	exp_parent(svc_client *clp, struct super_block *sb,
-					struct dentry *dentry);
-static svc_export *	exp_child(svc_client *clp, struct super_block *sb,
-					struct dentry *dentry);
 static void		exp_unexport_all(svc_client *clp);
 static void		exp_do_unexport(svc_export *unexp);
 static svc_client *	exp_getclientbyname(char *name);
@@ -51,9 +47,25 @@
 #define CLIENT_HASHMASK		(CLIENT_HASHMAX - 1)
 #define CLIENT_HASH(a) \
 		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
-/* XXX: is this adequate for 32bit kdev_t ? */
-#define EXPORT_HASH(dev)	(MINOR(dev) & (NFSCLNT_EXPMAX - 1))
-#define EXPORT_FSID_HASH(fsid)	((fsid) & (NFSCLNT_EXPMAX - 1))
+
+#define	EXPKEY_HASHBITS		8
+#define	EXPKEY_HASHMAX		(1 << EXPKEY_HASHBITS)
+#define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)
+static struct list_head expkey_table[EXPKEY_HASHMAX];
+
+static inline int expkey_hash(struct svc_client *clp, int type, u32 *fsidv)
+{
+	int hash = type;
+	char * cp = (char*)fsidv;
+	int len = (type==0)?8:4;
+	while (len--)
+		hash += *cp++;
+	cp = (char*)&clp;
+	len = sizeof(clp);
+	while (len--)
+		hash += *cp++;
+	return hash & EXPKEY_HASHMASK;
+}
 
 struct svc_clnthash {
 	struct svc_clnthash *	h_next;
@@ -63,123 +75,131 @@
 static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];
 static svc_client *		clients;
 
+/* hash table of exports indexed by dentry+client */
+#define	EXPORT_HASHBITS		8
+#define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
+#define	EXPORT_HASHMASK		(EXPORT_HASHMAX -1)
+
+struct list_head	export_table[EXPORT_HASHMAX];
+
+static int export_hash(svc_client *clp, struct dentry *dentry)
+{
+	void *k[2];
+	unsigned char *cp;
+	int rv, i;
+	k[0] = clp;
+	k[1] = dentry;
+
+	cp = (char*)k;
+	rv = 0;
+	for (i=0; i<sizeof(k); i++)
+		rv ^= cp[i];
+	return rv & EXPORT_HASHMASK;
+}
 
-/*
- * Find the client's export entry matching xdev/xino.
- */
-svc_export *
-exp_get(svc_client *clp, dev_t dev, ino_t ino)
+struct svc_expkey *
+exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv)
 {
-	struct list_head *head, *p;
+	struct list_head *head;
+	struct svc_expkey *ek;
 	
 	if (!clp)
 		return NULL;
 
-	head = &clp->cl_export[EXPORT_HASH(dev)];
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_hash);
-		if (exp->ex_ino == ino && exp->ex_dev ==  dev)
-			return exp;
-	}
+	head = &expkey_table[expkey_hash(clp, fsid_type, fsidv)];
+	list_for_each_entry(ek, head, ek_hash)
+		if (ek->ek_fsidtype == fsid_type &&
+		    fsidv[0] == ek->ek_fsid[0] &&
+		    (fsid_type == 1 || fsidv[1] == ek->ek_fsid[1]) &&
+		    clp      == ek->ek_client)
+			return ek;
+
 	return NULL;
 }
 
 /*
- * Find the client's export entry matching fsid
+ * Find the client's export entry matching xdev/xino.
  */
-svc_export *
-exp_get_fsid(svc_client *clp, int fsid)
+static inline struct svc_expkey *
+exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
 {
-	struct list_head *head, *p;
+	u32 fsidv[2];
+	
+	mk_fsid_v0(fsidv, dev, ino);
+	return exp_find_key(clp, 0, fsidv);
+}
 
+static inline svc_export *
+exp_get(svc_client *clp, dev_t dev, ino_t ino)
+{
+	struct svc_expkey *ek;
 
-	if (!clp)
+	ek = exp_get_key(clp, dev, ino);
+	if (ek)
+		return ek->ek_export;
+	else
 		return NULL;
-
-	head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)];
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_fsid_hash);
-		if (exp->ex_fsid == fsid)
-			return exp;
-	}
-	return NULL;
 }
 
-svc_export *
-exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
+/*
+ * Find the client's export entry matching fsid
+ */
+static inline struct svc_expkey *
+exp_get_fsid_key(svc_client *clp, int fsid)
 {
-	struct list_head *head, *p;
-	int hash = EXPORT_HASH(mnt->mnt_sb->s_dev);
+	u32 fsidv[2];
 
-	if (!clp)
-		return NULL;
+	mk_fsid_v1(fsidv, fsid);
 
-	head = &clp->cl_export[hash];
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_hash);
-		if (exp->ex_dentry == dentry && exp->ex_mnt == mnt)
-			break;
-	}
-	return NULL;
+	return exp_find_key(clp, 1, fsidv);
 }
 
-/*
- * Find the export entry for a given dentry.  <gam3@acm.org>
- */
-static svc_export *
-exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
+static inline svc_export *
+exp_get_fsid(svc_client *clp, int fsid)
 {
-	struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
-	struct list_head *p;
+	struct svc_expkey *ek;
 
-	spin_lock(&dcache_lock);
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_hash);
-		if (is_subdir(dentry, exp->ex_dentry)) {
-			spin_unlock(&dcache_lock);
-			return exp;
-		}
-	}
-	spin_unlock(&dcache_lock);
-	return NULL;
+	ek = exp_get_fsid_key(clp, fsid);
+	if (ek)
+		return ek->ek_export;
+	else
+		return NULL;
 }
 
-/*
- * Find the child export entry for a given fs. This function is used
- * only by the export syscall to keep the export tree consistent.
- * <gam3@acm.org>
- */
-static svc_export *
-exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry)
-{
-	struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
-	struct list_head *p;
-	struct dentry *ndentry;
-
-	spin_lock(&dcache_lock);
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_hash);
-		ndentry = exp->ex_dentry;
-		if (ndentry && is_subdir(ndentry->d_parent, dentry)) {
-			spin_unlock(&dcache_lock);
+svc_export *
+exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
+{
+	svc_export *exp;
+	struct list_head *head = &export_table[export_hash(clp, dentry)];
+
+	if (!clp)
+		return NULL;
+
+	list_for_each_entry(exp, head, ex_hash) {
+		if (exp->ex_dentry == dentry && 
+		    exp->ex_mnt    == mnt &&
+		    exp->ex_client == clp)
 			return exp;
-		}
 	}
-	spin_unlock(&dcache_lock);
 	return NULL;
 }
 
-/* Update parent pointers of all exports */
-static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new)
+/*
+ * Find the export entry for a given dentry.
+ */
+struct svc_export *
+exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
 {
-	struct list_head *head = &clp->cl_list;
-	struct list_head *p;
+	svc_export *exp;
 
-	list_for_each(p, head) {
-		svc_export *exp = list_entry(p, svc_export, ex_list);
-		if (exp->ex_parent == old)
-			exp->ex_parent = new;
+	read_lock(&dparent_lock);
+	exp = exp_get_by_name(clp, mnt, dentry);
+	while (exp == NULL && dentry != dentry->d_parent) {
+		dentry = dentry->d_parent;
+		exp = exp_get_by_name(clp, mnt, dentry);
 	}
+	read_unlock(&dparent_lock);
+	return exp;
 }
 
 /*
@@ -217,23 +237,75 @@
 
 static void exp_fsid_unhash(struct svc_export *exp)
 {
+	struct svc_expkey *ek;
 
 	if ((exp->ex_flags & NFSEXP_FSID) == 0)
 		return;
 
-	list_del_init(&exp->ex_fsid_hash);
+	ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
+	if (ek) {
+		list_del(&ek->ek_hash);
+		kfree(ek);
+	}
 }
 
-static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
+static int exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
 {
 	struct list_head *head;
-
+	struct svc_expkey *ek;
+ 
 	if ((exp->ex_flags & NFSEXP_FSID) == 0)
-		return;
-	head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
-	list_add(&exp->ex_fsid_hash, head);
+		return 0;
+
+	ek = kmalloc(sizeof(*ek), GFP_KERNEL);
+	if (ek == NULL)
+		return -ENOMEM;
+
+	ek->ek_fsidtype = 1;
+	ek->ek_export = exp;
+	ek->ek_client = clp;
+
+	mk_fsid_v1(ek->ek_fsid, exp->ex_fsid);
+	
+	head = &expkey_table[expkey_hash(clp, 1, ek->ek_fsid)];
+	list_add(&ek->ek_hash, head);
+	return 0;
 }
 
+static int exp_hash(struct svc_client *clp, struct svc_export *exp)
+{
+	struct list_head *head;
+	struct svc_expkey *ek;
+	struct inode *inode;
+ 
+	ek = kmalloc(sizeof(*ek), GFP_KERNEL);
+	if (ek == NULL)
+		return -ENOMEM;
+
+	ek->ek_fsidtype = 0;
+	ek->ek_export = exp;
+	ek->ek_client = clp;
+
+	inode = exp->ex_dentry->d_inode;
+	mk_fsid_v0(ek->ek_fsid, inode->i_sb->s_dev, inode->i_ino);
+	
+	head = &expkey_table[expkey_hash(clp, 0, ek->ek_fsid)];
+	list_add(&ek->ek_hash, head);
+	return 0;
+}
+
+static void exp_unhash(struct svc_export *exp)
+{
+	struct svc_expkey *ek;
+	struct inode *inode = exp->ex_dentry->d_inode;
+
+	ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
+	if (ek) {
+		list_del(&ek->ek_hash);
+		kfree(ek);
+	}
+}
+	
 extern struct dentry *
 find_exported_dentry(struct super_block *sb, void *obj, void *parent,
 		     int (*acceptable)(void *context, struct dentry *de),
@@ -245,13 +317,11 @@
 exp_export(struct nfsctl_export *nxp)
 {
 	svc_client	*clp;
-	svc_export	*exp = NULL, *parent;
+	svc_export	*exp = NULL;
 	svc_export	*fsid_exp;
 	struct nameidata nd;
 	struct inode	*inode = NULL;
 	int		err;
-	dev_t		dev;
-	ino_t		ino;
 
 	/* Consistency check */
 	err = -EINVAL;
@@ -276,11 +346,9 @@
 	if (err)
 		goto out_unlock;
 	inode = nd.dentry->d_inode;
-	dev = inode->i_sb->s_dev;
-	ino = inode->i_ino;
 	err = -EINVAL;
 
-	exp = exp_get(clp, dev, ino);
+	exp = exp_get_by_name(clp, nd.mnt, nd.dentry);
 
 	/* must make sure there wont be an ex_fsid clash */
 	if ((nxp->ex_flags & NFSEXP_FSID) &&
@@ -296,8 +364,8 @@
 		exp->ex_anon_uid = nxp->ex_anon_uid;
 		exp->ex_anon_gid = nxp->ex_anon_gid;
 		exp->ex_fsid     = nxp->ex_dev;
-		exp_fsid_hash(clp, exp);
-		err = 0;
+
+		err = exp_fsid_hash(clp, exp);
 		goto finish;
 	}
 
@@ -332,45 +400,30 @@
 		inode->i_sb->s_export_op->find_exported_dentry =
 			find_exported_dentry;
 
-	if ((parent = exp_child(clp, inode->i_sb, nd.dentry)) != NULL) {
-		dprintk("exp_export: export not valid (Rule 3).\n");
-		goto finish;
-	}
-	/* Is this is a sub-export, must be a proper subset of FS */
-	if ((parent = exp_parent(clp, inode->i_sb, nd.dentry)) != NULL) {
-		dprintk("exp_export: sub-export not valid (Rule 2).\n");
-		goto finish;
-	}
-
 	err = -ENOMEM;
 	if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
 		goto finish;
 	dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
 
-	strcpy(exp->ex_path, nxp->ex_path);
 	exp->ex_client = clp;
-	exp->ex_parent = parent;
 	exp->ex_mnt = mntget(nd.mnt);
 	exp->ex_dentry = dget(nd.dentry);
 	exp->ex_flags = nxp->ex_flags;
-	exp->ex_dev = dev;
-	exp->ex_ino = ino;
 	exp->ex_anon_uid = nxp->ex_anon_uid;
 	exp->ex_anon_gid = nxp->ex_anon_gid;
 	exp->ex_fsid = nxp->ex_dev;
 
-
-	/* Update parent pointers of all exports */
-	if (parent)
-		exp_change_parents(clp, parent, exp);
-
-	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
-	list_add_tail(&exp->ex_list, &clp->cl_list);
-
-	exp_fsid_hash(clp, exp);
-
+	list_add_tail(&exp->ex_hash,
+		      &export_table[export_hash(clp, nd.dentry)]);
 	err = 0;
 
+	if (exp_hash(clp, exp) ||
+	    exp_fsid_hash(clp, exp)) {
+		/* failed to create at least one index */
+		exp_do_unexport(exp);
+		err = -ENOMEM;
+	}
+
 finish:
 	path_release(&nd);
 out_unlock:
@@ -390,16 +443,12 @@
 	struct vfsmount *mnt;
 	struct inode	*inode;
 
-	list_del(&unexp->ex_list);
 	list_del(&unexp->ex_hash);
+	exp_unhash(unexp);
 	exp_fsid_unhash(unexp);
-	/* Update parent pointers. */
-	exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
 	dentry = unexp->ex_dentry;
 	mnt = unexp->ex_mnt;
 	inode = dentry->d_inode;
-	if (unexp->ex_dev != inode->i_sb->s_dev || unexp->ex_ino != inode->i_ino)
-		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
 	dput(dentry);
 	mntput(mnt);
 
@@ -412,14 +461,17 @@
 static void
 exp_unexport_all(svc_client *clp)
 {
-	struct list_head *p = &clp->cl_list;
+	struct list_head *lp, *tmp;
+	int index;
 
 	dprintk("unexporting all fs's for clnt %p\n", clp);
 
-	while (!list_empty(p)) {
-		svc_export *exp = list_entry(p->next, svc_export, ex_list);
-		exp_do_unexport(exp);
-	}
+	for (index=0; index<EXPORT_HASHMAX; index++)
+		list_for_each_safe(lp, tmp, &export_table[index]) {
+			svc_export *exp = list_entry(lp, struct svc_export, ex_hash);
+			if (exp->ex_client == clp)
+				exp_do_unexport(exp);
+		}
 }
 
 /*
@@ -476,7 +528,7 @@
 	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
 		 path, nd.dentry, clp->cl_ident,
 		 inode->i_sb->s_id, inode->i_ino);
-	exp = exp_parent(clp, inode->i_sb, nd.dentry);
+	exp = exp_parent(clp, nd.mnt, nd.dentry);
 	if (!exp) {
 		dprintk("nfsd: exp_rootfh export not found.\n");
 		goto out;
@@ -555,56 +607,52 @@
 static void *e_start(struct seq_file *m, loff_t *pos)
 {
 	loff_t n = *pos;
-	unsigned client, export;
-	svc_client *clp;
-	struct list_head *p;
+	unsigned hash, export;
+	svc_export  *exp;
 	
 	exp_readlock();
 	if (!n--)
 		return (void *)1;
-	client = n >> 32;
+	hash = n >> 32;
 	export = n & ((1LL<<32) - 1);
-	for (clp = clients; client && clp; clp = clp->cl_next, client--)
-		;
-	if (!clp)
-		return NULL;
-	list_for_each(p, &clp->cl_list)
+
+	list_for_each_entry(exp, &export_table[hash], ex_hash)
 		if (!export--)
-			return list_entry(p, svc_export, ex_list);
+			return exp;
 	n &= ~((1LL<<32) - 1);
 	do {
-		clp = clp->cl_next;
+		hash++;
 		n += 1LL<<32;
-	} while(clp && list_empty(&clp->cl_list));
-	if (!clp)
+	} while(hash < EXPORT_HASHMAX && list_empty(&export_table[hash]));
+	if (hash >= EXPORT_HASHMAX)
 		return NULL;
 	*pos = n+1;
-	return list_entry(clp->cl_list.next, svc_export, ex_list);
+	return list_entry(export_table[hash].next, svc_export, ex_hash);
 }
 
 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
 {
 	svc_export *exp = p;
-	svc_client *clp;
+	int hash = (*pos >> 32);
 
 	if (p == (void *)1)
-		clp = clients;
-	else if (exp->ex_list.next == &exp->ex_client->cl_list) {
-		clp = exp->ex_client->cl_next;
+		hash = 0;
+	else if (exp->ex_hash.next == &export_table[hash]) {
+		hash++;
 		*pos += 1LL<<32;
 	} else {
 		++*pos;
-		return list_entry(exp->ex_list.next, svc_export, ex_list);
+		return list_entry(exp->ex_hash.next, svc_export, ex_hash);
 	}
 	*pos &= ~((1LL<<32) - 1);
-	while (clp && list_empty(&clp->cl_list)) {
-		clp = clp->cl_next;
+	while (hash < EXPORT_HASHMAX && list_empty(&export_table[hash])) {
+		hash++;
 		*pos += 1LL<<32;
 	}
-	if (!clp)
+	if (hash >= EXPORT_HASHMAX)
 		return NULL;
 	++*pos;
-	return list_entry(clp->cl_list.next, svc_export, ex_list);
+	return list_entry(export_table[hash].next, svc_export, ex_hash);
 }
 
 static void e_stop(struct seq_file *m, void *p)
@@ -634,7 +682,7 @@
 	{ 0, {"", ""}}
 };
 
-static void exp_flags(struct seq_file *m, int flag, int fsid)
+static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
 {
 	int first = 0;
 	struct flags *flg;
@@ -646,6 +694,10 @@
 	}
 	if (flag & NFSEXP_FSID)
 		seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
+	if (anonu != (uid_t)-2 && anonu != (0x10000-2))
+		seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
+	if (anong != (gid_t)-2 && anong != (0x10000-2))
+		seq_printf(m, "%sanongid=%d", first++?",":"", anong);
 }
 
 static inline void mangle(struct seq_file *m, const char *s)
@@ -657,7 +709,7 @@
 {
 	struct svc_export *exp = p;
 	struct svc_client *clp;
-	int j, first = 0;
+	char *pbuf;
 
 	if (p == (void *)1) {
 		seq_puts(m, "# Version 1.1\n");
@@ -667,36 +719,16 @@
 
 	clp = exp->ex_client;
 
-	mangle(m, exp->ex_path);
+	pbuf = m->private;
+	mangle(m, d_path(exp->ex_dentry, exp->ex_mnt,
+			 pbuf, PAGE_SIZE));
+
 	seq_putc(m, '\t');
 	mangle(m, clp->cl_ident);
 	seq_putc(m, '(');
-	exp_flags(m, exp->ex_flags, exp->ex_fsid);
-	seq_puts(m, ") # ");
-	for (j = 0; j < clp->cl_naddr; j++) {
-		struct svc_clnthash **hp, **head, *tmp;
-		struct in_addr addr = clp->cl_addr[j]; 
-
-		head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
-		for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
-			if (tmp->h_addr.s_addr == addr.s_addr)
-				break;
-		}
-		if (tmp) {
-			if (first++)
-				seq_putc(m, ' ');
-			if (tmp->h_client != clp)
-				seq_putc(m, '(');
-			seq_printf(m, "%d.%d.%d.%d",
-				htonl(addr.s_addr) >> 24 & 0xff,
-				htonl(addr.s_addr) >> 16 & 0xff,
-				htonl(addr.s_addr) >>  8 & 0xff,
-				htonl(addr.s_addr) >>  0 & 0xff);
-			if (tmp->h_client != clp)
-				seq_putc(m, ')');
-		}
-	}
-	seq_putc(m, '\n');
+	exp_flags(m, exp->ex_flags, exp->ex_fsid, 
+		  exp->ex_anon_uid, exp->ex_anon_gid);
+	seq_puts(m, ")\n");
 	return 0;
 }
 
@@ -741,16 +773,10 @@
 		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
 			goto out_unlock;
 		memset(clp, 0, sizeof(*clp));
-		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
-			INIT_LIST_HEAD(&clp->cl_export[i]);
-			INIT_LIST_HEAD(&clp->cl_expfsid[i]);
-		}
-		INIT_LIST_HEAD(&clp->cl_list);
 
 		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
 
 		strcpy(clp->cl_ident, ncp->cl_ident);
-		clp->cl_idlen = ilen;
 	}
 
 	/* Allocate hash buckets */
@@ -765,19 +791,13 @@
 		}
 	}
 
-	/* Copy addresses. */
-	for (i = 0; i < ncp->cl_naddr; i++) {
-		clp->cl_addr[i] = ncp->cl_addrlist[i];
-	}
-	clp->cl_naddr = ncp->cl_naddr;
-
 	/* Remove old client hash entries. */
 	if (change)
 		exp_unhashclient(clp);
 
 	/* Insert client into hashtable. */
 	for (i = 0; i < ncp->cl_naddr; i++) {
-		struct in_addr	addr = clp->cl_addr[i];
+		struct in_addr	addr = ncp->cl_addrlist[i];
 		int		hash;
 
 		hash = CLIENT_HASH(addr.s_addr);
@@ -838,9 +858,7 @@
 {
 	exp_unhashclient(clp);
 
-	/* umap_free(&(clp->cl_umap)); */
 	exp_unexport_all(clp);
-	nfsd_lockd_unexport(clp);
 	kfree (clp);
 }
 
@@ -869,8 +887,6 @@
 			}
 		}
 	}
-	if (count != clp->cl_naddr)
-		printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
 	if (err)
 		goto again;
 	for (i = 0; i < count; i++)
@@ -878,18 +894,6 @@
 }
 
 /*
- * Lockd is shutting down and tells us to unregister all clients
- */
-void
-exp_nlmdetach(void)
-{
-	struct svc_client	*clp;
-
-	for (clp = clients; clp; clp = clp->cl_next)
-		nfsd_lockd_unexport(clp);
-}
-
-/*
  * Verify that string is non-empty and does not exceed max length.
  */
 static int
@@ -918,6 +922,12 @@
 	for (i = 0; i < CLIENT_HASHMAX; i++)
 		clnt_hash[i] = NULL;
 	clients = NULL;
+
+	for (i = 0; i < EXPORT_HASHMAX ; i++)
+		INIT_LIST_HEAD(&export_table[i]);
+
+	for (i = 0; i < EXPKEY_HASHMAX; i++)
+		INIT_LIST_HEAD(&expkey_table[i]);
 
 }
 
diff -Nru a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
--- a/fs/nfsd/lockd.c	Sun Sep 15 19:19:29 2002
+++ b/fs/nfsd/lockd.c	Sun Sep 15 19:19:29 2002
@@ -31,12 +31,19 @@
 	memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size);
 	fh.fh_export = NULL;
 
-	nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
+	exp_readlock();
+	rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
+	if (rqstp->rq_client == NULL)
+		nfserr = nfserr_stale;
+	else
+		nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
 	if (!nfserr) {
 		dget(filp->f_dentry);
 		mntget(filp->f_vfsmnt);
 	}
 	fh_put(&fh);
+	rqstp->rq_client = NULL;
+	exp_readunlock();
  	/* nlm and nfsd don't share error codes.
 	 * we invent: 0 = no error
 	 *            1 = stale file handle
@@ -61,23 +68,9 @@
 }
 
 struct nlmsvc_binding		nfsd_nlm_ops = {
-	.exp_readlock	= exp_readlock,		/* lock export table for reading */
-	.exp_unlock	= exp_readunlock,		/* unlock export table */
-	.exp_getclient	= exp_getclient,		/* look up NFS client */
 	.fopen		= nlm_fopen,		/* open file for locking */
 	.fclose		= nlm_fclose,		/* close file */
-	.detach		= exp_nlmdetach,		/* lockd shutdown notification */
 };
-
-/*
- * When removing an NFS client entry, notify lockd that it is gone.
- * FIXME: We should do the same when unexporting an NFS volume.
- */
-void
-nfsd_lockd_unexport(struct svc_client *clnt)
-{
-	nlmsvc_invalidate_client(clnt);
-}
 
 void
 nfsd_lockd_init(void)
diff -Nru a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
--- a/fs/nfsd/nfsctl.c	Sun Sep 15 19:19:29 2002
+++ b/fs/nfsd/nfsctl.c	Sun Sep 15 19:19:29 2002
@@ -127,13 +127,30 @@
 extern struct seq_operations nfs_exports_op;
 static int exports_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &nfs_exports_op);
+	int res;
+	res = seq_open(file, &nfs_exports_op);
+	if (!res) {
+		char *namebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (namebuf == NULL)
+			res = -ENOMEM;
+		else
+			((struct seq_file *)file->private_data)->private = namebuf;
+	}
+	return res;
 }
+static int exports_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *m = (struct seq_file *)file->private_data;
+	kfree(m->private);
+	m->private = NULL;
+	return seq_release(inode, file);
+}
+
 static struct file_operations exports_operations = {
 	.open		= exports_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= seq_release,
+	.release	= exports_release,
 };
 
 /*
diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c	Sun Sep 15 19:19:30 2002
+++ b/fs/nfsd/nfsfh.c	Sun Sep 15 19:19:30 2002
@@ -97,14 +97,10 @@
 	rqstp->rq_reffh = fh;
 
 	if (!fhp->fh_dentry) {
-		dev_t xdev = 0;
-		ino_t xino = 0;
 		__u32 *datap=NULL;
 		__u32 tfh[3];		/* filehandle fragment for oldstyle filehandles */
 		int fileid_type;
 		int data_left = fh->fh_size/4;
-		int nfsdev;
-		int fsid = 0;
 
 		error = nfserr_stale;
 		if (rqstp->rq_vers > 2)
@@ -113,6 +109,7 @@
 			return nfserr_nofilehandle;
 
 		if (fh->fh_version == 1) {
+			int len;
 			datap = fh->fh_auth;
 			if (--data_left<0) goto out;
 			switch (fh->fh_auth_type) {
@@ -122,39 +119,37 @@
 
 			switch (fh->fh_fsid_type) {
 			case 0:
-				if ((data_left-=2)<0) goto out;
-				nfsdev = ntohl(*datap++);
-				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
-				xino = *datap++;
+				len = 2;
 				break;
 			case 1:
-				if ((data_left-=1)<0) goto out;
-				fsid = *datap++;
+				len = 1;
 				break;
 			default:
 				goto out;
 			}
+			if ((data_left -= len)<0) goto out;
+			exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap);
+			datap += len;
 		} else {
+			dev_t xdev;
+			ino_t xino;
 			if (fh->fh_size != NFS_FHSIZE)
 				goto out;
 			/* assume old filehandle format */
 			xdev = u32_to_dev_t(fh->ofh_xdev);
 			xino = u32_to_ino_t(fh->ofh_xino);
+			mk_fsid_v0(tfh, xdev, xino);
+			exp = exp_find(rqstp->rq_client, 0, tfh);
 		}
 
 		/*
 		 * Look up the export entry.
 		 */
 		error = nfserr_stale; 
-		if (fh->fh_version == 1 && fh->fh_fsid_type == 1)
-			exp = exp_get_fsid(rqstp->rq_client, fsid);
-		else
-			exp = exp_get(rqstp->rq_client, xdev, xino);
 
-		if (!exp) {
+		if (!exp)
 			/* export entry revoked */
 			goto out;
-		}
 
 		/* Check if the request originated from a secure port. */
 		error = nfserr_perm;
@@ -322,9 +317,11 @@
 	struct inode * inode = dentry->d_inode;
 	struct dentry *parent = dentry->d_parent;
 	__u32 *datap;
+	dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev;
 
 	dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
-		MAJOR(exp->ex_dev), MINOR(exp->ex_dev), (long) exp->ex_ino,
+		MAJOR(ex_dev), MINOR(ex_dev),
+		(long) exp->ex_dentry->d_inode->i_ino,
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
@@ -351,9 +348,9 @@
 		memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 		fhp->fh_handle.fh_size = NFS_FHSIZE;
 		fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
-		fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+		fhp->fh_handle.ofh_dev =  htonl((MAJOR(ex_dev)<<16)| MINOR(ex_dev));
 		fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
-		fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
+		fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_dentry->d_inode->i_ino);
 		fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry));
 		if (inode)
 			_fh_update_old(dentry, exp, &fhp->fh_handle);
@@ -365,13 +362,14 @@
 		    (ref_fh_fsid_type == 1)) {
 			fhp->fh_handle.fh_fsid_type = 1;
 			/* fsid_type 1 == 4 bytes filesystem id */
-			*datap++ = exp->ex_fsid;
+			mk_fsid_v1(datap, exp->ex_fsid);
+			datap += 1;
 			fhp->fh_handle.fh_size = 2*4;
 		} else {
 			fhp->fh_handle.fh_fsid_type = 0;
 			/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-			*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
-			*datap++ = ino_t_to_u32(exp->ex_ino);
+			mk_fsid_v0(datap, ex_dev, exp->ex_dentry->d_inode->i_ino);
+			datap += 2;
 			fhp->fh_handle.fh_size = 3*4;
 		}
 		if (inode) {
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Sun Sep 15 19:19:34 2002
+++ b/fs/nfsd/vfs.c	Sun Sep 15 19:19:34 2002
@@ -119,24 +119,24 @@
 		else {
 			/* checking mountpoint crossing is very different when stepping up */
 			struct svc_export *exp2 = NULL;
-			struct dentry *dp, *old;
+			struct dentry *dp;
 			struct vfsmount *mnt = mntget(exp->ex_mnt);
 			dentry = dget(dparent);
 			while(follow_up(&mnt, &dentry))
 				;
-			old = dentry;
 			read_lock(&dparent_lock);
-			dp = dentry->d_parent;
-			for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent)
-				exp2 = exp_get_by_name(exp->ex_client, mnt, dp);
+			dp = dget(dentry->d_parent);
+			read_unlock(&dparent_lock);
+			dput(dentry);
+			dentry = dp;
+
+			exp2 = exp_parent(exp->ex_client, mnt, dentry);
 			if (!exp2) {
+				dput(dentry);
 				dentry = dget(dparent);
 			} else {
-				dget(dentry->d_parent);
 				exp = exp2;
 			}
-			read_unlock(&dparent_lock);
-			dput(old);
 			mntput(mnt);
 		}
 	} else {
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Sun Sep 15 19:19:30 2002
+++ b/fs/partitions/check.c	Sun Sep 15 19:19:30 2002
@@ -251,7 +251,7 @@
 			p[j-1].start_sect = state->parts[j].from;
 			p[j-1].nr_sects = state->parts[j].size;
 #if CONFIG_BLK_DEV_MD
-			if (!state->parts[j-1].flags)
+			if (!state->parts[j].flags)
 				continue;
 			md_autodetect_dev(bdev->bd_dev+j);
 #endif
@@ -327,7 +327,7 @@
 	devfs_auto_unregister(dev->disk_de, slave);
 	if (!(dev->flags & GENHD_FL_DEVFS))
 		devfs_auto_unregister (slave, dir);
-	for (part = 1, p++; part < max_p; part++, p++)
+	for (part = 1; part < max_p; part++, p++)
 		if (p->nr_sects)
 			devfs_register_partition(dev, part);
 #endif
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Sun Sep 15 19:19:28 2002
+++ b/fs/proc/base.c	Sun Sep 15 19:19:28 2002
@@ -1136,7 +1136,7 @@
 
 	index--;
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
 		int pid = p->pid;
 		if (!pid)
 			continue;
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Sun Sep 15 19:19:30 2002
+++ b/fs/proc/inode.c	Sun Sep 15 19:19:30 2002
@@ -235,7 +235,9 @@
 	 * Fixup the root inode's nlink value
 	 */
 	read_lock(&tasklist_lock);
-	for_each_task(p) if (p->pid) root_inode->i_nlink++;
+	for_each_process(p)
+		if (p->pid)
+			root_inode->i_nlink++;
 	read_unlock(&tasklist_lock);
 	s->s_root = d_alloc_root(root_inode);
 	if (!s->s_root)
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Sun Sep 15 19:19:30 2002
+++ b/fs/ramfs/inode.c	Sun Sep 15 19:19:30 2002
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
 
 #include <asm/uaccess.h>
 
@@ -41,6 +42,11 @@
 static struct file_operations ramfs_file_operations;
 static struct inode_operations ramfs_dir_inode_operations;
 
+static struct backing_dev_info ramfs_backing_dev_info = {
+	.ra_pages	= 0,	/* No readahead */
+	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+};
+
 /*
  * Read a page. Again trivial. If it didn't already exist
  * in the page cache, it is zero-filled.
@@ -69,7 +75,7 @@
 		kunmap_atomic(kaddr, KM_USER0);
 		SetPageUptodate(page);
 	}
-	SetPageDirty(page);
+	set_page_dirty(page);
 	return 0;
 }
 
@@ -95,6 +101,7 @@
 		inode->i_blocks = 0;
 		inode->i_rdev = NODEV;
 		inode->i_mapping->a_ops = &ramfs_aops;
+		inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		switch (mode & S_IFMT) {
 		default:
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Sun Sep 15 19:19:56 2002
+++ b/fs/read_write.c	Sun Sep 15 19:19:56 2002
@@ -286,9 +286,29 @@
 	return ret;
 }
 
+/*
+ * Reduce an iovec's length in-place.  Return the resulting number of segments
+ */
+unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
+{
+	unsigned long seg = 0;
+	size_t len = 0;
+
+	while (seg < nr_segs) {
+		seg++;
+		if (len + iov->iov_len >= to) {
+			iov->iov_len = to - len;
+			break;
+		}
+		len += iov->iov_len;
+		iov++;
+	}
+	return seg;
+}
+
 static ssize_t do_readv_writev(int type, struct file *file,
 			       const struct iovec * vector,
-			       unsigned long count)
+			       unsigned long nr_segs)
 {
 	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
@@ -296,73 +316,86 @@
 	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
-	ssize_t ret, i;
+	ssize_t ret = -EINVAL;
+	int seg;
 	io_fn_t fn;
 	iov_fn_t fnv;
 	struct inode *inode;
 
 	/*
+	 * SuS says "The readv() function *may* fail if the iovcnt argument
+	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+	 * traditionally returned -EINVAL for zero segments, so...
+	 */
+	if (nr_segs == 0)
+		goto out;
+
+	/*
 	 * First get the "struct iovec" from user memory and
 	 * verify all the pointers
 	 */
-	ret = 0;
-	if (!count)
-		goto out_nofree;
-	ret = -EINVAL;
-	if (count > UIO_MAXIOV)
-		goto out_nofree;
+	if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
+		goto out;
 	if (!file->f_op)
-		goto out_nofree;
-	if (count > UIO_FASTIOV) {
+		goto out;
+	if (nr_segs > UIO_FASTIOV) {
 		ret = -ENOMEM;
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
-			goto out_nofree;
+			goto out;
 	}
 	ret = -EFAULT;
-	if (copy_from_user(iov, vector, count*sizeof(*vector)))
+	if (copy_from_user(iov, vector, nr_segs*sizeof(*vector)))
 		goto out;
 
 	/*
 	 * Single unix specification:
-	 * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
-	 * The total length is fitting an ssize_t
+	 * We should -EINVAL if an element length is not >= 0 and fitting an
+	 * ssize_t.  The total length is fitting an ssize_t
 	 *
 	 * Be careful here because iov_len is a size_t not an ssize_t
 	 */
-	 
 	tot_len = 0;
 	ret = -EINVAL;
-	for (i = 0 ; i < count ; i++) {
+	for (seg = 0 ; seg < nr_segs; seg++) {
 		ssize_t tmp = tot_len;
-		ssize_t len = (ssize_t)iov[i].iov_len;
+		ssize_t len = (ssize_t)iov[seg].iov_len;
 		if (len < 0)	/* size_t not fitting an ssize_t .. */
 			goto out;
 		tot_len += len;
 		if (tot_len < tmp) /* maths overflow on the ssize_t */
 			goto out;
 	}
+	if (tot_len == 0) {
+		ret = 0;
+		goto out;
+	}
 
 	inode = file->f_dentry->d_inode;
 	/* VERIFY_WRITE actually means a read, as we write to user space */
-	ret = locks_verify_area((type == VERIFY_WRITE
+	ret = locks_verify_area((type == READ 
 				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
 				inode, file, file->f_pos, tot_len);
-	if (ret) goto out;
+	if (ret)
+		goto out;
 
-	fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
+	fnv = NULL;
+	if (type == READ) {
+		fn = file->f_op->read;
+		fnv = file->f_op->readv;
+	} else {
+		fn = (io_fn_t)file->f_op->write;
+		fnv = file->f_op->writev;
+	}
 	if (fnv) {
-		ret = fnv(file, iov, count, &file->f_pos);
+		ret = fnv(file, iov, nr_segs, &file->f_pos);
 		goto out;
 	}
 
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	fn = (type == VERIFY_WRITE ? file->f_op->read :
-	      (io_fn_t) file->f_op->write);
-
+	/* Do it by hand, with file-ops */
 	ret = 0;
 	vector = iov;
-	while (count > 0) {
+	while (nr_segs > 0) {
 		void * base;
 		size_t len;
 		ssize_t nr;
@@ -370,7 +403,7 @@
 		base = vector->iov_base;
 		len = vector->iov_len;
 		vector++;
-		count--;
+		nr_segs--;
 
 		nr = fn(file, base, len, &file->f_pos);
 
@@ -382,20 +415,18 @@
 		if (nr != len)
 			break;
 	}
-
 out:
 	if (iov != iovstack)
 		kfree(iov);
-out_nofree:
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	if ((ret + (type == VERIFY_WRITE)) > 0)
+	if ((ret + (type == READ)) > 0)
 		dnotify_parent(file->f_dentry,
-			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
+				(type == READ) ? DN_MODIFY : DN_ACCESS);
 	return ret;
 }
 
-asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
-			     unsigned long count)
+
+asmlinkage ssize_t
+sys_readv(unsigned long fd, const struct iovec *vector, unsigned long nr_segs)
 {
 	struct file * file;
 	ssize_t ret;
@@ -409,7 +440,7 @@
 	    (file->f_op->readv || file->f_op->read)) {
 		ret = security_ops->file_permission (file, MAY_READ);
 		if (!ret)
-			ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
+			ret = do_readv_writev(READ, file, vector, nr_segs);
 	}
 	fput(file);
 
@@ -417,8 +448,8 @@
 	return ret;
 }
 
-asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
-			      unsigned long count)
+asmlinkage ssize_t
+sys_writev(unsigned long fd, const struct iovec * vector, unsigned long nr_segs)
 {
 	struct file * file;
 	ssize_t ret;
@@ -432,7 +463,7 @@
 	    (file->f_op->writev || file->f_op->write)) {
 		ret = security_ops->file_permission (file, MAY_WRITE);
 		if (!ret)
-			ret = do_readv_writev(VERIFY_READ, file, vector, count);
+			ret = do_readv_writev(WRITE, file, vector, nr_segs);
 	}
 	fput(file);
 
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Sun Sep 15 19:19:37 2002
+++ b/fs/super.c	Sun Sep 15 19:19:37 2002
@@ -58,7 +58,6 @@
 		}
 		INIT_LIST_HEAD(&s->s_dirty);
 		INIT_LIST_HEAD(&s->s_io);
-		INIT_LIST_HEAD(&s->s_locked_inodes);
 		INIT_LIST_HEAD(&s->s_files);
 		INIT_LIST_HEAD(&s->s_instances);
 		INIT_LIST_HEAD(&s->s_anon);
diff -Nru a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
--- a/fs/udf/udfdecl.h	Sun Sep 15 19:19:37 2002
+++ b/fs/udf/udfdecl.h	Sun Sep 15 19:19:37 2002
@@ -32,7 +32,7 @@
 #define UDF_NAME_LEN		255
 #define UDF_PATH_LEN		1023
 
-#define CURRENT_UTIME	(xtime.tv_usec)
+#define CURRENT_UTIME	(xtime.tv_nsec / 1000)
 
 #define udf_file_entry_alloc_offset(inode)\
 	((UDF_I_EXTENDED_FE(inode) ?\
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Sun Sep 15 19:19:28 2002
+++ b/fs/ufs/super.c	Sun Sep 15 19:19:28 2002
@@ -605,7 +605,7 @@
 	}
 	
 again:	
-	if (sb_set_blocksize(sb, block_size)) {
+	if (!sb_set_blocksize(sb, block_size)) {
 		printk(KERN_ERR "UFS: failed to set blocksize\n");
 		goto failed;
 	}
diff -Nru a/include/asm-alpha/hdreg.h b/include/asm-alpha/hdreg.h
--- a/include/asm-alpha/hdreg.h	Sun Sep 15 19:19:37 2002
+++ b/include/asm-alpha/hdreg.h	Sun Sep 15 19:19:37 2002
@@ -7,6 +7,6 @@
 #ifndef __ASMalpha_HDREG_H
 #define __ASMalpha_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMalpha_HDREG_H */
diff -Nru a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
--- a/include/asm-alpha/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-alpha/pgtable.h	Sun Sep 15 19:19:29 2002
@@ -370,4 +370,6 @@
 /* We have our own get_unmapped_area to cope with ADDR_LIMIT_32BIT.  */
 #define HAVE_ARCH_UNMAPPED_AREA
 
+typedef pte_t *pte_addr_t;
+
 #endif /* _ALPHA_PGTABLE_H */
diff -Nru a/include/asm-alpha/signal.h b/include/asm-alpha/signal.h
--- a/include/asm-alpha/signal.h	Sun Sep 15 19:19:48 2002
+++ b/include/asm-alpha/signal.h	Sun Sep 15 19:19:48 2002
@@ -186,7 +186,6 @@
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
 
-#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER
 #define HAVE_ARCH_SYS_PAUSE
 
 #endif
diff -Nru a/include/asm-alpha/system.h b/include/asm-alpha/system.h
--- a/include/asm-alpha/system.h	Sun Sep 15 19:19:52 2002
+++ b/include/asm-alpha/system.h	Sun Sep 15 19:19:52 2002
@@ -311,6 +311,8 @@
 #define local_irq_save(flags)	do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
 #define local_irq_restore(flags)	do { barrier(); setipl(flags); barrier(); } while(0)
 
+#define irqs_disabled()	(getipl() == IPL_MAX)
+
 /*
  * TB routines..
  */
diff -Nru a/include/asm-arm/hdreg.h b/include/asm-arm/hdreg.h
--- a/include/asm-arm/hdreg.h	Sun Sep 15 19:19:46 2002
+++ b/include/asm-arm/hdreg.h	Sun Sep 15 19:19:46 2002
@@ -7,7 +7,7 @@
 #ifndef __ASMARM_HDREG_H
 #define __ASMARM_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMARM_HDREG_H */
 
diff -Nru a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
--- a/include/asm-arm/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-arm/pgtable.h	Sun Sep 15 19:19:29 2002
@@ -161,6 +161,8 @@
 #define io_remap_page_range(vma,from,phys,size,prot) \
 		remap_page_range(vma,from,phys,size,prot)
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASMARM_PGTABLE_H */
diff -Nru a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
--- a/include/asm-cris/pgtable.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-cris/pgtable.h	Sun Sep 15 19:19:28 2002
@@ -515,4 +515,6 @@
  */
 #define pgtable_cache_init()   do { } while (0)
 
+typedef pte_t *pte_addr_t;
+
 #endif /* _CRIS_PGTABLE_H */
diff -Nru a/include/asm-generic/rmap.h b/include/asm-generic/rmap.h
--- a/include/asm-generic/rmap.h	Sun Sep 15 19:19:53 2002
+++ b/include/asm-generic/rmap.h	Sun Sep 15 19:19:53 2002
@@ -13,6 +13,16 @@
  * - page->index has the high bits of the address
  * - the lower bits of the address are calculated from the
  *   offset of the page table entry within the page table page
+ *
+ * For CONFIG_HIGHPTE, we need to represent the address of a pte in a
+ * scalar pte_addr_t.  The pfn of the pte's page is shifted left by PAGE_SIZE
+ * bits and is then ORed with the byte offset of the pte within its page.
+ *
+ * For CONFIG_HIGHMEM4G, the pte_addr_t is 32 bits.  20 for the pfn, 12 for
+ * the offset.
+ *
+ * For CONFIG_HIGHMEM64G, the pte_addr_t is 64 bits.  52 for the pfn, 12 for
+ * the offset.
  */
 #include <linux/mm.h>
 
@@ -39,16 +49,42 @@
 
 static inline struct mm_struct * ptep_to_mm(pte_t * ptep)
 {
-	struct page * page = virt_to_page(ptep);
+	struct page * page = kmap_atomic_to_page(ptep);
 	return (struct mm_struct *) page->mapping;
 }
 
 static inline unsigned long ptep_to_address(pte_t * ptep)
 {
-	struct page * page = virt_to_page(ptep);
+	struct page * page = kmap_atomic_to_page(ptep);
 	unsigned long low_bits;
 	low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE;
 	return page->index + low_bits;
 }
+
+#if CONFIG_HIGHPTE
+static inline pte_addr_t ptep_to_paddr(pte_t *ptep)
+{
+	pte_addr_t paddr;
+	paddr = ((pte_addr_t)page_to_pfn(kmap_atomic_to_page(ptep))) << PAGE_SHIFT;
+	return paddr + (pte_addr_t)((unsigned long)ptep & ~PAGE_MASK);
+}
+#else
+static inline pte_addr_t ptep_to_paddr(pte_t *ptep)
+{
+	return (pte_addr_t)ptep;
+}
+#endif
+
+#ifndef CONFIG_HIGHPTE
+static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr)
+{
+	return (pte_t *)pte_paddr;
+}
+
+static inline void rmap_ptep_unmap(pte_t *pte)
+{
+	return;
+}
+#endif
 
 #endif /* _GENERIC_RMAP_H */
diff -Nru a/include/asm-i386/apic.h b/include/asm-i386/apic.h
--- a/include/asm-i386/apic.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-i386/apic.h	Sun Sep 15 19:20:24 2002
@@ -89,6 +89,7 @@
 
 extern unsigned int apic_timer_irqs [NR_CPUS];
 extern int check_nmi_watchdog (void);
+extern void enable_NMI_through_LVT0 (void * dummy);
 
 extern unsigned int nmi_watchdog;
 #define NMI_NONE	0
diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
--- a/include/asm-i386/fixmap.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-i386/fixmap.h	Sun Sep 15 19:19:28 2002
@@ -103,6 +103,7 @@
 #define FIXADDR_START	(FIXADDR_TOP - __FIXADDR_SIZE)
 
 #define __fix_to_virt(x)	(FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)	((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
 
 extern void __this_fixmap_does_not_exist(void);
 
@@ -126,6 +127,12 @@
 		__this_fixmap_does_not_exist();
 
         return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+	return __virt_to_fix(vaddr);
 }
 
 #endif
diff -Nru a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h	Sun Sep 15 19:20:10 2002
+++ b/include/asm-i386/hardirq.h	Sun Sep 15 19:20:10 2002
@@ -27,8 +27,8 @@
  * - ( bit 26 is the PREEMPT_ACTIVE flag. )
  *
  * PREEMPT_MASK: 0x000000ff
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x00ff0000
  */
 
 #define PREEMPT_BITS	8
diff -Nru a/include/asm-i386/hdreg.h b/include/asm-i386/hdreg.h
--- a/include/asm-i386/hdreg.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-i386/hdreg.h	Sun Sep 15 19:19:28 2002
@@ -7,6 +7,6 @@
 #ifndef __ASMi386_HDREG_H
 #define __ASMi386_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMi386_HDREG_H */
diff -Nru a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
--- a/include/asm-i386/highmem.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-i386/highmem.h	Sun Sep 15 19:19:29 2002
@@ -122,6 +122,19 @@
 	dec_preempt_count();
 }
 
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+	unsigned long idx, vaddr = (unsigned long)ptr;
+	pte_t *pte;
+
+	if (vaddr < FIXADDR_START)
+		return virt_to_page(ptr);
+
+	idx = virt_to_fix(vaddr);
+	pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+	return pte_page(*pte);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -Nru a/include/asm-i386/ide.h b/include/asm-i386/ide.h
--- a/include/asm-i386/ide.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-i386/ide.h	Sun Sep 15 19:19:29 2002
@@ -77,20 +77,6 @@
 #endif
 }
 
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMi386_IDE_H */
diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h
--- a/include/asm-i386/kmap_types.h	Sun Sep 15 19:20:05 2002
+++ b/include/asm-i386/kmap_types.h	Sun Sep 15 19:20:05 2002
@@ -19,9 +19,10 @@
 D(6)	KM_BIO_DST_IRQ,
 D(7)	KM_PTE0,
 D(8)	KM_PTE1,
-D(9)	KM_IRQ0,
-D(10)	KM_IRQ1,
-D(11)	KM_TYPE_NR
+D(9)	KM_PTE2,
+D(10)	KM_IRQ0,
+D(11)	KM_IRQ1,
+D(12)	KM_TYPE_NR
 };
 
 #undef D
diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
--- a/include/asm-i386/mmzone.h	Sun Sep 15 19:19:46 2002
+++ b/include/asm-i386/mmzone.h	Sun Sep 15 19:19:46 2002
@@ -11,8 +11,8 @@
 #ifdef CONFIG_X86_NUMAQ
 #include <asm/numaq.h>
 #else
-#define PHYSADDR_TO_NID(pa)	(0)
-#define PFN_TO_NID(pfn)		(0)
+#define pa_to_nid(pa)	(0)
+#define pfn_to_nid(pfn)		(0)
 #ifdef CONFIG_NUMA
 #define _cpu_to_node(cpu) 0
 #endif /* CONFIG_NUMA */
@@ -22,11 +22,7 @@
 #define numa_node_id() _cpu_to_node(smp_processor_id())
 #endif /* CONFIG_NUMA */
 
-struct plat_pglist_data {
-	pg_data_t	gendata;
-};
-
-extern struct plat_pglist_data *plat_node_data[];
+extern struct pglist_data *node_data[];
 
 /*
  * Following are macros that are specific to this numa platform.
@@ -48,12 +44,9 @@
 #define alloc_bootmem_low_pages_node(ignore, x) \
 	__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0)
 
-#define PLAT_NODE_DATA(n)		(plat_node_data[(n)])
-#define PLAT_NODE_DATA_STARTNR(n)	\
-	(PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
-#define PLAT_NODE_DATA_SIZE(n)		(PLAT_NODE_DATA(n)->gendata.node_size)
-#define PLAT_NODE_DATA_LOCALNR(pfn, n) \
-	((pfn) - PLAT_NODE_DATA(n)->gendata.node_start_pfn)
+#define node_startnr(nid)	(node_data[nid]->node_start_mapnr)
+#define node_size(nid)		(node_data[nid]->node_size)
+#define node_localnr(pfn, nid)	((pfn) - node_data[nid]->node_start_pfn)
 
 /*
  * Following are macros that each numa implmentation must define.
@@ -62,39 +55,23 @@
 /*
  * Given a kernel address, find the home node of the underlying memory.
  */
-#define KVADDR_TO_NID(kaddr)	PHYSADDR_TO_NID(__pa(kaddr))
+#define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
 
 /*
  * Return a pointer to the node data for node n.
  */
-#define NODE_DATA(n)	(&((PLAT_NODE_DATA(n))->gendata))
+#define NODE_DATA(nid)		(node_data[nid])
 
-/*
- * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
- */
-#define NODE_MEM_MAP(nid)	(NODE_DATA(nid)->node_mem_map)
-
-/*
- * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
- */
-#define ADDR_TO_MAPBASE(kaddr) \
-			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
-
-/*
- * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
- * and returns the kaddr corresponding to first physical page in the
- * node's mem_map.
- */
-#define LOCAL_BASE_ADDR(kaddr)	((unsigned long)__va(NODE_DATA(KVADDR_TO_NID(kaddr))->node_start_pfn << PAGE_SHIFT))
+#define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
+#define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
 
-#define LOCAL_MAP_NR(kvaddr) \
-	(((unsigned long)(kvaddr)-LOCAL_BASE_ADDR(kvaddr)) >> PAGE_SHIFT)
+#define local_mapnr(kvaddr) \
+	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) )
 
-#define kern_addr_valid(kaddr)	test_bit(LOCAL_MAP_NR(kaddr), \
-					 NODE_DATA(KVADDR_TO_NID(kaddr))->valid_addr_bitmap)
+#define kern_addr_valid(kaddr)	test_bit(local_mapnr(kaddr), \
+		 NODE_DATA(kvaddr_to_nid(kaddr))->valid_addr_bitmap)
 
-#define pfn_to_page(pfn)	(NODE_MEM_MAP(PFN_TO_NID(pfn)) + PLAT_NODE_DATA_LOCALNR(pfn, PFN_TO_NID(pfn)))
+#define pfn_to_page(pfn)	(node_mem_map(pfn_to_nid(pfn)) + node_localnr(pfn, pfn_to_nid(pfn)))
 #define page_to_pfn(page)	((page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn)
 #define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
 #endif /* CONFIG_DISCONTIGMEM */
diff -Nru a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
--- a/include/asm-i386/mtrr.h	Sun Sep 15 19:19:37 2002
+++ b/include/asm-i386/mtrr.h	Sun Sep 15 19:19:37 2002
@@ -115,13 +115,6 @@
 
 #  endif
 
-/*  The following functions are for initialisation: don't use them!  */
-extern int mtrr_init (void);
-#  if defined(CONFIG_SMP) && defined(CONFIG_MTRR)
-extern void mtrr_init_boot_cpu (void);
-extern void mtrr_init_secondary_cpu (void);
-#  endif
-
 #endif
 
 #endif  /*  _LINUX_MTRR_H  */
diff -Nru a/include/asm-i386/numaq.h b/include/asm-i386/numaq.h
--- a/include/asm-i386/numaq.h	Sun Sep 15 19:19:50 2002
+++ b/include/asm-i386/numaq.h	Sun Sep 15 19:19:50 2002
@@ -38,14 +38,12 @@
 #define MAX_ELEMENTS 256
 #define ELEMENT_REPRESENTS 8 /* 256 Mb */
 
-#define PHYSADDR_TO_NID(pa) numaqpa_to_nid(pa)
-#define PFN_TO_NID(pa) numaqpfn_to_nid(pa)
 #define MAX_NUMNODES		8
 #ifdef CONFIG_NUMA
 #define _cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4)
 #endif /* CONFIG_NUMA */
-extern int numaqpa_to_nid(u64);
-extern int numaqpfn_to_nid(unsigned long);
+extern int pa_to_nid(u64);
+extern int pfn_to_nid(unsigned long);
 extern void get_memcfg_numaq(void);
 #define get_memcfg_numa() get_memcfg_numaq()
 
diff -Nru a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
--- a/include/asm-i386/pgtable.h	Sun Sep 15 19:20:12 2002
+++ b/include/asm-i386/pgtable.h	Sun Sep 15 19:20:12 2002
@@ -266,6 +266,18 @@
 #define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
 #define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
 
+#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G)
+typedef u32 pte_addr_t;
+#endif
+
+#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM64G)
+typedef u64 pte_addr_t;
+#endif
+
+#if !defined(CONFIG_HIGHPTE)
+typedef pte_t *pte_addr_t;
+#endif
+
 /*
  * The i386 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
diff -Nru a/include/asm-i386/rmap.h b/include/asm-i386/rmap.h
--- a/include/asm-i386/rmap.h	Sun Sep 15 19:19:56 2002
+++ b/include/asm-i386/rmap.h	Sun Sep 15 19:19:56 2002
@@ -4,4 +4,18 @@
 /* nothing to see, move along */
 #include <asm-generic/rmap.h>
 
+#ifdef CONFIG_HIGHPTE
+static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr)
+{
+	unsigned long pfn = (unsigned long)(pte_paddr >> PAGE_SHIFT);
+	unsigned long off = ((unsigned long)pte_paddr) & ~PAGE_MASK;
+	return (pte_t *)((char *)kmap_atomic(pfn_to_page(pfn), KM_PTE2) + off);
+}
+
+static inline void rmap_ptep_unmap(pte_t *pte)
+{
+	kunmap_atomic(pte, KM_PTE2);
+}
+#endif
+
 #endif
diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Sun Sep 15 19:19:56 2002
+++ b/include/asm-i386/unistd.h	Sun Sep 15 19:19:56 2002
@@ -254,6 +254,9 @@
 #define __NR_io_getevents	247
 #define __NR_io_submit		248
 #define __NR_io_cancel		249
+#define __NR_alloc_hugepages	250
+#define __NR_free_hugepages	251
+#define __NR_exit_group		252
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
--- a/include/asm-ia64/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ia64/pgtable.h	Sun Sep 15 19:19:30 2002
@@ -420,6 +420,8 @@
 /* We provide our own get_unmapped_area to cope with VA holes for userland */
 #define HAVE_ARCH_UNMAPPED_AREA
 
+typedef pte_t *pte_addr_t;
+
 # endif /* !__ASSEMBLY__ */
 
 /*
diff -Nru a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
--- a/include/asm-m68k/pgtable.h	Sun Sep 15 19:20:23 2002
+++ b/include/asm-m68k/pgtable.h	Sun Sep 15 19:20:23 2002
@@ -171,6 +171,9 @@
 
 #ifndef __ASSEMBLY__
 #include <asm-generic/pgtable.h>
+
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff -Nru a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
--- a/include/asm-mips/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-mips/pgtable.h	Sun Sep 15 19:19:29 2002
@@ -771,6 +771,8 @@
 
 #include <asm-generic/pgtable.h>
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
 #define io_remap_page_range remap_page_range
diff -Nru a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h
--- a/include/asm-mips64/pgtable.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-mips64/pgtable.h	Sun Sep 15 19:20:24 2002
@@ -811,6 +811,8 @@
 
 #include <asm-generic/pgtable.h>
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
 /*
diff -Nru a/include/asm-parisc/hdreg.h b/include/asm-parisc/hdreg.h
--- a/include/asm-parisc/hdreg.h	Sun Sep 15 19:20:00 2002
+++ b/include/asm-parisc/hdreg.h	Sun Sep 15 19:20:00 2002
@@ -1,6 +1,6 @@
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif
diff -Nru a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
--- a/include/asm-parisc/pgtable.h	Sun Sep 15 19:19:30 2002
+++ b/include/asm-parisc/pgtable.h	Sun Sep 15 19:19:30 2002
@@ -326,6 +326,8 @@
 
 #include <asm-generic/pgtable.h>
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #define io_remap_page_range remap_page_range
diff -Nru a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h
--- a/include/asm-ppc/atomic.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc/atomic.h	Sun Sep 15 19:19:29 2002
@@ -67,6 +67,8 @@
 	return t;
 }
 
+#define atomic_add_negative(a, v)	(atomic_add_return((a), (v)) < 0)
+
 static __inline__ void atomic_sub(int a, atomic_t *v)
 {
 	int t;
diff -Nru a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h
--- a/include/asm-ppc/hdreg.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc/hdreg.h	Sun Sep 15 19:19:29 2002
@@ -14,7 +14,7 @@
 #ifndef __ASMPPC_HDREG_H
 #define __ASMPPC_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMPPC_HDREG_H */
 
diff -Nru a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h
--- a/include/asm-ppc/highmem.h	Sun Sep 15 19:19:37 2002
+++ b/include/asm-ppc/highmem.h	Sun Sep 15 19:19:37 2002
@@ -128,6 +128,17 @@
 	dec_preempt_count();
 }
 
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+	unsigned long idx, vaddr = (unsigned long) ptr;
+
+	if (vaddr < KMAP_FIX_BEGIN)
+		return virt_to_page(ptr);
+
+	idx = (vaddr - KMAP_FIX_BEGIN) >> PAGE_SHIFT;
+	return pte_page(kmap_pte[idx]);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
--- a/include/asm-ppc/ide.h	Sun Sep 15 19:19:30 2002
+++ b/include/asm-ppc/ide.h	Sun Sep 15 19:19:30 2002
@@ -103,30 +103,10 @@
 #endif
 }
 
-#if !defined(ide_request_irq)
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#endif
-
-#if !defined(ide_free_irq)
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#endif
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-extern void ide_fix_driveid(struct hd_driveid *id);
-
-/*
- * The following are not needed for the non-m68k ports
- * unless direct IDE on 8xx
- */
 #if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE )
+#define IDE_ARCH_ACK_INTR  1
 #define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
-#define ide_ack_intr(hwif)		(1)
 #endif
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc/pgtable.h	Sun Sep 15 19:19:29 2002
@@ -543,6 +543,8 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
-#endif /* __ASSEMBLY__ */
+typedef pte_t *pte_addr_t;
+
+#endif /* !__ASSEMBLY__ */
 #endif /* _PPC_PGTABLE_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
--- a/include/asm-ppc/spinlock.h	Sun Sep 15 19:19:34 2002
+++ b/include/asm-ppc/spinlock.h	Sun Sep 15 19:19:34 2002
@@ -100,6 +100,8 @@
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 RWLOCK_DEBUG_INIT }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
 
+#define rwlock_is_locked(x)	((x)->lock != 0)
+
 #ifndef CONFIG_DEBUG_SPINLOCK
 
 static __inline__ void _raw_read_lock(rwlock_t *rw)
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc/unistd.h	Sun Sep 15 19:19:29 2002
@@ -239,6 +239,9 @@
 #define __NR_io_getevents	229
 #define __NR_io_submit		230
 #define __NR_io_cancel		231
+#define __NR_alloc_hugepages	232
+#define __NR_free_hugepages	233
+#define __NR_exit_group		234
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-ppc64/delay.h b/include/asm-ppc64/delay.h
--- a/include/asm-ppc64/delay.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/delay.h	Sun Sep 15 19:19:28 2002
@@ -18,6 +18,7 @@
 /* define these here to prevent circular dependencies */ 
 #define __HMT_low()	asm volatile("or 1,1,1")
 #define __HMT_medium()	asm volatile("or 2,2,2")
+#define __barrier()	asm volatile("":::"memory")
 
 static inline unsigned long __get_tb(void)
 {
@@ -34,6 +35,7 @@
 	while((__get_tb()-start) < loops)
 		__HMT_low();
 	__HMT_medium();
+	__barrier();
 }
 
 static inline void udelay(unsigned long usecs)
diff -Nru a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h
--- a/include/asm-ppc64/eeh.h	Sun Sep 15 19:20:23 2002
+++ b/include/asm-ppc64/eeh.h	Sun Sep 15 19:20:23 2002
@@ -149,4 +149,38 @@
 	memcpy(vdest, src, n);
 }
 
+static inline void eeh_insb(volatile u8 *addr, void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_insb(vaddr, buf, n);
+	/* ToDo: look for ff's in buf[n] */
+}
+
+static inline void eeh_outsb(volatile u8 *addr, const void *buf, int n) {
+	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
+	_outsb(vaddr, buf, n);
+}
+
+static inline void eeh_insw_ns(volatile u16 *addr, void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_insw_ns(vaddr, buf, n);
+	/* ToDo: look for ffff's in buf[n] */
+}
+
+static inline void eeh_outsw_ns(volatile u16 *addr, const void *buf, int n) {
+	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
+	_outsw_ns(vaddr, buf, n);
+}
+
+static inline void eeh_insl_ns(volatile u32 *addr, void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_insl_ns(vaddr, buf, n);
+	/* ToDo: look for ffffffff's in buf[n] */
+}
+
+static inline void eeh_outsl_ns(volatile u32 *addr, const void *buf, int n) {
+	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
+	_outsl_ns(vaddr, buf, n);
+}
+
+
 #endif /* _EEH_H */
diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h
--- a/include/asm-ppc64/elf.h	Sun Sep 15 19:20:08 2002
+++ b/include/asm-ppc64/elf.h	Sun Sep 15 19:20:08 2002
@@ -122,12 +122,13 @@
  */
 #define ARCH_DLINFO							\
 do {									\
+	/* Handle glibc compatibility. */				\
+	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
+	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
+	/* Cache size items */						\
 	NEW_AUX_ENT(AT_DCACHEBSIZE, dcache_bsize);			\
 	NEW_AUX_ENT(AT_ICACHEBSIZE, icache_bsize);			\
 	NEW_AUX_ENT(AT_UCACHEBSIZE, ucache_bsize);			\
-	/* Now handle glibc compatibility. */				\
-	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
-	NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC);			\
  } while (0)
 
 #endif /* __PPC64_ELF_H */
diff -Nru a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h
--- a/include/asm-ppc64/hardirq.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc64/hardirq.h	Sun Sep 15 19:19:29 2002
@@ -82,8 +82,10 @@
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
+# define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()	(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 #define irq_exit()							\
diff -Nru a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/hvcall.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,84 @@
+
+#define H_Success	0
+#define H_Busy		1	/* Hardware busy -- retry later */
+#define H_Hardware	-1	/* Hardware error */
+#define H_Function	-2	/* Function not supported */
+#define H_Privilege	-3	/* Caller not privileged */
+#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */
+#define H_Bad_Mode	-5	/* Illegal msr value */
+#define H_PTEG_Full	-6	/* PTEG is full */
+#define H_Not_Found	-7	/* PTE was not found" */
+#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" */
+
+/* Flags */
+#define H_LARGE_PAGE		(1UL<<(63-16))
+#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */
+#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */
+#define H_ANDCOND		(1UL<<(63-33))
+#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE		(1UL<<(63-49))
+#define H_N			(1UL<<(63-61))
+#define H_PP1			(1UL<<(63-62))
+#define H_PP2			(1UL<<(63-63))
+
+
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE		0x04
+#define H_ENTER			0x08
+#define H_READ			0x0c
+#define H_CLEAR_MOD		0x10
+#define H_CLEAR_REF		0x14
+#define H_PROTECT		0x18
+#define H_GET_TCE		0x1c
+#define H_PUT_TCE		0x20
+#define H_SET_SPRG0		0x24
+#define H_SET_DABR		0x28
+#define H_PAGE_INIT		0x2c
+#define H_SET_ASR		0x30
+#define H_ASR_ON		0x34
+#define H_ASR_OFF		0x38
+#define H_LOGICAL_CI_LOAD	0x3c
+#define H_LOGICAL_CI_STORE	0x40
+#define H_LOGICAL_CACHE_LOAD	0x44
+#define H_LOGICAL_CACHE_STORE	0x48
+#define H_LOGICAL_ICBI		0x4c
+#define H_LOGICAL_DCBF		0x50
+#define H_GET_TERM_CHAR		0x54
+#define H_PUT_TERM_CHAR		0x58
+#define H_REAL_TO_LOGICAL	0x5c
+#define H_HYPERVISOR_DATA	0x60
+#define H_EOI			0x64
+#define H_CPPR			0x68
+#define H_IPI			0x6c
+#define H_IPOLL			0x70
+#define H_XIRR			0x74
+
+#define HSC			".long 0x44000022\n"
+#define H_ENTER_r3		"li	3, 0x08\n"
+
+/* plpar_hcall() -- Generic call interface using above opcodes
+ *
+ * The actual call interface is a hypervisor call instruction with
+ * the opcode in R3 and input args in R4-R7.
+ * Status is returned in R3 with variable output values in R4-R11.
+ * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now
+ * and return only two out args which MUST ALWAYS BE PROVIDED.
+ */
+long plpar_hcall(unsigned long opcode,
+		 unsigned long arg1,
+		 unsigned long arg2,
+		 unsigned long arg3,
+		 unsigned long arg4,
+		 unsigned long *out1,
+		 unsigned long *out2,
+		 unsigned long *out3);
+
+/* Same as plpar_hcall but for those opcodes that return no values
+ * other than status.  Slightly more efficient.
+ */
+long plpar_hcall_norets(unsigned long opcode, ...);
diff -Nru a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
--- a/include/asm-ppc64/io.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-ppc64/io.h	Sun Sep 15 19:20:24 2002
@@ -40,7 +40,7 @@
 #define writeb(data, addr)	iSeries_Write_Byte(data,((void*)(addr)))
 #define writew(data, addr)	iSeries_Write_Word(data,((void*)(addr)))
 #define writel(data, addr)	iSeries_Write_Long(data,((void*)(addr)))
-#define memset_io(a,b,c)	iSeries_memset((void *)(a),(b),(c))
+#define memset_io(a,b,c)	iSeries_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	iSeries_memcpy_fromio((void *)(a), (void *)(b), (c))
 #define memcpy_toio(a,b,c)	iSeries_memcpy_toio((void *)(a), (void *)(b), (c))
 #define inb(addr)		readb(((unsigned long)(addr)))  
@@ -66,6 +66,18 @@
 #define outw(val, port)		_outw(val, (unsigned long)port)
 #define inl(port)		_inl((unsigned long)port)
 #define outl(val, port)		_outl(val, (unsigned long)port)
+
+/*
+ * The insw/outsw/insl/outsl macros don't do byte-swapping.
+ * They are only used in practice for transferring buffers which
+ * are arrays of bytes, and byte-swapping is not appropriate in
+ * that case.  - paulus */
+#define insb(port, buf, ns)	eeh_insb((u8 *)(port), (buf), (ns))
+#define outsb(port, buf, ns)	eeh_outsb((u8 *)(port), (buf), (ns))
+#define insw(port, buf, ns)	eeh_insw_ns((u16 *)(port), (buf), (ns))
+#define outsw(port, buf, ns)	eeh_outsw_ns((u16 *)(port), (buf), (ns))
+#define insl(port, buf, nl)	eeh_insl_ns((u32 *)(port), (buf), (nl))
+#define outsl(port, buf, nl)	eeh_outsl_ns((u32 *)(port), (buf), (nl))
 #endif
 
 
@@ -80,18 +92,6 @@
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val, (port)))
 
-/*
- * The insw/outsw/insl/outsl macros don't do byte-swapping.
- * They are only used in practice for transferring buffers which
- * are arrays of bytes, and byte-swapping is not appropriate in
- * that case.  - paulus */
-#define _IOMAP_VADDR(port) (IS_MAPPED_VADDR(port) ? (port) : (port)+_IO_BASE)
-#define insb(port, buf, ns)	_insb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsb(port, buf, ns)	_outsb((u8 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insw(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
 
 extern void _insb(volatile u8 *port, void *buf, int ns);
 extern void _outsb(volatile u8 *port, const void *buf, int ns);
@@ -109,10 +109,10 @@
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#define insw_ns(port, buf, ns)	_insw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)(_IOMAP_VADDR(port)), (buf), (ns))
-#define insl_ns(port, buf, nl)	_insl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
-#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)(_IOMAP_VADDR(port)), (buf), (nl))
+#define insw_ns(port, buf, ns)	insw(port, buf, ns)
+#define outsw_ns(port, buf, ns)	outsw(port, buf, ns)
+#define insl_ns(port, buf, nl)	insl(port, buf, nl)
+#define outsl_ns(port, buf, nl)	outsl(port, buf, nl)
 
 
 #define IO_SPACE_LIMIT ~(0UL)
@@ -155,7 +155,7 @@
 /*
  * Change "struct page" to physical address.
  */
-#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
 
 #if 0
 #define BIO_VMERGE_BOUNDARY	4096
diff -Nru a/include/asm-ppc64/kmap_types.h b/include/asm-ppc64/kmap_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/kmap_types.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,21 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KMAP_TYPES_H
+#define _ASM_KMAP_TYPES_H
+
+enum km_type {
+	KM_BOUNCE_READ,
+	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
+	KM_BIO_SRC_IRQ,
+	KM_BIO_DST_IRQ,
+	KM_PTE0,
+	KM_PTE1,
+	KM_IRQ0,
+	KM_IRQ1,
+	KM_TYPE_NR
+};
+
+#endif
+#endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h
--- a/include/asm-ppc64/lmb.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc64/lmb.h	Sun Sep 15 19:19:29 2002
@@ -28,6 +28,9 @@
 #define LMB_MEMORY_AREA	1
 #define LMB_IO_AREA	2
 
+#define LMB_ALLOC_ANYWHERE	0
+#define LMB_ALLOC_FIRST4GBYTE	(1UL<<32)
+
 struct lmb_property {
 	unsigned long base;
 	unsigned long physbase;
@@ -45,6 +48,7 @@
 
 struct lmb {
 	unsigned long debug;
+	unsigned long rmo_size;
 	struct lmb_region memory;
 	struct lmb_region reserved;
 };
@@ -59,6 +63,7 @@
 #endif /* CONFIG_MSCHUNKS */
 extern long lmb_reserve(unsigned long, unsigned long);
 extern unsigned long lmb_alloc(unsigned long, unsigned long);
+extern unsigned long lmb_alloc_base(unsigned long, unsigned long, unsigned long);
 extern unsigned long lmb_phys_mem_size(void);
 extern unsigned long lmb_end_of_DRAM(void);
 extern unsigned long lmb_abs_to_phys(unsigned long);
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Sun Sep 15 19:19:30 2002
+++ b/include/asm-ppc64/machdep.h	Sun Sep 15 19:19:30 2002
@@ -15,7 +15,6 @@
 struct pt_regs;
 struct pci_bus;	
 struct pci_dev;
-struct kbd_repeat;
 struct device_node;
 struct TceTable;
 struct rtc_time;
@@ -32,9 +31,6 @@
 #endif
 
 struct machdep_calls {
-	/* High use functions in the first cachelines, low use functions
-	 * follow.  DRENG collect profile data.
-	 */
 	void            (*hpte_invalidate)(unsigned long slot,
 					   unsigned long va,
 					   int large,
@@ -99,32 +95,14 @@
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
-/* Tons of keyboard stuff. */
-	int		(*kbd_setkeycode)(unsigned int scancode,
-				unsigned int keycode);
-	int		(*kbd_getkeycode)(unsigned int scancode);
-	int		(*kbd_translate)(unsigned char scancode,
-				unsigned char *keycode,
-				char raw_mode);
-	char		(*kbd_unexpected_up)(unsigned char keycode);
-	void		(*kbd_leds)(unsigned char leds);
-	void		(*kbd_init_hw)(void);
-#ifdef CONFIG_MAGIC_SYSRQ
-	unsigned char 	*ppc_kbd_sysrq_xlate;
-#endif
-
 	/* Debug interface.  Low level I/O to some terminal device */
 	void		(*udbg_putc)(unsigned char c);
 	unsigned char	(*udbg_getc)(void);
 	int		(*udbg_getc_poll)(void);
 
 	/* PCI interfaces */
-	int (*pcibios_read_config_byte)(struct device_node *dn, int offset, u8 *val);
-	int (*pcibios_read_config_word)(struct device_node *dn, int offset, u16 *val);
-	int (*pcibios_read_config_dword)(struct device_node *dn, int offset, u32 *val);
-	int (*pcibios_write_config_byte)(struct device_node *dn, int offset, u8 val);
-	int (*pcibios_write_config_word)(struct device_node *dn, int offset, u16 val);
-	int (*pcibios_write_config_dword)(struct device_node *dn, int offset, u32 val);
+	int (*pcibios_read_config)(struct device_node *dn, int where, int size, u32 *val);
+	int (*pcibios_write_config)(struct device_node *dn, int where, int size, u32 val);
 
 	/* Called after scanning the bus, before allocating
 	 * resources
diff -Nru a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
--- a/include/asm-ppc64/mmu.h	Sun Sep 15 19:20:00 2002
+++ b/include/asm-ppc64/mmu.h	Sun Sep 15 19:20:00 2002
@@ -115,7 +115,7 @@
 
 typedef struct {
 	unsigned long pp0:  1; /* Page protection bit 0 */
-	unsigned long :     1; /* Reserved */
+	unsigned long ts:   1; /* Tag set bit */
 	unsigned long rpn: 50; /* Real page number */
 	unsigned long :     2; /* Reserved */
 	unsigned long ac:   1; /* Address compare */ 
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-ppc64/mmzone.h	Sun Sep 15 19:20:24 2002
@@ -9,31 +9,67 @@
 
 #include <linux/config.h>
 
-typedef struct plat_pglist_data {
-	pg_data_t	gendata;
-} plat_pg_data_t;
+#ifdef CONFIG_DISCONTIGMEM
+
+extern struct pglist_data *node_data[];
 
 /*
- * Following are macros that are specific to this numa platform.
+ * Following are specific to this numa platform.
  */
 
-extern plat_pg_data_t plat_node_data[];
+extern int numa_node_exists[];
+extern int numa_cpu_lookup_table[];
+extern int numa_memory_lookup_table[];
 
-#define MAX_NUMNODES 4
+#define MAX_NUMNODES 16
+#define MAX_MEMORY (1UL << 41)
+/* 256MB regions */
+#define MEMORY_INCREMENT_SHIFT 28
+#define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT)
 
-/* XXX grab this from the device tree - Anton */
-#define MEMORY_ZONE_BITS	33
-#define CPU_SHIFT_BITS          1
-
-#define PHYSADDR_TO_NID(pa)		((pa) >> MEMORY_ZONE_BITS)
-#define PLAT_NODE_DATA(n)		(&plat_node_data[(n)])
-#define PLAT_NODE_DATA_STARTNR(n)	\
-	(PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
-#define PLAT_NODE_DATA_SIZE(n)		(PLAT_NODE_DATA(n)->gendata.node_size)
-#define PLAT_NODE_DATA_LOCALNR(p, n)	\
-	(((p) >> PAGE_SHIFT) - PLAT_NODE_DATA(n)->gendata.node_start_pfn)
+#undef DEBUG_NUMA
 
-#ifdef CONFIG_DISCONTIGMEM
+static inline int pa_to_nid(unsigned long pa)
+{
+        int nid;
+
+        nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT];
+
+#ifdef DEBUG_NUMA
+        /* the physical address passed in is not in the map for the system */
+        if (nid == -1) {
+                printk("bad address: %lx\n", pa);
+                BUG();
+        }
+#endif
+
+        return nid;
+}
+
+#define pfn_to_nid(pfn)		pa_to_nid((pfn) << PAGE_SHIFT)
+
+#define node_startnr(nid)	(node_data[nid]->node_start_mapnr)
+#define node_size(nid)		(node_data[nid]->node_size)
+#define node_localnr(pfn, nid)	((pfn) - node_data[nid]->node_start_pfn)
+
+#ifdef CONFIG_NUMA
+
+static inline int __cpu_to_node(int cpu)
+{
+        int node;
+
+        node = numa_cpu_lookup_table[cpu];
+
+#ifdef DEBUG_NUMA
+        if (node == -1)
+                BUG();
+#endif
+
+        return node;
+}
+
+#define numa_node_id()	__cpu_to_node(smp_processor_id())
+#endif /* CONFIG_NUMA */
 
 /*
  * Following are macros that each numa implmentation must define.
@@ -42,55 +78,39 @@
 /*
  * Given a kernel address, find the home node of the underlying memory.
  */
-#define KVADDR_TO_NID(kaddr)	PHYSADDR_TO_NID(__pa(kaddr))
+#define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
 
 /*
  * Return a pointer to the node data for node n.
  */
-#define NODE_DATA(n)	(&((PLAT_NODE_DATA(n))->gendata))
-
-/*
- * NODE_MEM_MAP gives the kaddr for the mem_map of the node.
- */
-#define NODE_MEM_MAP(nid)	(NODE_DATA(nid)->node_mem_map)
+#define NODE_DATA(nid)		(node_data[nid])
 
-/*
- * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the mem_map of that node.
- */
-#define ADDR_TO_MAPBASE(kaddr) \
-			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
+#define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
+#define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
 
-/*
- * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory
- * and returns the kaddr corresponding to first physical page in the
- * node's mem_map.
- */
-#define LOCAL_BASE_ADDR(kaddr) \
-	((unsigned long)__va(NODE_DATA(KVADDR_TO_NID(kaddr))->node_start_pfn << PAGE_SHIFT))
-
-#define LOCAL_MAP_NR(kvaddr) \
-	(((unsigned long)(kvaddr)-LOCAL_BASE_ADDR(kvaddr)) >> PAGE_SHIFT)
+#define local_mapnr(kvaddr) \
+	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) 
 
 #if 0
 /* XXX fix - Anton */
-#define kern_addr_valid(kaddr)	test_bit(LOCAL_MAP_NR(kaddr), \
-					 NODE_DATA(KVADDR_TO_NID(kaddr))->valid_addr_bitmap)
+#define kern_addr_valid(kaddr)	test_bit(local_mapnr(kaddr), \
+		 NODE_DATA(kvaddr_to_nid(kaddr))->valid_addr_bitmap)
 #endif
 
+/* Written this way to avoid evaluating arguments twice */
 #define discontigmem_pfn_to_page(pfn) \
 ({ \
-	unsigned long kaddr = (unsigned long)__va(pfn << PAGE_SHIFT); \
-	(ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr)); \
+	unsigned long __tmp = pfn; \
+	(node_mem_map(pfn_to_nid(__tmp)) + \
+	 node_localnr(__tmp, pfn_to_nid(__tmp))); \
 })
 
-#ifdef CONFIG_NUMA
-
-/* XXX grab this from the device tree - Anton */
-#define cputonode(cpu)	((cpu) >> CPU_SHIFT_BITS)
-
-#define numa_node_id()	cputonode(smp_processor_id())
+#define discontigmem_page_to_pfn(p)	\
+({ \
+	struct page *__tmp = p; \
+	(((__tmp) - page_zone(__tmp)->zone_mem_map) + \
+	 page_zone(__tmp)->zone_start_pfn); \
+})
 
-#endif /* CONFIG_NUMA */
 #endif /* CONFIG_DISCONTIGMEM */
 #endif /* _ASM_MMZONE_H_ */
diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/page.h	Sun Sep 15 19:19:28 2002
@@ -205,9 +205,7 @@
 #define __a2v(x) ((void *) __va(absolute_to_phys(x)))
 
 #ifdef CONFIG_DISCONTIGMEM
-#define page_to_pfn(page) \
-		((page) - page_zone(page)->zone_mem_map + \
-		(page_zone(page)->zone_start_pfn))
+#define page_to_pfn(page)	discontigmem_page_to_pfn(page)
 #define pfn_to_page(pfn)	discontigmem_pfn_to_page(pfn)
 #else
 #define pfn_to_page(pfn)	(mem_map + (pfn))
diff -Nru a/include/asm-ppc64/pgalloc.h b/include/asm-ppc64/pgalloc.h
--- a/include/asm-ppc64/pgalloc.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/pgalloc.h	Sun Sep 15 19:19:28 2002
@@ -1,7 +1,7 @@
 #ifndef _PPC64_PGALLOC_H
 #define _PPC64_PGALLOC_H
 
-#include <linux/threads.h>
+#include <linux/mm.h>
 #include <asm/processor.h>
 
 /*
@@ -78,8 +78,16 @@
 	return pte;
 }
 
-#define pte_alloc_one(mm, address) \
-	virt_to_page(pte_alloc_one_kernel((mm), (address)))
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+	pte_t *pte = pte_alloc_one_kernel(mm, address);
+
+	if (pte)
+		return virt_to_page(pte);
+
+	return NULL;
+}
 
 static inline void
 pte_free_kernel(pte_t *pte)
diff -Nru a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
--- a/include/asm-ppc64/pgtable.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-ppc64/pgtable.h	Sun Sep 15 19:20:24 2002
@@ -377,5 +377,7 @@
 extern void hpte_init_pSeries(void);
 extern void hpte_init_iSeries(void);
 
+typedef pte_t *pte_addr_t;
+
 #endif /* __ASSEMBLY__ */
 #endif /* _PPC64_PGTABLE_H */
diff -Nru a/include/asm-ppc64/ppcdebug.h b/include/asm-ppc64/ppcdebug.h
--- a/include/asm-ppc64/ppcdebug.h	Sun Sep 15 19:19:50 2002
+++ b/include/asm-ppc64/ppcdebug.h	Sun Sep 15 19:19:50 2002
@@ -51,6 +51,8 @@
 #define PPCDBG_SMP           PPCDBG_BITVAL(19)
 #define PPCDBG_BOOT          PPCDBG_BITVAL(20)
 #define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
+#define PPCDBG_PROM	     PPCDBG_BITVAL(22)
+#define PPCDBG_RTAS	     PPCDBG_BITVAL(23)
 #define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
 #define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
 #define PPCDBG_NONE          (0UL)
@@ -74,7 +76,8 @@
 	"signal",	"signal_xmon",
 	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
 	"alignfixup",   "tceinit",      "tce",          "phb_init",     
-	"smp",          "boot",         "buswalk"
+	"smp",          "boot",         "buswalk",	"prom",
+	"rtas"
 };
 #else
 extern char *trace_names[64];
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-ppc64/processor.h	Sun Sep 15 19:19:29 2002
@@ -366,7 +366,7 @@
 #define	IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
 #define	IMMR	SPRN_IMMR      	/* PPC 860/821 Internal Memory Map Register */
 #define	L2CR	SPRN_L2CR    	/* PPC 750 L2 control register */
-#define	LR	SPRN_LR
+#define	__LR	SPRN_LR
 #define	PVR	SPRN_PVR	/* Processor Version */
 #define	PIR	SPRN_PIR	/* Processor ID */
 #define	RPA	SPRN_RPA	/* Required Physical Address Register */
diff -Nru a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
--- a/include/asm-ppc64/prom.h	Sun Sep 15 19:19:45 2002
+++ b/include/asm-ppc64/prom.h	Sun Sep 15 19:19:45 2002
@@ -126,9 +126,9 @@
 	struct	interrupt_info *intrs;
 	char	*full_name;
 	int	busno;			/* for pci devices */
+	int	bussubno;		/* for pci devices */
 	int	devfn;			/* for pci devices */
 	struct  pci_controller *phb;	/* for pci devices */
-	int	status;			/* current status of device */
 	struct	TceTable *tce_table;	/* for phb's or bridges */
 #define DN_STATUS_BIST_FAILED (1<<0)
 	struct	property *properties;
@@ -171,6 +171,8 @@
 };
 
 extern struct prom_t prom;
+
+extern int boot_cpuid;
 
 /* Prototypes */
 extern void abort(void);
diff -Nru a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h
--- a/include/asm-ppc64/ptrace-common.h	Sun Sep 15 19:19:56 2002
+++ b/include/asm-ppc64/ptrace-common.h	Sun Sep 15 19:19:56 2002
@@ -19,9 +19,20 @@
  */
 static inline unsigned long get_reg(struct task_struct *task, int regno)
 {
-	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
-		return ((unsigned long *)task->thread.regs)[regno];
-	return 0;
+	unsigned long tmp = 0;
+
+	/*
+	 * Put the correct FP bits in, they might be wrong as a result
+	 * of our lazy FP restore.
+	 */
+	if (regno == PT_MSR) {
+		tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
+		tmp |= task->thread.fpexc_mode;
+	} else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
+		tmp = ((unsigned long *)task->thread.regs)[regno];
+	}
+
+	return tmp;
 }
 
 /*
diff -Nru a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h
--- a/include/asm-ppc64/rtas.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-ppc64/rtas.h	Sun Sep 15 19:20:24 2002
@@ -17,6 +17,8 @@
  */
 
 #define RTAS_UNKNOWN_SERVICE (-1)
+#define RTAS_INSTANTIATE_MAX (1UL<<30) /* Don't instantiate rtas at/above this value */
+
 /*
  * In general to call RTAS use rtas_token("string") to lookup
  * an RTAS token for the given string (e.g. "event-scan").
diff -Nru a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h
--- a/include/asm-ppc64/smp.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/smp.h	Sun Sep 15 19:19:28 2002
@@ -56,8 +56,6 @@
 
 #define smp_processor_id() (get_paca()->xPacaIndex)
 
-extern int boot_cpuid;
-
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  *
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
diff -Nru a/include/asm-ppc64/spinlock.h b/include/asm-ppc64/spinlock.h
--- a/include/asm-ppc64/spinlock.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/spinlock.h	Sun Sep 15 19:19:28 2002
@@ -214,5 +214,7 @@
 
 #define rwlock_init(x)         do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
+#define rwlock_is_locked(x)	((x)->lock)
+
 #endif /* __KERNEL__ */
 #endif /* __ASM_SPINLOCK_H */
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-ppc64/unistd.h	Sun Sep 15 19:19:28 2002
@@ -235,6 +235,12 @@
 #define __NR_sched_getaffinity	223
 #define __NR_security		224
 #define __NR_tuxcall		225
+#define __NR_sendfile64		226
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-ppc64/user.h b/include/asm-ppc64/user.h
--- a/include/asm-ppc64/user.h	Sun Sep 15 19:19:50 2002
+++ b/include/asm-ppc64/user.h	Sun Sep 15 19:19:50 2002
@@ -9,7 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/ptrace.h>
+#include <asm/ptrace.h>
 #include <asm/page.h>
 
 /*
diff -Nru a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
--- a/include/asm-s390/pgtable.h	Sun Sep 15 19:20:20 2002
+++ b/include/asm-s390/pgtable.h	Sun Sep 15 19:20:20 2002
@@ -505,6 +505,8 @@
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)	((pte_t) { (x).val })
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #define kern_addr_valid(addr)   (1)
diff -Nru a/include/asm-s390x/pgtable.h b/include/asm-s390x/pgtable.h
--- a/include/asm-s390x/pgtable.h	Sun Sep 15 19:19:37 2002
+++ b/include/asm-s390x/pgtable.h	Sun Sep 15 19:19:37 2002
@@ -531,6 +531,8 @@
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)	((pte_t) { (x).val })
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #define kern_addr_valid(addr)   (1)
diff -Nru a/include/asm-sh/hdreg.h b/include/asm-sh/hdreg.h
--- a/include/asm-sh/hdreg.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sh/hdreg.h	Sun Sep 15 19:19:29 2002
@@ -7,6 +7,6 @@
 #ifndef __ASM_SH_HDREG_H
 #define __ASM_SH_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_SH_HDREG_H */
diff -Nru a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
--- a/include/asm-sh/pgtable.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-sh/pgtable.h	Sun Sep 15 19:20:24 2002
@@ -310,6 +310,8 @@
 
 #define pte_same(A,B)	(pte_val(A) == pte_val(B))
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #define kern_addr_valid(addr)	(1)
diff -Nru a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h
--- a/include/asm-sparc/hardirq.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-sparc/hardirq.h	Sun Sep 15 19:20:24 2002
@@ -39,8 +39,8 @@
  * - ( bit 26 is the PREEMPT_ACTIVE flag. )
  *
  * PREEMPT_MASK: 0x000000ff
- * HARDIRQ_MASK: 0x0000ff00
- * SOFTIRQ_MASK: 0x00ff0000
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x00ff0000
  */
 
 #define PREEMPT_BITS    8
@@ -90,8 +90,10 @@
 #define irq_enter()             (preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
+# define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()	(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 #define irq_exit()                                                      \
@@ -121,7 +123,7 @@
 
 #ifndef CONFIG_SMP
 
-#define synchronize_irq()	barrier()
+#define synchronize_irq(irq)	barrier()
 
 #else /* (CONFIG_SMP) */
 
diff -Nru a/include/asm-sparc/highmem.h b/include/asm-sparc/highmem.h
--- a/include/asm-sparc/highmem.h	Sun Sep 15 19:20:24 2002
+++ b/include/asm-sparc/highmem.h	Sun Sep 15 19:20:24 2002
@@ -148,6 +148,19 @@
 	dec_preempt_count();
 }
 
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+	unsigned long idx, vaddr = (unsigned long)ptr;
+	pte_t *pte;
+
+	if (vaddr < FIX_KMAP_BEGIN)
+		return virt_to_page(ptr);
+
+	idx = ((vaddr - FIX_KMAP_BEGIN) >> PAGE_SHIFT);
+	pte = kmap_pte + idx;
+	return pte_page(*pte);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -Nru a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
--- a/include/asm-sparc/ide.h	Sun Sep 15 19:19:46 2002
+++ b/include/asm-sparc/ide.h	Sun Sep 15 19:19:46 2002
@@ -81,92 +81,30 @@
  * The following are not needed for the non-m68k ports
  */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
-/* From m68k code... */
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-#define insw(port, buf, nr) ide_insw((port), (buf), (nr))
-#define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
-
-static __inline__ void ide_insw(unsigned long port,
-				void *dst,
-				unsigned long count)
-{
-	volatile unsigned short *data_port;
-	/* unsigned long end = (unsigned long)dst + (count << 1); */ /* P3 */
-	u16 *ps = dst;
-	u32 *pi;
-
-	data_port = (volatile unsigned short *)port;
-
-	if(((unsigned long)ps) & 0x2) {
-		*ps++ = *data_port;
-		count--;
-	}
-	pi = (u32 *)ps;
-	while(count >= 2) {
-		u32 w;
-
-		w  = (*data_port) << 16;
-		w |= (*data_port);
-		*pi++ = w;
-		count -= 2;
-	}
-	ps = (u16 *)pi;
-	if(count)
-		*ps++ = *data_port;
-
-	/* __flush_dcache_range((unsigned long)dst, end); */ /* P3 see hme */
-}
-
-static __inline__ void ide_outsw(unsigned long port,
-				 const void *src,
-				 unsigned long count)
-{
-	volatile unsigned short *data_port;
-	/* unsigned long end = (unsigned long)src + (count << 1); */
-	const u16 *ps = src;
-	const u32 *pi;
-
-	data_port = (volatile unsigned short *)port;
-
-	if(((unsigned long)src) & 0x2) {
-		*data_port = *ps++;
-		count--;
-	}
-	pi = (const u32 *)ps;
-	while(count >= 2) {
-		u32 w;
-
-		w = *pi++;
-		*data_port = (w >> 16);
-		*data_port = w;
-		count -= 2;
-	}
-	ps = (const u16 *)pi;
-	if(count)
-		*data_port = *ps;
-
-	/* __flush_dcache_range((unsigned long)src, end); */ /* P3 see hme */
-}
+/* XXX Known to be broken.  Axboe will fix the problems this
+ * XXX has by making seperate IN/OUT macros for IDE_DATA
+ * XXX register and rest of IDE regs and also using
+ * XXX ide_ioreg_t instead of u32 for ports. -DaveM
+ */
+
+#define HAVE_ARCH_IN_BYTE
+#define IN_BYTE(p)		(*((volatile u8 *)(p)))
+#define IN_WORD(p)		(*((volatile u16 *)(p)))
+#define IN_LONG(p)		(*((volatile u32 *)(p)))
+#define IN_BYTE_P		IN_BYTE
+#define IN_WORD_P		IN_WORD
+#define IN_LONG_P		IN_LONG
+
+#define HAVE_ARCH_OUT_BYTE
+#define OUT_BYTE(b,p)		((*((volatile u8 *)(p))) = (b))
+#define OUT_WORD(w,p)		((*((volatile u16 *)(p))) = (w))
+#define OUT_LONG(l,p)		((*((volatile u32 *)(p))) = (l))
+#define OUT_BYTE_P		OUT_BYTE
+#define OUT_WORD_P		OUT_WORD
+#define OUT_LONG_P		OUT_LONG
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
--- a/include/asm-sparc/irq.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-sparc/irq.h	Sun Sep 15 19:19:28 2002
@@ -21,6 +21,8 @@
 
 #define NR_IRQS    15
 
+#define irq_cannonicalize(irq)	(irq)
+
 /* Dave Redman (djhr@tadpole.co.uk)
  * changed these to function pointers.. it saves cycles and will allow
  * the irq dependencies to be split into different files at a later date
diff -Nru a/include/asm-sparc/kmap_types.h b/include/asm-sparc/kmap_types.h
--- a/include/asm-sparc/kmap_types.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sparc/kmap_types.h	Sun Sep 15 19:19:29 2002
@@ -11,6 +11,8 @@
 	KM_BIO_DST_IRQ,
 	KM_PTE0,
 	KM_PTE1,
+	KM_IRQ0,
+	KM_IRQ1,
 	KM_TYPE_NR
 };
 
diff -Nru a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
--- a/include/asm-sparc/pgtable.h	Sun Sep 15 19:19:50 2002
+++ b/include/asm-sparc/pgtable.h	Sun Sep 15 19:19:50 2002
@@ -442,6 +442,8 @@
 
 #include <asm-generic/pgtable.h>
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !(__ASSEMBLY__) */
 
 /* We provide our own get_unmapped_area to cope with VA holes for userland */
diff -Nru a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h
--- a/include/asm-sparc/spinlock.h	Sun Sep 15 19:20:10 2002
+++ b/include/asm-sparc/spinlock.h	Sun Sep 15 19:20:10 2002
@@ -42,6 +42,7 @@
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} }
 
 #define rwlock_init(lp)	do { *(lp)= RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(lp) ((lp)->lock != 0)
 
 extern void _do_read_lock(rwlock_t *rw, char *str);
 extern void _do_read_unlock(rwlock_t *rw, char *str);
@@ -141,6 +142,7 @@
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 #define rwlock_init(lp)	do { *(lp)= RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(lp) ((lp)->lock != 0)
 
 
 /* Sort of like atomic_t's on Sparc, but even more clever.
diff -Nru a/include/asm-sparc/system.h b/include/asm-sparc/system.h
--- a/include/asm-sparc/system.h	Sun Sep 15 19:20:05 2002
+++ b/include/asm-sparc/system.h	Sun Sep 15 19:20:05 2002
@@ -56,6 +56,17 @@
 extern struct linux_romvec *romvec;
 #define halt() romvec->pv_halt()
 
+extern void sun_do_break(void);
+extern int serial_console;
+extern int stop_a_enabled;
+
+static __inline__ int con_is_present(void)
+{
+	return serial_console ? 0 : 1;
+}
+
+extern struct pt_regs *kbd_pt_regs;
+
 /* When a context switch happens we must flush all user windows so that
  * the windows of the current process are flushed onto its stack. This
  * way the windows are all clean for the next process and the stack
@@ -113,6 +124,7 @@
 	"restore; restore; restore; restore; restore; restore; restore"); \
 } while(0)
 #define finish_arch_switch(rq, next)	do{ }while(0)
+#define task_running(rq, p)		((rq)->curr == (p))
 
 	/* Much care has gone into this code, do not touch it.
 	 *
@@ -263,6 +275,15 @@
 #define local_irq_save(flags)	((flags) = read_psr_and_cli())
 #define local_irq_restore(flags)	setipl((flags))
 
+/* On sparc32 IRQ flags are the PSR register in the PSR_PIL
+ * field.
+ */
+#define irqs_disabled()		\
+({	unsigned long flags;	\
+	local_save_flags(flags);\
+	(flags & PSR_PIL) != 0;	\
+})
+
 #ifdef CONFIG_SMP
 
 extern unsigned char global_irq_holder;
@@ -282,9 +303,6 @@
 
 #define cli() local_irq_disable()
 #define sti() local_irq_enable()
-#define save_flags(x) local_save_flags(x)
-#define restore_flags(x) local_irq_restore(x)
-#define save_and_cli(x) local_irq_save(x)
 
 #endif
 
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sparc/unistd.h	Sun Sep 15 19:19:29 2002
@@ -203,7 +203,7 @@
 #define __NR_setpgid            185 /* Common                                      */
 #define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 #define __NR_tkill              187 /* SunOS: fpathconf                            */
-/* #define __NR_sysconf         188    SunOS Specific                              */
+#define __NR_exit_group		188 /* Linux specific, sysconf undef SunOS         */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
diff -Nru a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h
--- a/include/asm-sparc64/hardirq.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sparc64/hardirq.h	Sun Sep 15 19:19:29 2002
@@ -85,8 +85,10 @@
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
+# define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()	(preempt_count() != 0)
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 #define irq_exit()							\
diff -Nru a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h	Sun Sep 15 19:19:34 2002
+++ b/include/asm-sparc64/ide.h	Sun Sep 15 19:19:34 2002
@@ -78,112 +78,63 @@
  * The following are not needed for the non-m68k ports
  */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
-/* From m68k code... */
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-#define insw(port, buf, nr) ide_insw((port), (buf), (nr))
-#define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
-
-static __inline__ unsigned int inw_be(unsigned long addr)
-{
-	unsigned int ret;
-
-	__asm__ __volatile__("lduha [%1] %2, %0"
+/* XXX Known to be broken.  Axboe will fix the problems this
+ * XXX has by making seperate IN/OUT macros for IDE_DATA
+ * XXX register and rest of IDE regs and also using
+ * XXX ide_ioreg_t instead of u32 for ports. -DaveM
+ */
+
+#define HAVE_ARCH_IN_BYTE
+static __inline__ u8 IN_BYTE(ide_ioreg_t addr)
+{	u8 ret;
+	 __asm__ __volatile__("lduba [%1] %2, %0\t/* ide_in_byte */"
 			     : "=r" (ret)
 			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-
 	return ret;
 }
+static __inline__ u16 IN_WORD(ide_ioreg_t addr)
+{	u16 ret;
+	__asm__ __volatile__("lduha [%1] %2, %0\t/* ide_in_word */"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+	return ret;
+}
+static __inline__ u16 IN_LONG(ide_ioreg_t addr)
+{	u32 ret;
+	__asm__ __volatile__("lduwa [%1] %2, %0\t/* ide_in_long */"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+	return ret;
+}
+#define IN_BYTE_P		IN_BYTE
+#define IN_WORD_P		IN_WORD
+#define IN_LONG_P		IN_LONG
 
-static __inline__ void ide_insw(unsigned long port,
-				void *dst,
-				unsigned long count)
+#define HAVE_ARCH_OUT_BYTE
+static __inline__ void OUT_BYTE(u8 byte, ide_ioreg_t addr)
 {
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
-	unsigned long end = (unsigned long)dst + (count << 1);
-#endif
-	u16 *ps = dst;
-	u32 *pi;
-
-	if(((u64)ps) & 0x2) {
-		*ps++ = inw_be(port);
-		count--;
-	}
-	pi = (u32 *)ps;
-	while(count >= 2) {
-		u32 w;
-
-		w  = inw_be(port) << 16;
-		w |= inw_be(port);
-		*pi++ = w;
-		count -= 2;
-	}
-	ps = (u16 *)pi;
-	if(count)
-		*ps++ = inw_be(port);
-
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
-	__flush_dcache_range((unsigned long)dst, end);
-#endif
+	__asm__ __volatile__("stba %r0, [%1] %2\t/* ide_out_byte */"
+			     : /* no outputs */
+			     : "Jr" (byte), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
-
-static __inline__ void outw_be(unsigned short w, unsigned long addr)
+static __inline__ void OUT_WORD(u16 word, ide_ioreg_t addr)
 {
-	__asm__ __volatile__("stha %0, [%1] %2"
+	__asm__ __volatile__("stha %r0, [%1] %2\t/* ide_out_word */"
 			     : /* no outputs */
-			     : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
+			     : "Jr" (word), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
-
-static __inline__ void ide_outsw(unsigned long port,
-				 const void *src,
-				 unsigned long count)
+static __inline__ void OUT_LONG(u32 _long, ide_ioreg_t addr)
 {
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
-	unsigned long end = (unsigned long)src + (count << 1);
-#endif
-	const u16 *ps = src;
-	const u32 *pi;
-
-	if(((u64)src) & 0x2) {
-		outw_be(*ps++, port);
-		count--;
-	}
-	pi = (const u32 *)ps;
-	while(count >= 2) {
-		u32 w;
-
-		w = *pi++;
-		outw_be((w >> 16), port);
-		outw_be(w, port);
-		count -= 2;
-	}
-	ps = (const u16 *)pi;
-	if(count)
-		outw_be(*ps, port);
-
-#if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
-	__flush_dcache_range((unsigned long)src, end);
-#endif
+	__asm__ __volatile__("stwa %r0, [%1] %2\t/* ide_out_long */"
+			     : /* no outputs */
+			     : "Jr" (_long), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
+#define OUT_BYTE_P		OUT_BYTE
+#define OUT_WORD_P		OUT_WORD
+#define OUT_LONG_P		OUT_LONG
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
--- a/include/asm-sparc64/pgtable.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-sparc64/pgtable.h	Sun Sep 15 19:19:28 2002
@@ -369,6 +369,8 @@
 
 extern void check_pgt_cache(void);
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
diff -Nru a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
--- a/include/asm-sparc64/spinlock.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sparc64/spinlock.h	Sun Sep 15 19:19:29 2002
@@ -112,6 +112,7 @@
 typedef unsigned int rwlock_t;
 #define RW_LOCK_UNLOCKED	0
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
 
 extern void __read_lock(rwlock_t *);
 extern void __read_unlock(rwlock_t *);
@@ -132,6 +133,7 @@
 } rwlock_t;
 #define RW_LOCK_UNLOCKED	(rwlock_t) { 0, 0, 0xff, { 0, 0, 0, 0 } }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x) ((x)->lock != 0)
 
 extern void _do_read_lock(rwlock_t *rw, char *str);
 extern void _do_read_unlock(rwlock_t *rw, char *str);
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-sparc64/unistd.h	Sun Sep 15 19:19:29 2002
@@ -203,7 +203,7 @@
 #define __NR_setpgid            185 /* Common                                      */
 #define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 #define __NR_tkill              187 /* SunOS: fpathconf                            */
-/* #define __NR_sysconf         188    SunOS Specific                              */
+#define __NR_exit_group		188 /* Linux specific, sysconf undef SunOS         */
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
diff -Nru a/include/asm-um/a.out.h b/include/asm-um/a.out.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/a.out.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,18 @@
+#ifndef __UM_A_OUT_H
+#define __UM_A_OUT_H
+
+#include "asm/arch/a.out.h"
+
+#undef STACK_TOP
+
+extern unsigned long stacksizelim;
+
+extern unsigned long host_task_size;
+
+extern int honeypot;
+
+#define STACK_ROOM (stacksizelim)
+
+#define STACK_TOP (honeypot ? host_task_size : task_size)
+
+#endif
diff -Nru a/include/asm-um/arch-signal-i386.h b/include/asm-um/arch-signal-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/arch-signal-i386.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,24 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ARCH_SIGNAL_I386_H
+#define __UM_ARCH_SIGNAL_I386_H
+
+struct arch_signal_context {
+	unsigned long extrasigs[_NSIG_WORDS];
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/archparam-i386.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,80 @@
+/* 
+ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ARCHPARAM_I386_H
+#define __UM_ARCHPARAM_I386_H
+
+/********* Bits for asm-um/elf.h ************/
+
+#include "user.h"
+
+#define ELF_PLATFORM "i586"
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+typedef struct user_i387_struct elf_fpregset_t;
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+#define ELF_DATA        ELFDATA2LSB
+#define ELF_ARCH        EM_386
+
+#define ELF_PLAT_INIT(regs) do { \
+	PT_REGS_EBX(regs) = 0; \
+	PT_REGS_ECX(regs) = 0; \
+	PT_REGS_EDX(regs) = 0; \
+	PT_REGS_ESI(regs) = 0; \
+	PT_REGS_EDI(regs) = 0; \
+	PT_REGS_EBP(regs) = 0; \
+	PT_REGS_EAX(regs) = 0; \
+} while(0)
+
+/* Shamelessly stolen from include/asm-i386/elf.h */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do {	\
+	pr_reg[0] = PT_REGS_EBX(regs);		\
+	pr_reg[1] = PT_REGS_ECX(regs);		\
+	pr_reg[2] = PT_REGS_EDX(regs);		\
+	pr_reg[3] = PT_REGS_ESI(regs);		\
+	pr_reg[4] = PT_REGS_EDI(regs);		\
+	pr_reg[5] = PT_REGS_EBP(regs);		\
+	pr_reg[6] = PT_REGS_EAX(regs);		\
+	pr_reg[7] = PT_REGS_DS(regs);		\
+	pr_reg[8] = PT_REGS_ES(regs);		\
+	/* fake once used fs and gs selectors? */	\
+	pr_reg[9] = PT_REGS_DS(regs);		\
+	pr_reg[10] = PT_REGS_DS(regs);		\
+	pr_reg[11] = regs->regs.syscall;	\
+	pr_reg[12] = PT_REGS_IP(regs);		\
+	pr_reg[13] = PT_REGS_CS(regs);		\
+	pr_reg[14] = PT_REGS_EFLAGS(regs);	\
+	pr_reg[15] = PT_REGS_SP(regs);		\
+	pr_reg[16] = PT_REGS_SS(regs);		\
+} while(0);
+
+/********* Bits for asm-um/delay.h **********/
+
+typedef unsigned long um_udelay_t;
+
+/********* Nothing for asm-um/hardirq.h **********/
+
+/********* Nothing for asm-um/hw_irq.h **********/
+
+/********* Nothing for asm-um/string.h **********/
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/archparam-ppc.h b/include/asm-um/archparam-ppc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/archparam-ppc.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,41 @@
+#ifndef __UM_ARCHPARAM_PPC_H
+#define __UM_ARCHPARAM_PPC_H
+
+/********* Bits for asm-um/elf.h ************/
+
+#define ELF_PLATFORM (0)
+
+#define ELF_ET_DYN_BASE (0x08000000)
+
+/* the following stolen from asm-ppc/elf.h */
+#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
+#define ELF_NFPREG	33	/* includes fpscr */
+/* General registers */
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Floating point registers */
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_DATA        ELFDATA2MSB
+#define ELF_ARCH	EM_PPC
+
+/********* Bits for asm-um/delay.h **********/
+
+typedef unsigned int um_udelay_t;
+
+/********* Bits for asm-um/hw_irq.h **********/
+
+struct hw_interrupt_type;
+
+/********* Bits for asm-um/hardirq.h **********/
+
+#define irq_enter(cpu, irq) hardirq_enter(cpu)
+#define irq_exit(cpu, irq) hardirq_exit(cpu)
+
+/********* Bits for asm-um/string.h **********/
+
+#define __HAVE_ARCH_STRRCHR
+
+#endif
diff -Nru a/include/asm-um/atomic.h b/include/asm-um/atomic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/atomic.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_ATOMIC_H
+#define __UM_ATOMIC_H
+
+#include "asm/arch/atomic.h"
+
+#endif
diff -Nru a/include/asm-um/bitops.h b/include/asm-um/bitops.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/bitops.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BITOPS_H
+#define __UM_BITOPS_H
+
+#include "asm/arch/bitops.h"
+
+#endif
diff -Nru a/include/asm-um/boot.h b/include/asm-um/boot.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/boot.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BOOT_H
+#define __UM_BOOT_H
+
+#include "asm/arch/boot.h"
+
+#endif
diff -Nru a/include/asm-um/bugs.h b/include/asm-um/bugs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/bugs.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BUGS_H
+#define __UM_BUGS_H
+
+void check_bugs(void);
+
+#endif
diff -Nru a/include/asm-um/byteorder.h b/include/asm-um/byteorder.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/byteorder.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_BYTEORDER_H
+#define __UM_BYTEORDER_H
+
+#include "asm/arch/byteorder.h"
+
+#endif
diff -Nru a/include/asm-um/cache.h b/include/asm-um/cache.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/cache.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,7 @@
+#ifndef __UM_CACHE_H
+#define __UM_CACHE_H
+
+#define L1_CACHE_SHIFT 5
+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+
+#endif
diff -Nru a/include/asm-um/cacheflush.h b/include/asm-um/cacheflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/cacheflush.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_CACHEFLUSH_H
+#define __UM_CACHEFLUSH_H
+
+#include "asm/arch/cacheflush.h"
+
+#endif
diff -Nru a/include/asm-um/checksum.h b/include/asm-um/checksum.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/checksum.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_CHECKSUM_H
+#define __UM_CHECKSUM_H
+
+#include "asm/arch/checksum.h"
+
+#endif
diff -Nru a/include/asm-um/cobalt.h b/include/asm-um/cobalt.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/cobalt.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_COBALT_H
+#define __UM_COBALT_H
+
+#include "asm/arch/cobalt.h"
+
+#endif
diff -Nru a/include/asm-um/current.h b/include/asm-um/current.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/current.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,34 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_CURRENT_H
+#define __UM_CURRENT_H
+
+#ifndef __ASSEMBLY__
+
+struct thread_info;
+
+#include "linux/config.h"
+#include "asm/page.h"
+
+#define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & (PAGE_MASK << 2))
+
+#define current ({ int dummy; \
+                   ((struct thread_info *) CURRENT_THREAD(dummy))->task; })
+
+#endif /* __ASSEMBLY__ */
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/delay.h b/include/asm-um/delay.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/delay.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,7 @@
+#ifndef __UM_DELAY_H
+#define __UM_DELAY_H
+
+#include "asm/arch/delay.h"
+#include "asm/archparam.h"
+
+#endif
diff -Nru a/include/asm-um/desc.h b/include/asm-um/desc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/desc.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_DESC_H
+#define __UM_DESC_H
+
+#include "asm/arch/desc.h"
+
+#endif
diff -Nru a/include/asm-um/div64.h b/include/asm-um/div64.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/div64.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef _UM_DIV64_H
+#define _UM_DIV64_H
+
+#include "asm/arch/div64.h"
+
+#endif
diff -Nru a/include/asm-um/dma.h b/include/asm-um/dma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/dma.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_DMA_H
+#define __UM_DMA_H
+
+#include "asm/io.h"
+
+extern unsigned long uml_physmem;
+
+#define MAX_DMA_ADDRESS (uml_physmem)
+
+#endif
diff -Nru a/include/asm-um/elf.h b/include/asm-um/elf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/elf.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,18 @@
+#ifndef __UM_ELF_H
+#define __UM_ELF_H
+
+#include "asm/archparam.h"
+
+#define ELF_HWCAP (0)
+
+#define SET_PERSONALITY(ex, ibcs2) do ; while(0)
+
+#define ELF_EXEC_PAGESIZE 4096
+
+#define elf_check_arch(x) (1)
+
+#define ELF_CLASS ELFCLASS32
+
+#define USE_ELF_CORE_DUMP
+
+#endif
diff -Nru a/include/asm-um/errno.h b/include/asm-um/errno.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/errno.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_ERRNO_H
+#define __UM_ERRNO_H
+
+#include "asm/arch/errno.h"
+
+#endif
diff -Nru a/include/asm-um/fcntl.h b/include/asm-um/fcntl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/fcntl.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_FCNTL_H
+#define __UM_FCNTL_H
+
+#include "asm/arch/fcntl.h"
+
+#endif
diff -Nru a/include/asm-um/floppy.h b/include/asm-um/floppy.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/floppy.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_FLOPPY_H
+#define __UM_FLOPPY_H
+
+#include "asm/arch/floppy.h"
+
+#endif
diff -Nru a/include/asm-um/hardirq.h b/include/asm-um/hardirq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/hardirq.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HARDIRQ_H
+#define __UM_HARDIRQ_H
+
+#include "asm/arch/hardirq.h"
+
+#endif
diff -Nru a/include/asm-um/hdreg.h b/include/asm-um/hdreg.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/hdreg.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HDREG_H
+#define __UM_HDREG_H
+
+#include "asm/arch/hdreg.h"
+
+#endif
diff -Nru a/include/asm-um/highmem.h b/include/asm-um/highmem.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/highmem.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_HIGHMEM_H
+#define __UM_HIGHMEM_H
+
+#include "asm/arch/highmem.h"
+
+#endif
diff -Nru a/include/asm-um/hw_irq.h b/include/asm-um/hw_irq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/hw_irq.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,10 @@
+#ifndef _ASM_UM_HW_IRQ_H
+#define _ASM_UM_HW_IRQ_H
+
+#include "asm/irq.h"
+#include "asm/archparam.h"
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+{}
+
+#endif
diff -Nru a/include/asm-um/ide.h b/include/asm-um/ide.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ide.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IDE_H
+#define __UM_IDE_H
+
+#include "asm/arch/ide.h"
+
+#endif
diff -Nru a/include/asm-um/init.h b/include/asm-um/init.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/init.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,11 @@
+#ifndef _UM_INIT_H
+#define _UM_INIT_H
+
+#ifdef notdef
+#define __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+#define __cacheline_aligned 
+#endif
+
+#endif
diff -Nru a/include/asm-um/io.h b/include/asm-um/io.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/io.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,25 @@
+#ifndef __UM_IO_H
+#define __UM_IO_H
+
+#include "asm/page.h"
+
+#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */
+
+static inline int inb(unsigned long i) { return(0); }
+static inline void outb(char c, unsigned long i) { }
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are pretty trivial
+ */
+static inline unsigned long virt_to_phys(volatile void * address)
+{
+	return __pa((void *) address);
+}
+
+static inline void * phys_to_virt(unsigned long address)
+{
+	return __va(address);
+}
+
+#endif
diff -Nru a/include/asm-um/ioctl.h b/include/asm-um/ioctl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ioctl.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IOCTL_H
+#define __UM_IOCTL_H
+
+#include "asm/arch/ioctl.h"
+
+#endif
diff -Nru a/include/asm-um/ioctls.h b/include/asm-um/ioctls.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ioctls.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IOCTLS_H
+#define __UM_IOCTLS_H
+
+#include "asm/arch/ioctls.h"
+
+#endif
diff -Nru a/include/asm-um/ipc.h b/include/asm-um/ipc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ipc.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IPC_H
+#define __UM_IPC_H
+
+#include "asm/arch/ipc.h"
+
+#endif
diff -Nru a/include/asm-um/ipcbuf.h b/include/asm-um/ipcbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ipcbuf.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_IPCBUF_H
+#define __UM_IPCBUF_H
+
+#include "asm/arch/ipcbuf.h"
+
+#endif
diff -Nru a/include/asm-um/irq.h b/include/asm-um/irq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/irq.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,35 @@
+#ifndef __UM_IRQ_H
+#define __UM_IRQ_H
+
+/* The i386 irq.h has a struct task_struct in a prototype without including
+ * sched.h.  This forward declaration kills the resulting warning.
+ */
+struct task_struct;
+
+#include "asm/arch/irq.h"
+#include "asm/ptrace.h"
+
+#undef NR_IRQS
+
+#define TIMER_IRQ		0
+#define UMN_IRQ			1
+#define CONSOLE_IRQ		2
+#define CONSOLE_WRITE_IRQ	3
+#define UBD_IRQ			4
+#define UM_ETH_IRQ		5
+#define SSL_IRQ			6
+#define SSL_WRITE_IRQ		7
+#define ACCEPT_IRQ		8
+#define MCONSOLE_IRQ		9
+#define WINCH_IRQ		10
+#define SIGIO_WRITE_IRQ 	11
+#define TELNETD_IRQ 		12
+
+#define LAST_IRQ TELNETD_IRQ
+#define NR_IRQS (LAST_IRQ + 1)
+
+extern int um_request_irq(unsigned int irq, int fd, int type,
+			  void (*handler)(int, void *, struct pt_regs *),
+			  unsigned long irqflags,  const char * devname,
+			  void *dev_id);
+#endif
diff -Nru a/include/asm-um/irq_vectors.h b/include/asm-um/irq_vectors.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/irq_vectors.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,20 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_IRQ_VECTORS_H
+#define __UM_IRQ_VECTORS_H
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/keyboard.h b/include/asm-um/keyboard.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/keyboard.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_KEYBOARD_H
+#define __UM_KEYBOARD_H
+
+#include "asm/arch/keyboard.h"
+
+#endif
diff -Nru a/include/asm-um/kmap_types.h b/include/asm-um/kmap_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/kmap_types.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,11 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_KMAP_TYPES_H
+#define __UM_KMAP_TYPES_H
+
+#include "asm/arch/kmap_types.h"
+
+#endif
diff -Nru a/include/asm-um/linkage.h b/include/asm-um/linkage.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/linkage.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#define FASTCALL(x)	x __attribute__((regparm(3)))
+
+#endif
diff -Nru a/include/asm-um/linux_logo.h b/include/asm-um/linux_logo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/linux_logo.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_LINUX_LOGO_H
+#define __UM_LINUX_LOGO_H
+
+#include "asm/arch/linux_logo.h"
+
+#endif
diff -Nru a/include/asm-um/locks.h b/include/asm-um/locks.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/locks.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_LOCKS_H
+#define __UM_LOCKS_H
+
+#include "asm/arch/locks.h"
+
+#endif
diff -Nru a/include/asm-um/mca_dma.h b/include/asm-um/mca_dma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/mca_dma.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef mca___UM_DMA_H
+#define mca___UM_DMA_H
+
+#include "asm/arch/mca_dma.h"
+
+#endif
diff -Nru a/include/asm-um/mman.h b/include/asm-um/mman.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/mman.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MMAN_H
+#define __UM_MMAN_H
+
+#include "asm/arch/mman.h"
+
+#endif
diff -Nru a/include/asm-um/mmu.h b/include/asm-um/mmu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/mmu.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __MMU_H
+#define __MMU_H
+
+#include "asm/arch/mmu.h"
+
+#endif
diff -Nru a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/mmu_context.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,25 @@
+#ifndef __UM_MMU_CONTEXT_H
+#define __UM_MMU_CONTEXT_H
+
+#include "linux/sched.h"
+
+#define init_new_context(task, mm) (0)
+#define get_mmu_context(task) do ; while(0)
+#define activate_context(tsk) do ; while(0)
+#define destroy_context(mm) do ; while(0)
+
+static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
+{
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+			     struct task_struct *tsk, unsigned cpu)
+{
+}
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, 
+				  struct task_struct *tsk, unsigned cpu)
+{
+}
+
+#endif
diff -Nru a/include/asm-um/module.h b/include/asm-um/module.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/module.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MODULE_H
+#define __UM_MODULE_H
+
+#include "asm/arch/module.h"
+
+#endif
diff -Nru a/include/asm-um/msgbuf.h b/include/asm-um/msgbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/msgbuf.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MSGBUF_H
+#define __UM_MSGBUF_H
+
+#include "asm/arch/msgbuf.h"
+
+#endif
diff -Nru a/include/asm-um/mtrr.h b/include/asm-um/mtrr.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/mtrr.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_MTRR_H
+#define __UM_MTRR_H
+
+#include "asm/arch/mtrr.h"
+
+#endif
diff -Nru a/include/asm-um/namei.h b/include/asm-um/namei.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/namei.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_NAMEI_H
+#define __UM_NAMEI_H
+
+#include "asm/arch/namei.h"
+
+#endif
diff -Nru a/include/asm-um/page.h b/include/asm-um/page.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/page.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,60 @@
+#ifndef __UM_PAGE_H
+#define __UM_PAGE_H
+
+struct page;
+
+#include "asm/arch/page.h"
+
+#undef BUG
+#undef PAGE_BUG
+#undef __pa
+#undef __va
+#undef pfn_to_page
+#undef page_to_pfn
+#undef virt_to_page
+#undef pfn_valid
+#undef virt_addr_valid
+#undef VALID_PAGE
+#undef PAGE_OFFSET
+#undef KERNELBASE
+
+#define PAGE_OFFSET (uml_physmem)
+#define KERNELBASE PAGE_OFFSET
+
+#ifndef __ASSEMBLY__
+
+extern void stop(void);
+
+#define BUG() do { \
+	panic("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+	BUG(); \
+} while (0)
+
+#endif /* __ASSEMBLY__ */
+
+#define __va_space (8*1024*1024)
+
+extern unsigned long region_pa(void *virt);
+extern void *region_va(unsigned long phys);
+
+#define __pa(virt) region_pa((void *) (virt))
+#define __va(phys) region_va((unsigned long) (phys))
+
+extern struct page *phys_to_page(unsigned long phys);
+
+#define pfn_to_page(pfn) (phys_to_page(pfn << PAGE_SHIFT))
+#define page_to_pfn(page) (page_to_phys(page) >> PAGE_SHIFT)
+#define virt_to_page(v) (phys_to_page(__pa(v)))
+
+extern struct page *page_mem_map(struct page *page);
+
+#define pfn_valid(pfn) (page_mem_map(pfn_to_page(pfn)) != NULL)
+#define virt_addr_valid(v) pfn_valid(__pa(v) >> PAGE_SHIFT)
+
+extern struct page *arch_validate(struct page *page, int mask, int order);
+#define HAVE_ARCH_VALIDATE
+
+#endif
diff -Nru a/include/asm-um/page_offset.h b/include/asm-um/page_offset.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/page_offset.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1 @@
+#define PAGE_OFFSET_RAW (uml_physmem)
diff -Nru a/include/asm-um/param.h b/include/asm-um/param.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/param.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,22 @@
+#ifndef _UM_PARAM_H
+#define _UM_PARAM_H
+
+#define EXEC_PAGESIZE   4096
+
+#ifndef NGROUPS
+#define NGROUPS         32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP         (-1)
+#endif
+
+#define MAXHOSTNAMELEN  64      /* max length of hostname */
+
+#ifdef __KERNEL__
+#define HZ 100
+#define USER_HZ	100	   /* .. some user interfaces are in "ticks" */
+#define CLOCKS_PER_SEC (USER_HZ)  /* frequency at which times() counts */
+#endif
+
+#endif
diff -Nru a/include/asm-um/pci.h b/include/asm-um/pci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/pci.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_PCI_H
+#define __UM_PCI_H
+
+#define PCI_DMA_BUS_IS_PHYS     (1)
+
+#endif
diff -Nru a/include/asm-um/percpu.h b/include/asm-um/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/percpu.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_CACHEFLUSH_H
+#define __UM_CACHEFLUSH_H
+
+#include "asm/arch/percpu.h"
+
+#endif
diff -Nru a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/pgalloc.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,62 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PGALLOC_H
+#define __UM_PGALLOC_H
+
+#include "linux/mm.h"
+
+#define pmd_populate_kernel(mm, pmd, pte) \
+		set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, 
+				struct page *pte)
+{
+	set_pmd(pmd, __pmd(_PAGE_TABLE + phys_addr(page_to_phys(pte))));
+}
+
+extern pgd_t *pgd_alloc(struct mm_struct *);
+extern void pgd_free(pgd_t *pgd);
+
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *, unsigned long);
+extern struct page *pte_alloc_one(struct mm_struct *, unsigned long);
+
+static inline void pte_free_kernel(pte_t *pte)
+{
+	free_page((unsigned long) pte);
+}
+
+static inline void pte_free(struct page *pte)
+{
+	__free_page(pte);
+}
+
+#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+
+#define pmd_alloc_one(mm, addr)		({ BUG(); ((pmd_t *)2); })
+#define pmd_free(x)			do { } while (0)
+#define __pmd_free_tlb(tlb,x)		do { } while (0)
+#define pgd_populate(mm, pmd, pte)	BUG()
+
+#define check_pgt_cache()	do { } while (0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/pgtable.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,389 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Derived from include/asm-i386/pgtable.h
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PGTABLE_H
+#define __UM_PGTABLE_H
+
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/page.h"
+
+extern pgd_t swapper_pg_dir[1024];
+
+/* zero page used for uninitialized stuff */
+extern unsigned long *empty_zero_page;
+
+#define pgtable_cache_init() do ; while (0)
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT	22
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT	22
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: the i386 is two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE	1024
+#define PTRS_PER_PMD	1
+#define PTRS_PER_PGD	1024
+#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_PGD_NR       0
+
+#define pte_ERROR(e) \
+        printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+        printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+        printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * pgd entries used up by user/kernel:
+ */
+
+#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#ifndef __ASSEMBLY__
+/* Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+
+extern unsigned long high_physmem;
+extern unsigned long end_vm;
+
+#define VMALLOC_OFFSET	(__va_space)
+#define VMALLOC_START	(((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END	(end_vm)
+
+#define _PAGE_PRESENT	0x001
+#define _PAGE_NEWPAGE	0x002
+#define _PAGE_PROTNONE	0x004	/* If not present */
+#define _PAGE_RW	0x008
+#define _PAGE_USER	0x010
+#define _PAGE_ACCESSED	0x020
+#define _PAGE_DIRTY	0x040
+#define _PAGE_NEWPROT   0x080
+
+#define REGION_MASK	0xf0000000
+#define REGION_SHIFT	28
+
+#define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+/*
+ * The i386 can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#define __P000	PAGE_NONE
+#define __P001	PAGE_READONLY
+#define __P010	PAGE_COPY
+#define __P011	PAGE_COPY
+#define __P100	PAGE_READONLY
+#define __P101	PAGE_READONLY
+#define __P110	PAGE_COPY
+#define __P111	PAGE_COPY
+
+#define __S000	PAGE_NONE
+#define __S001	PAGE_READONLY
+#define __S010	PAGE_SHARED
+#define __S011	PAGE_SHARED
+#define __S100	PAGE_READONLY
+#define __S101	PAGE_READONLY
+#define __S110	PAGE_SHARED
+#define __S111	PAGE_SHARED
+
+/*
+ * Define this if things work differently on an i386 and an i486:
+ * it will (on an i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef TEST_VERIFY_AREA
+
+/* page table for 0-4MB for everybody */
+extern unsigned long pg0[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR			(8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK			(~(sizeof(void*)-1))
+
+/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* 64-bit machines, beware!  SRB. */
+#define SIZEOF_PTR_LOG2			2
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+#define pte_none(x)	!(pte_val(x) & ~_PAGE_NEWPAGE)
+#define pte_present(x)	(pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+
+#define pte_clear(xp)	do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
+
+#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT)
+#define pte_region_index(x) phys_region_index(pte_val(x))
+
+#define pmd_none(x)	(!(pmd_val(x) & ~_PAGE_NEWPAGE))
+#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+#define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
+#define pmd_clear(xp)	do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
+
+#define pmd_newpage(x)  (pmd_val(x) & _PAGE_NEWPAGE)
+#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE)
+
+/*
+ * The "pgd_xxx()" functions here are trivial for a folded two-level
+ * setup: the pgd is never bad, and a pmd always exists (as it's folded
+ * into the pgd entry)
+ */
+static inline int pgd_none(pgd_t pgd)		{ return 0; }
+static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+static inline int pgd_present(pgd_t pgd)	{ return 1; }
+static inline void pgd_clear(pgd_t * pgdp)	{ }
+
+
+#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+
+extern struct page *pte_mem_map(pte_t pte);
+extern struct page *phys_mem_map(unsigned long phys);
+
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
+#define mk_phys(a, r) ((a) + (r << REGION_SHIFT))
+#define phys_addr(p) ((p) & ~REGION_MASK)
+#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT))
+#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
+#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+static inline pte_t pte_mknewprot(pte_t pte)
+{
+ 	pte_val(pte) |= _PAGE_NEWPROT;
+	return(pte);
+}
+
+static inline pte_t pte_mknewpage(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_NEWPAGE;
+	return(pte);
+}
+
+static inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+	/* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so
+	 * fix_range knows to unmap it.  _PAGE_NEWPROT is specific to
+	 * mapped pages.
+	 */
+	*pteptr = pte_mknewpage(pteval);
+	if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr);
+}
+
+/*
+ * (pmds are folded into pgds so this doesnt get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_exec(pte_t pte)	{ return pte_val(pte) & _PAGE_USER; }
+static inline int pte_dirty(pte_t pte)	{ return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte)	{ return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte)	{ return pte_val(pte) & _PAGE_RW; }
+static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
+static inline int pte_newprot(pte_t pte)
+{ 
+	return(pte_present(pte) && (pte_val(pte) & _PAGE_NEWPROT)); 
+}
+
+static inline pte_t pte_rdprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_USER; 
+	return(pte_mknewprot(pte));
+}
+
+static inline pte_t pte_exprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_USER;
+	return(pte_mknewprot(pte));
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+	pte_val(pte) &= ~_PAGE_DIRTY; 
+	return(pte);
+}
+
+static inline pte_t pte_mkold(pte_t pte)	
+{ 
+	pte_val(pte) &= ~_PAGE_ACCESSED; 
+	return(pte);
+}
+
+static inline pte_t pte_wrprotect(pte_t pte)
+{ 
+	pte_val(pte) &= ~_PAGE_RW; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkread(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_USER; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkexec(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_USER; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{ 
+	pte_val(pte) |= _PAGE_DIRTY; 
+	return(pte);
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_ACCESSED; 
+	return(pte);
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)	
+{
+	pte_val(pte) |= _PAGE_RW; 
+	return(pte_mknewprot(pte)); 
+}
+
+static inline pte_t pte_mkuptodate(pte_t pte)	
+{
+	pte_val(pte) &= ~_PAGE_NEWPAGE;
+	if(pte_present(pte)) pte_val(pte) &= ~_PAGE_NEWPROT;
+	return(pte); 
+}
+
+extern unsigned long page_to_phys(struct page *page);
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+#define mk_pte(page, pgprot) \
+({					\
+	pte_t __pte;                    \
+                                        \
+	pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\
+	if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \
+	__pte;                          \
+})
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte));
+	return pte; 
+}
+
+#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \
+		       ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT)))
+
+/* to find an entry in a page-table-directory. */
+#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm, address) \
+((mm)->pgd + ((address) >> PGDIR_SHIFT))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* Find an entry in the second-level page table.. */
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+	return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */ 
+#define __pte_offset(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, address) \
+	((pte_t *) pmd_page_kernel(*(dir)) +  __pte_offset(address))
+#define pte_offset_map(dir, address) \
+        ((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + __pte_offset(address))
+#define pte_offset_map_nested(dir, address) \
+	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + __pte_offset(address))
+#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+
+#define update_mmu_cache(vma,address,pte) do ; while (0)
+
+/* Encode and de-code a swap entry */
+#define __swp_type(x)			(((x).val >> 3) & 0x7f)
+#define __swp_offset(x)			((x).val >> 10)
+
+#define __swp_entry(type, offset) \
+	((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
+#define __pte_to_swp_entry(pte) \
+	((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
+#define __swp_entry_to_pte(x)		((pte_t) { (x).val })
+
+#define kern_addr_valid(addr) (1)
+
+#include <asm-generic/pgtable.h>
+
+#endif
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/poll.h b/include/asm-um/poll.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/poll.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_POLL_H
+#define __UM_POLL_H
+
+#include "asm/arch/poll.h"
+
+#endif
diff -Nru a/include/asm-um/posix_types.h b/include/asm-um/posix_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/posix_types.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_POSIX_TYPES_H
+#define __UM_POSIX_TYPES_H
+
+#include "asm/arch/posix_types.h"
+
+#endif
diff -Nru a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/processor-generic.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,157 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PROCESSOR_GENERIC_H
+#define __UM_PROCESSOR_GENERIC_H
+
+struct pt_regs;
+
+struct task_struct;
+
+#include "linux/config.h"
+#include "linux/signal.h"
+#include "asm/segment.h"
+#include "asm/ptrace.h"
+#include "asm/siginfo.h"
+
+struct mm_struct;
+
+#define current_text_addr() ((void *) 0)
+
+#define cpu_relax()	do ; while (0)
+
+struct thread_struct {
+	int extern_pid;
+	int tracing;
+	int forking;
+	unsigned long kernel_stack;
+	int nsyscalls;
+	struct pt_regs regs;
+	unsigned long cr2;
+	int err;
+	void *fault_addr;
+	void *fault_catcher;
+	int vm_seq;
+	struct task_struct *prev_sched;
+	unsigned long temp_stack;
+	int switch_pipe[2];
+	void *jmp;
+	struct arch_thread arch;
+	int singlestep_syscall;
+	struct {
+		int op;
+		union {
+			struct {
+				int pid;
+			} fork, exec;
+			struct {
+				int (*proc)(void *);
+				void *arg;
+			} thread;
+			struct {
+				void (*proc)(void *);
+				void *arg;
+			} cb;
+		} u;
+	} request;
+};
+
+#define INIT_THREAD \
+{ \
+	extern_pid:		-1, \
+	tracing:		0, \
+	forking:		0, \
+	kernel_stack:		0, \
+	nsyscalls:		0, \
+        regs:		   	EMPTY_REGS, \
+	cr2:			0, \
+	err:			0, \
+	fault_addr:		NULL, \
+	vm_seq:			0, \
+	prev_sched:		NULL, \
+	temp_stack:		0, \
+	switch_pipe:		{ -1, -1 }, \
+	jmp:			NULL, \
+	arch:			INIT_ARCH_THREAD, \
+	singlestep_syscall:	0, \
+	request:		{ 0 } \
+}
+
+#define INIT_THREAD_SIZE (4 * PAGE_SIZE)
+
+typedef struct {
+	unsigned long seg;
+} mm_segment_t;
+
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *task);
+
+extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern void dump_thread(struct pt_regs *regs, struct user *u);
+
+static inline void release_segments(struct mm_struct *mm)
+{
+}
+
+static inline void copy_segments(struct task_struct *p, 
+				 struct mm_struct *new_mm)
+{
+}
+
+#define forget_segments() do ; while(0)
+
+extern unsigned long thread_saved_pc(struct task_struct *t);
+
+#define init_stack	(init_thread_union.stack)
+
+/*
+ * User space process size: 3GB (default).
+ */
+extern unsigned long task_size;
+
+#define TASK_SIZE	(task_size)
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE	(0x40000000)
+
+extern void start_thread(struct pt_regs *regs, unsigned long entry, 
+			 unsigned long stack);
+
+struct cpuinfo_um {
+	unsigned long loops_per_jiffy;
+	int ipi_pipe[2];
+};
+
+extern struct cpuinfo_um boot_cpu_data;
+
+#define my_cpu_data		cpu_data[smp_processor_id()]
+
+#ifdef CONFIG_SMP
+extern struct cpuinfo_um cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+#endif
+
+#define KSTK_EIP(tsk) (PT_REGS_IP(&tsk->thread.regs))
+#define KSTK_ESP(tsk) (PT_REGS_SP(&tsk->thread.regs))
+#define get_wchan(p) (0)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/processor-i386.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,35 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PROCESSOR_I386_H
+#define __UM_PROCESSOR_I386_H
+
+extern int cpu_has_xmm;
+extern int cpu_has_cmov;
+
+struct arch_thread {
+	unsigned long debugregs[8];
+	int debugregs_seq;
+};
+
+#define INIT_ARCH_THREAD { debugregs : 		{ [ 0 ... 7 ] = 0 }, \
+                           debugregs_seq :	0 }
+
+#include "asm/arch/user.h"
+
+#include "asm/processor-generic.h"
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/processor-ppc.h b/include/asm-um/processor-ppc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/processor-ppc.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,15 @@
+#ifndef __UM_PROCESSOR_PPC_H
+#define __UM_PROCESSOR_PPC_H
+
+#if defined(__ASSEMBLY__)
+
+#define CONFIG_ALL_PPC
+#include "arch/processor.h"
+
+#else
+
+#include "asm/processor-generic.h"
+
+#endif
+
+#endif
diff -Nru a/include/asm-um/ptrace-generic.h b/include/asm-um/ptrace-generic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ptrace-generic.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,69 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PTRACE_GENERIC_H
+#define __UM_PTRACE_GENERIC_H
+
+#ifndef __ASSEMBLY__
+
+#include "asm/current.h"
+
+#define pt_regs pt_regs_subarch
+#define show_regs show_regs_subarch
+
+#include "asm/arch/ptrace.h"
+
+#undef pt_regs
+#undef show_regs
+#undef user_mode
+#undef instruction_pointer
+
+#include "sysdep/ptrace.h"
+
+struct pt_regs {
+	struct uml_pt_regs regs;
+};
+
+#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS }
+
+#define PT_REGS_IP(r) UPT_IP(&(r)->regs)
+#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
+
+#define PT_REG(r, reg) UPT_REG(&(r)->regs, reg)
+#define PT_REGS_SET(r, reg, val) UPT_SET(&(r)->regs, reg, val)
+
+#define PT_REGS_SET_SYSCALL_RETURN(r, res) \
+	UPT_SET_SYSCALL_RETURN(&(r)->regs, res)
+#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs)
+
+#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs)
+
+#define PT_REGS_SC(r) UPT_SC(&(r)->regs)
+
+struct task_struct;
+
+extern unsigned long getreg(struct task_struct *child, int regno);
+extern int putreg(struct task_struct *child, int regno, unsigned long value);
+extern int get_fpregs(unsigned long buf, struct task_struct *child);
+extern int set_fpregs(unsigned long buf, struct task_struct *child);
+extern int get_fpxregs(unsigned long buf, struct task_struct *child);
+extern int set_fpxregs(unsigned long buf, struct task_struct *tsk);
+
+extern void show_regs(struct pt_regs *regs);
+
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/ptrace-i386.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,45 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PTRACE_I386_H
+#define __UM_PTRACE_I386_H
+
+#include "asm/ptrace-generic.h"
+
+#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
+#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
+#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
+#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
+#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
+#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
+#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
+
+#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
+#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
+#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
+#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
+#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
+#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
+
+#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define user_mode(r) ((r)->regs.is_user)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/resource.h b/include/asm-um/resource.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/resource.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_RESOURCE_H
+#define __UM_RESOURCE_H
+
+#include "asm/arch/resource.h"
+
+#endif
diff -Nru a/include/asm-um/rmap.h b/include/asm-um/rmap.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/rmap.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_RMAP_H
+#define __UM_RMAP_H
+
+#include "asm/arch/rmap.h"
+
+#endif
diff -Nru a/include/asm-um/rwlock.h b/include/asm-um/rwlock.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/rwlock.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_RWLOCK_H
+#define __UM_RWLOCK_H
+
+#include "asm/arch/rwlock.h"
+
+#endif
diff -Nru a/include/asm-um/rwsem.h b/include/asm-um/rwsem.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/rwsem.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_RWSEM_H__
+#define __UM_RWSEM_H__
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(exp,c) (exp)
+#endif
+
+#include "asm/arch/rwsem.h"
+
+#endif
diff -Nru a/include/asm-um/scatterlist.h b/include/asm-um/scatterlist.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/scatterlist.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SCATTERLIST_H
+#define __UM_SCATTERLIST_H
+
+#include "asm/arch/scatterlist.h"
+
+#endif
diff -Nru a/include/asm-um/segment.h b/include/asm-um/segment.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/segment.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,4 @@
+#ifndef __UM_SEGMENT_H
+#define __UM_SEGMENT_H
+
+#endif
diff -Nru a/include/asm-um/semaphore.h b/include/asm-um/semaphore.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/semaphore.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SEMAPHORE_H
+#define __UM_SEMAPHORE_H
+
+#include "asm/arch/semaphore.h"
+
+#endif
diff -Nru a/include/asm-um/sembuf.h b/include/asm-um/sembuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/sembuf.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SEMBUF_H
+#define __UM_SEMBUF_H
+
+#include "asm/arch/sembuf.h"
+
+#endif
diff -Nru a/include/asm-um/serial.h b/include/asm-um/serial.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/serial.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SERIAL_H
+#define __UM_SERIAL_H
+
+#include "asm/arch/serial.h"
+
+#endif
diff -Nru a/include/asm-um/shmbuf.h b/include/asm-um/shmbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/shmbuf.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SHMBUF_H
+#define __UM_SHMBUF_H
+
+#include "asm/arch/shmbuf.h"
+
+#endif
diff -Nru a/include/asm-um/shmparam.h b/include/asm-um/shmparam.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/shmparam.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SHMPARAM_H
+#define __UM_SHMPARAM_H
+
+#include "asm/arch/shmparam.h"
+
+#endif
diff -Nru a/include/asm-um/sigcontext-generic.h b/include/asm-um/sigcontext-generic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/sigcontext-generic.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGCONTEXT_GENERIC_H
+#define __UM_SIGCONTEXT_GENERIC_H
+
+#include "asm/arch/sigcontext.h"
+
+#endif
diff -Nru a/include/asm-um/sigcontext-i386.h b/include/asm-um/sigcontext-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/sigcontext-i386.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGCONTEXT_I386_H
+#define __UM_SIGCONTEXT_I386_H
+
+#include "asm/sigcontext-generic.h"
+
+#endif
diff -Nru a/include/asm-um/sigcontext-ppc.h b/include/asm-um/sigcontext-ppc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/sigcontext-ppc.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_SIGCONTEXT_PPC_H
+#define __UM_SIGCONTEXT_PPC_H
+
+#define pt_regs sys_pt_regs
+
+#include "asm/sigcontext-generic.h"
+
+#undef pt_regs
+
+#endif
diff -Nru a/include/asm-um/siginfo.h b/include/asm-um/siginfo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/siginfo.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGINFO_H
+#define __UM_SIGINFO_H
+
+#include "asm/arch/siginfo.h"
+
+#endif
diff -Nru a/include/asm-um/signal.h b/include/asm-um/signal.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/signal.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,26 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_SIGNAL_H
+#define __UM_SIGNAL_H
+
+/* Need to kill the do_signal() declaration in the i386 signal.h */
+
+#define do_signal do_signal_renamed
+#include "asm/arch/signal.h"
+#undef do_signal
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/smp.h b/include/asm-um/smp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/smp.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,20 @@
+#ifndef __UM_SMP_H
+#define __UM_SMP_H
+
+extern unsigned long cpu_online_map;
+
+#ifdef CONFIG_SMP
+
+#include "linux/config.h"
+#include "asm/current.h"
+
+#define smp_processor_id() (current->processor)
+#define cpu_logical_map(n) (n)
+#define cpu_number_map(n) (n)
+#define PROC_CHANGE_PENALTY	15 /* Pick a number, any number */
+extern int hard_smp_processor_id(void);
+#define NO_PROC_ID -1
+
+#endif
+
+#endif
diff -Nru a/include/asm-um/smplock.h b/include/asm-um/smplock.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/smplock.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SMPLOCK_H
+#define __UM_SMPLOCK_H
+
+#include "asm/arch/smplock.h"
+
+#endif
diff -Nru a/include/asm-um/socket.h b/include/asm-um/socket.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/socket.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SOCKET_H
+#define __UM_SOCKET_H
+
+#include "asm/arch/socket.h"
+
+#endif
diff -Nru a/include/asm-um/sockios.h b/include/asm-um/sockios.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/sockios.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SOCKIOS_H
+#define __UM_SOCKIOS_H
+
+#include "asm/arch/sockios.h"
+
+#endif
diff -Nru a/include/asm-um/softirq.h b/include/asm-um/softirq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/softirq.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,13 @@
+#ifndef __UM_SOFTIRQ_H
+#define __UM_SOFTIRQ_H
+
+#include "linux/smp.h"
+#include "asm/system.h"
+#include "asm/processor.h"
+
+/* A gratuitous name change */
+#define i386_bh_lock um_bh_lock
+#include "asm/arch/softirq.h"
+#undef i386_bh_lock
+
+#endif
diff -Nru a/include/asm-um/spinlock.h b/include/asm-um/spinlock.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/spinlock.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,10 @@
+#ifndef __UM_SPINLOCK_H
+#define __UM_SPINLOCK_H
+
+#include "linux/config.h"
+
+#ifdef CONFIG_SMP
+#include "asm/arch/spinlock.h"
+#endif
+
+#endif
diff -Nru a/include/asm-um/stat.h b/include/asm-um/stat.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/stat.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_STAT_H
+#define __UM_STAT_H
+
+#include "asm/arch/stat.h"
+
+#endif
diff -Nru a/include/asm-um/statfs.h b/include/asm-um/statfs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/statfs.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef _UM_STATFS_H
+#define _UM_STATFS_H
+
+#include "asm/arch/statfs.h"
+
+#endif
diff -Nru a/include/asm-um/string.h b/include/asm-um/string.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/string.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,7 @@
+#ifndef __UM_STRING_H
+#define __UM_STRING_H
+
+#include "asm/arch/string.h"
+#include "asm/archparam.h"
+
+#endif
diff -Nru a/include/asm-um/suspend.h b/include/asm-um/suspend.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/suspend.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,4 @@
+#ifndef __UM_SUSPEND_H
+#define __UM_SUSPEND_H
+
+#endif
diff -Nru a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/system-generic.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,41 @@
+#ifndef __UM_SYSTEM_GENERIC_H
+#define __UM_SYSTEM_GENERIC_H
+
+#include "asm/arch/system.h"
+
+#undef switch_to
+#undef local_irq_save
+#undef local_irq_restore
+#undef local_irq_disable
+#undef local_irq_enable
+#undef local_save_flags
+#undef local_irq_restore
+#undef local_irq_enable
+#undef local_irq_disable
+#undef local_irq_save
+#undef irqs_disabled
+
+extern void *switch_to(void *prev, void *next, void *last);
+
+extern int set_signals(int enable);
+extern void block_signals(void);
+extern void unblock_signals(void);
+extern int get_signals(void);
+
+#define local_save_flags(flags) do { (flags) = get_signals(); } while(0)
+#define local_irq_restore(flags) do { set_signals(flags); } while(0)
+
+#define local_irq_save(flags) do { local_save_flags(flags); \
+                                   local_irq_disable(); } while(0)
+
+#define local_irq_enable() unblock_signals()
+#define local_irq_disable() block_signals()
+
+#define irqs_disabled()			\
+({					\
+	unsigned long flags;		\
+	local_save_flags(flags);	\
+	(flags != 0);			\
+})
+
+#endif
diff -Nru a/include/asm-um/system-i386.h b/include/asm-um/system-i386.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/system-i386.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_SYSTEM_I386_H
+#define __UM_SYSTEM_I386_H
+
+#include "asm/system-generic.h"
+
+#endif
diff -Nru a/include/asm-um/system-ppc.h b/include/asm-um/system-ppc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/system-ppc.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,12 @@
+#ifndef __UM_SYSTEM_PPC_H
+#define __UM_SYSTEM_PPC_H
+
+#define _switch_to _ppc_switch_to
+
+#include "asm/arch/system.h"
+
+#undef _switch_to
+ 
+#include "asm/system-generic.h"
+
+#endif
diff -Nru a/include/asm-um/termbits.h b/include/asm-um/termbits.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/termbits.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TERMBITS_H
+#define __UM_TERMBITS_H
+
+#include "asm/arch/termbits.h"
+
+#endif
diff -Nru a/include/asm-um/termios.h b/include/asm-um/termios.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/termios.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TERMIOS_H
+#define __UM_TERMIOS_H
+
+#include "asm/arch/termios.h"
+
+#endif
diff -Nru a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/thread_info.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,83 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_THREAD_INFO_H
+#define __UM_THREAD_INFO_H
+
+#ifndef __ASSEMBLY__
+
+#include <asm/processor.h>
+
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	unsigned long		flags;		/* low level flags */
+	__u32			cpu;		/* current CPU */
+	__s32			preempt_count;  /* 0 => preemptable, 
+						   <0 => BUG */
+	mm_segment_t		addr_limit;	/* thread address space:
+					 	   0-0xBFFFFFFF for user
+						   0-0xFFFFFFFF for kernel */
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	task:		&tsk,			\
+	exec_domain:	&default_exec_domain,	\
+	flags:		0,			\
+	cpu:		0,			\
+	preempt_count:	1,			\
+	addr_limit:	KERNEL_DS,		\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+	struct thread_info *ti;
+	__asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL));
+	return ti;
+}
+
+/* thread information allocation */
+#define THREAD_SIZE (4*PAGE_SIZE)
+#define alloc_thread_info() ((struct thread_info *) \
+	__get_free_pages(GFP_KERNEL,2))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 2)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#endif
+
+#define PREEMPT_ACTIVE		0x4000000
+
+#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_SIGPENDING		1	/* signal pending */
+#define TIF_NEED_RESCHED	2	/* rescheduling necessary */
+
+#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/timex.h b/include/asm-um/timex.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/timex.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,15 @@
+#ifndef __UM_TIMEX_H
+#define __UM_TIMEX_H
+
+#include "linux/time.h"
+
+typedef unsigned long cycles_t;
+
+#define cacheflush_time (0)
+
+static inline cycles_t get_cycles (void)
+{
+	return 0;
+}
+
+#endif
diff -Nru a/include/asm-um/tlb.h b/include/asm-um/tlb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/tlb.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TLB_H
+#define __UM_TLB_H
+
+#include <asm/arch/tlb.h>
+
+#endif
diff -Nru a/include/asm-um/tlbflush.h b/include/asm-um/tlbflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/tlbflush.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,47 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_TLBFLUSH_H
+#define __UM_TLBFLUSH_H
+
+#include <linux/mm.h>
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_kernel_vm() flushes the kernel vm area
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
+			    unsigned long end);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_kernel_vm(void);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/types.h b/include/asm-um/types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/types.h	Sun Sep 15 19:20:24 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_TYPES_H
+#define __UM_TYPES_H
+
+#include "asm/arch/types.h"
+
+#endif
diff -Nru a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/uaccess.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,193 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_UACCESS_H
+#define __UM_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not.  If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+#define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
+#define USER_DS		MAKE_MM_SEG(TASK_SIZE)
+
+#define get_ds()	(KERNEL_DS)
+#define get_fs()	(current_thread_info()->addr_limit)
+#define set_fs(x)	(current_thread_info()->addr_limit = (x))
+
+extern unsigned long end_vm;
+extern unsigned long uml_physmem;
+
+#define under_task_size(addr, size) \
+	(((unsigned long) (addr) < TASK_SIZE) && \
+         (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define is_stack(addr, size) \
+	(((unsigned long) (addr) < STACK_TOP) && \
+	 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
+	 (((unsigned long) (addr) + (size)) <= STACK_TOP))
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#define access_ok(type, addr, size) \
+	((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
+         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
+          (under_task_size(addr, size) || is_stack(addr, size))))
+
+static inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return(access_ok(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern unsigned long get_fault_addr(void);
+
+extern int __do_copy_from_user(void *to, const void *from, int n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int copy_from_user(void *to, const void *from, int n)
+{
+	return(access_ok(VERIFY_READ, from, n) ?
+	       __do_copy_from_user(to, from, n, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher) : n);
+}
+
+#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
+
+extern int __do_copy_to_user(void *to, const void *from, int n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int copy_to_user(void *to, const void *from, int n)
+{
+	return(access_ok(VERIFY_WRITE, to, n) ?
+	       __do_copy_to_user(to, from, n, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher) : n);
+}
+
+#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
+
+#define __get_user(x, ptr) \
+({ \
+        const __typeof__(ptr) __private_ptr = ptr; \
+        __typeof__(*(__private_ptr)) __private_val; \
+        int __private_ret = -EFAULT; \
+        (x) = 0; \
+	if (__copy_from_user(&__private_val, (__private_ptr), \
+	    sizeof(*(__private_ptr))) == 0) {\
+        	(x) = (__typeof__(*(__private_ptr))) __private_val; \
+		__private_ret = 0; \
+	} \
+        __private_ret; \
+}) 
+
+#define get_user(x, ptr) \
+({ \
+        const __typeof__((*ptr)) *private_ptr = (ptr); \
+        (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
+	 __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \
+})
+
+#define __put_user(x, ptr) \
+({ \
+        __typeof__(ptr) __private_ptr = ptr; \
+        __typeof__(*(__private_ptr)) __private_val; \
+        int __private_ret = -EFAULT; \
+        __private_val = (__typeof__(*(__private_ptr))) (x); \
+        if (__copy_to_user((__private_ptr), &__private_val, \
+			   sizeof(*(__private_ptr))) == 0) { \
+		__private_ret = 0; \
+	} \
+        __private_ret; \
+})
+
+#define put_user(x, ptr) \
+({ \
+        __typeof__(*(ptr)) *private_ptr = (ptr); \
+        (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \
+	 __put_user(x, private_ptr) : -EFAULT); \
+})
+
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+				  void **fault_addr, void **fault_catcher);
+
+static inline int strncpy_from_user(char *dst, const char *src, int count)
+{
+	int n;
+
+	if(!access_ok(VERIFY_READ, src, 1)) return(-EFAULT);
+	n = __do_strncpy_from_user(dst, src, count, 
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher);
+	if(n < 0) return(-EFAULT);
+	return(n);
+}
+
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+			   void **fault_catcher);
+
+static inline int __clear_user(void *mem, int len)
+{
+	return(__do_clear_user(mem, len,
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+static inline int clear_user(void *mem, int len)
+{
+	return(access_ok(VERIFY_WRITE, mem, len) ? 
+	       __do_clear_user(mem, len, 
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher) : len);
+}
+
+extern int __do_strnlen_user(const char *str, unsigned long n,
+			     void **fault_addr, void **fault_catcher);
+
+static inline int strnlen_user(void *str, int len)
+{
+	return(__do_strnlen_user(str, len,
+				 &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+
+struct exception_table_entry
+{
+        unsigned long insn;
+	unsigned long fixup;
+};
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/unaligned.h b/include/asm-um/unaligned.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/unaligned.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_UNALIGNED_H
+#define __UM_UNALIGNED_H
+
+#include "asm/arch/unaligned.h"
+
+#endif
diff -Nru a/include/asm-um/unistd.h b/include/asm-um/unistd.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/unistd.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,118 @@
+/* 
+ * Copyright (C) 2000, 2001  Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef _UM_UNISTD_H_
+#define _UM_UNISTD_H_
+
+#include "linux/resource.h"
+#include "asm/uaccess.h"
+
+extern long sys_open(const char *filename, int flags, int mode);
+extern long sys_dup(unsigned int fildes);
+extern long sys_close(unsigned int fd);
+extern int um_execve(const char *file, char *const argv[], char *const env[]);
+extern long sys_setsid(void);
+extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options);
+extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, 
+		      struct rusage *ru);
+extern long sys_mount(char *dev_name, char *dir_name, char *type, 
+		      unsigned long flags, void *data);
+extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, 
+		       struct timeval *tvp);
+extern long sys_lseek(unsigned int fildes, unsigned long offset, int whence);
+extern long sys_read(unsigned int fildes, char *buf, int len);
+extern long sys_write(unsigned int fildes, char *buf, int len);
+
+#ifdef __KERNEL_SYSCALLS__
+
+#define KERNEL_CALL(ret_t, sys, args...)	\
+	mm_segment_t fs = get_fs();		\
+	ret_t ret;				\
+	set_fs(KERNEL_DS);			\
+	ret = sys(args);			\
+	set_fs(fs);				\
+	return ret;
+
+static inline long open(const char *pathname, int flags, int mode) 
+{
+	KERNEL_CALL(int, sys_open, pathname, flags, mode)
+}
+
+static inline long dup(unsigned int fd)
+{
+	KERNEL_CALL(int, sys_dup, fd);
+}
+
+static inline long close(unsigned int fd)
+{
+	KERNEL_CALL(int, sys_close, fd);
+}
+
+static inline int execve(const char *filename, char *const argv[], 
+			 char *const envp[])
+{
+	KERNEL_CALL(int, um_execve, filename, argv, envp);
+}
+
+static inline long waitpid(pid_t pid, unsigned int *status, int options)
+{
+	KERNEL_CALL(pid_t, sys_wait4, pid, status, options, NULL)
+}
+
+static inline pid_t wait(int *status)
+{
+	KERNEL_CALL(pid_t, sys_wait4, -1, status, 0, NULL)
+}
+
+static inline pid_t setsid(void)
+{
+	KERNEL_CALL(pid_t, sys_setsid)
+}
+
+static inline long lseek(unsigned int fd, off_t offset, unsigned int whence)
+{
+	KERNEL_CALL(long, sys_lseek, fd, offset, whence)
+}
+
+static inline int read(unsigned int fd, char * buf, int len)
+{
+	KERNEL_CALL(int, sys_read, fd, buf, len)
+}
+
+static inline int write(unsigned int fd, char * buf, int len)
+{
+	KERNEL_CALL(int, sys_write, fd, buf, len)
+}
+
+#endif
+
+/* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying
+ * arch's unistd.h for the system call numbers, and restore the old 
+ * __KERNEL_SYSCALLS__.
+ */
+
+#ifdef __KERNEL_SYSCALLS__
+#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__
+#endif
+
+#undef __KERNEL_SYSCALLS__
+#include "asm/arch/unistd.h"
+
+#ifdef __KERNEL_SYSCALLS__
+#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__
+#endif
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/include/asm-um/user.h b/include/asm-um/user.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/user.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_USER_H
+#define __UM_USER_H
+
+#include "asm/arch/user.h"
+
+#endif
diff -Nru a/include/asm-um/vga.h b/include/asm-um/vga.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/vga.h	Sun Sep 15 19:20:25 2002
@@ -0,0 +1,6 @@
+#ifndef __UM_VGA_H
+#define __UM_VGA_H
+
+#include "asm/arch/vga.h"
+
+#endif
diff -Nru a/include/asm-x86_64/hdreg.h b/include/asm-x86_64/hdreg.h
--- a/include/asm-x86_64/hdreg.h	Sun Sep 15 19:19:28 2002
+++ b/include/asm-x86_64/hdreg.h	Sun Sep 15 19:19:28 2002
@@ -7,6 +7,6 @@
 #ifndef __ASMx86_64_HDREG_H
 #define __ASMx86_64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMx86_64_HDREG_H */
diff -Nru a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h
--- a/include/asm-x86_64/ide.h	Sun Sep 15 19:19:46 2002
+++ b/include/asm-x86_64/ide.h	Sun Sep 15 19:19:46 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/include/asm-i386/ide.h
+ *  linux/include/asm-x86_64/ide.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
@@ -8,8 +8,8 @@
  *  This file contains the i386 architecture specific IDE code.
  */
 
-#ifndef __ASMi386_IDE_H
-#define __ASMi386_IDE_H
+#ifndef __ASMx86_64_IDE_H
+#define __ASMx86_64_IDE_H
 
 #ifdef __KERNEL__
 
@@ -79,4 +79,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* __ASMi386_IDE_H */
+#endif /* __ASMx86_64_IDE_H */
diff -Nru a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
--- a/include/asm-x86_64/pgtable.h	Sun Sep 15 19:19:29 2002
+++ b/include/asm-x86_64/pgtable.h	Sun Sep 15 19:19:29 2002
@@ -336,6 +336,8 @@
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
 
+typedef pte_t *pte_addr_t;
+
 #endif /* !__ASSEMBLY__ */
 
 #define kern_addr_valid(addr)	(1)
diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h
--- a/include/linux/acpi.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/acpi.h	Sun Sep 15 19:19:28 2002
@@ -354,11 +354,11 @@
 
 extern int acpi_mp_config;
 
-#else /*!CONFIG_ACPI_BOOT*/
+#else
 
 #define acpi_mp_config	0
 
-#endif /*CONFIG_ACPI_BOOT*/
+#endif
 
 
 #ifdef CONFIG_ACPI_PCI
diff -Nru a/include/linux/aio.h b/include/linux/aio.h
--- a/include/linux/aio.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/aio.h	Sun Sep 15 19:19:28 2002
@@ -1,7 +1,6 @@
 #ifndef __LINUX__AIO_H
 #define __LINUX__AIO_H
 
-#include <linux/tqueue.h>
 #include <linux/list.h>
 #include <asm/atomic.h>
 
@@ -21,10 +20,14 @@
 #define KIOCB_C_CANCELLED	0x01
 #define KIOCB_C_COMPLETE	0x02
 
+#define KIOCB_SYNC_KEY		(~0U)
+
 #define KIOCB_PRIVATE_SIZE	(16 * sizeof(long))
 
 struct kiocb {
 	int			ki_users;
+	unsigned		ki_key;		/* id of this request */
+
 	struct file		*ki_filp;
 	struct kioctx		*ki_ctx;	/* may be NULL for sync ops */
 	int			(*ki_cancel)(struct kiocb *, struct io_event *);
@@ -34,17 +37,19 @@
 	void			*ki_data;	/* for use by the the file */
 	void			*ki_user_obj;	/* pointer to userland's iocb */
 	__u64			ki_user_data;	/* user's data for completion */
-	unsigned		ki_key;		/* id of this request */
 
 	long			private[KIOCB_PRIVATE_SIZE/sizeof(long)];
 };
 
-#define init_sync_kiocb(x, filp)	\
-	do {				\
-		(x)->ki_users = 1;	\
-		(x)->ki_filp = (filp);	\
-		(x)->ki_ctx = 0;	\
-		(x)->ki_cancel = NULL;	\
+#define init_sync_kiocb(x, filp)			\
+	do {						\
+		struct task_struct *tsk = current;	\
+		(x)->ki_users = 1;			\
+		(x)->ki_key = KIOCB_SYNC_KEY;		\
+		(x)->ki_filp = (filp);			\
+		(x)->ki_ctx = &tsk->active_mm->default_kioctx;	\
+		(x)->ki_cancel = NULL;			\
+		(x)->ki_user_obj = tsk;			\
 	} while (0)
 
 #define AIO_RING_MAGIC			0xa10a10a1
@@ -105,6 +110,7 @@
 /* prototypes */
 extern unsigned aio_max_size;
 
+extern ssize_t FASTCALL(wait_on_sync_kiocb(struct kiocb *iocb));
 extern int FASTCALL(aio_put_req(struct kiocb *iocb));
 extern int FASTCALL(aio_complete(struct kiocb *iocb, long res, long res2));
 extern void FASTCALL(__put_ioctx(struct kioctx *ctx));
diff -Nru a/include/linux/atari_rootsec.h b/include/linux/atari_rootsec.h
--- a/include/linux/atari_rootsec.h	Sun Sep 15 19:20:10 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-#ifndef _LINUX_ATARI_ROOTSEC_H
-#define _LINUX_ATARI_ROOTSEC_H
-
-/*
- * linux/include/linux/atari_rootsec.h
- * definitions for Atari Rootsector layout
- * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
- *
- * modified for ICD/Supra partitioning scheme restricted to at most 12
- * partitions
- * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
- */
-
-struct partition_info
-{
-  u_char flg;			/* bit 0: active; bit 7: bootable */
-  char id[3];			/* "GEM", "BGM", "XGM", or other */
-  u32 st;			/* start of partition */
-  u32 siz;			/* length of partition */
-};
-
-struct rootsector
-{
-  char unused[0x156];			/* room for boot code */
-  struct partition_info icdpart[8];	/* info for ICD-partitions 5..12 */
-  char unused2[0xc];
-  u32 hd_siz;				/* size of disk in blocks */
-  struct partition_info part[4];
-  u32 bsl_st;				/* start of bad sector list */
-  u32 bsl_cnt;				/* length of bad sector list */
-  u16 checksum;				/* checksum for bootable disks */
-} __attribute__ ((__packed__));
-
-#endif /* _LINUX_ATARI_ROOTSEC_H */
diff -Nru a/include/linux/backing-dev.h b/include/linux/backing-dev.h
--- a/include/linux/backing-dev.h	Sun Sep 15 19:19:30 2002
+++ b/include/linux/backing-dev.h	Sun Sep 15 19:19:30 2002
@@ -19,6 +19,7 @@
 struct backing_dev_info {
 	unsigned long ra_pages;	/* max readahead in PAGE_CACHE_SIZE units */
 	unsigned long state;	/* Always use atomic bitops on this */
+	int memory_backed;	/* Cannot clean pages with writepage */
 };
 
 extern struct backing_dev_info default_backing_dev_info;
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Sun Sep 15 19:20:18 2002
+++ b/include/linux/bio.h	Sun Sep 15 19:20:18 2002
@@ -215,17 +215,11 @@
 {
 	unsigned long addr;
 
-	local_save_flags(*flags);
-
-	/*
-	 * could be low
-	 */
-	if (!PageHighMem(bio_page(bio)))
-		return bio_data(bio);
-
 	/*
-	 * it's a highmem page
+	 * might not be a highmem page, but the preempt/irq count
+	 * balancing is a lot nicer this way
 	 */
+	local_save_flags(*flags);
 	local_irq_disable();
 	addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ);
 
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/blkdev.h	Sun Sep 15 19:19:29 2002
@@ -219,6 +219,7 @@
 #define blk_queue_plugged(q)	!list_empty(&(q)->plug_list)
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
 #define blk_queue_empty(q)	elv_queue_empty(q)
+#define blk_fs_request(rq)	((rq)->flags & REQ_CMD)
 #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
 
 #define rq_data_dir(rq)		((rq)->flags & 1)
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/buffer_head.h	Sun Sep 15 19:19:28 2002
@@ -167,6 +167,7 @@
 struct buffer_head *alloc_buffer_head(void);
 void free_buffer_head(struct buffer_head * bh);
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
+extern int buffer_heads_over_limit;
 
 /*
  * Generic address_space_operations implementations for buffer_head-backed
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/fs.h	Sun Sep 15 19:19:29 2002
@@ -307,8 +307,7 @@
 	int (*bmap)(struct address_space *, long);
 	int (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
-	int (*direct_IO)(int, struct inode *, char *buf,
-				loff_t offset, size_t count);
+	int (*direct_IO)(int, struct inode *, const struct iovec *iov, loff_t offset, unsigned long nr_segs);
 };
 
 struct backing_dev_info;
@@ -526,10 +525,10 @@
 
 #define FL_POSIX	1
 #define FL_FLOCK	2
-#define FL_BROKEN	4	/* broken flock() emulation */
-#define FL_ACCESS	8	/* for processes suspended by mandatory locking */
+#define FL_ACCESS	8	/* not trying to lock, just looking */
 #define FL_LOCKD	16	/* lock held by rpc.lockd */
 #define FL_LEASE	32	/* lease held on this file */
+#define FL_SLEEP	128	/* A blocking lock */
 
 /*
  * The POSIX file lock owner is determined by
@@ -591,9 +590,9 @@
 extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
 extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
+extern int posix_lock_file(struct file *, struct file_lock *);
 extern void posix_block_lock(struct file_lock *, struct file_lock *);
-extern void posix_unblock_lock(struct file_lock *);
+extern void posix_unblock_lock(struct file *, struct file_lock *);
 extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
 extern int __get_lease(struct inode *inode, unsigned int flags);
 extern time_t lease_get_mtime(struct inode *);
@@ -660,7 +659,6 @@
 
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
-	struct list_head	s_locked_inodes;/* inodes being synced */
 	struct list_head	s_anon;		/* anonymous dentries for (nfs) exporting */
 	struct list_head	s_files;
 
@@ -1246,14 +1244,18 @@
 extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
-extern ssize_t generic_file_write_nolock(struct file *, const char *, size_t, loff_t *);
+ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
+				unsigned long nr_segs, loff_t *ppos);
 extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
-ssize_t generic_file_direct_IO(int rw, struct inode *inode, char *buf,
-				loff_t offset, size_t count);
-int generic_direct_IO(int rw, struct inode *inode, char *buf,
-			loff_t offset, size_t count, get_blocks_t *get_blocks);
-
+extern ssize_t generic_file_direct_IO(int rw, struct inode *inode, 
+	const struct iovec *iov, loff_t offset, unsigned long nr_segs);
+extern int generic_direct_IO(int rw, struct inode *inode, const struct iovec 
+	*iov, loff_t offset, unsigned long nr_segs, get_blocks_t *get_blocks);
+extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov, 
+	unsigned long nr_segs, loff_t *ppos);
+ssize_t generic_file_writev(struct file *filp, const struct iovec *iov, 
+			unsigned long nr_segs, loff_t *ppos);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Sun Sep 15 19:19:37 2002
+++ b/include/linux/hdreg.h	Sun Sep 15 19:19:37 2002
@@ -32,7 +32,7 @@
 #define ECC_STAT		0x04	/* Corrected error */
 #define DRQ_STAT		0x08
 #define SEEK_STAT		0x10
-#define SERVICE_STAT		SEEK_STAT
+#define SRV_STAT		0x10
 #define WRERR_STAT		0x20
 #define READY_STAT		0x40
 #define BUSY_STAT		0x80
@@ -48,6 +48,13 @@
 #define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
 #define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
 
+/* Bits of HD_NSECTOR */
+#define CD			0x01
+#define IO			0x02
+#define REL			0x04
+#define TAG_MASK		0xf8
+
+
 /*
  * Command Header sizes for IOCTL commands
  */
@@ -70,10 +77,11 @@
  */
 #define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
 #define IDE_TASKFILE_STD_IN_FLAGS	0xFE
-#define IDE_HOB_STD_OUT_FLAGS		0x3C     /* sector, nsector lcyl and hcyl */
+#define IDE_HOB_STD_OUT_FLAGS		0x3C
 #define IDE_HOB_STD_IN_FLAGS		0x3C
 
 typedef unsigned char task_ioreg_t;
+typedef unsigned long sata_ioreg_t;
 
 typedef union ide_reg_valid_s {
 	unsigned all				: 16;
@@ -170,38 +178,83 @@
 
 /* ATA/ATAPI Commands pre T13 Spec */
 #define WIN_NOP				0x00
+/*
+ *	0x01->0x02 Reserved
+ */
 #define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+/*
+ *	0x04->0x07 Reserved
+ */
 #define WIN_SRST			0x08 /* ATAPI soft reset command */
 #define WIN_DEVICE_RESET		0x08
+/*
+ *	0x09->0x0F Reserved
+ */
 #define WIN_RECAL			0x10
-#define WIN_RESTORE			0x10
+#define WIN_RESTORE			WIN_RECAL
+/*
+ *	0x10->0x1F Reserved
+ */
 #define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
+#define WIN_READ_LONG			0x22 /* 28-Bit */
+#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
 #define WIN_READ_EXT			0x24 /* 48-Bit */
 #define WIN_READDMA_EXT			0x25 /* 48-Bit */
 #define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
 #define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+/*
+ *	0x28
+ */
 #define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+/*
+ *	0x2A->0x2F Reserved
+ */
 #define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
+#define WIN_WRITE_LONG			0x32 /* 28-Bit */
+#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
 #define WIN_WRITE_EXT			0x34 /* 48-Bit */
 #define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
 #define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
 #define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
 #define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
 #define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+/*
+ *	0x3A->0x3B Reserved
+ */
 #define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+/*
+ *	0x3D->0x3F Reserved
+ */
 #define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
 #define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+/*
+ *	0x43->0x4F Reserved
+ */
 #define WIN_FORMAT			0x50
+/*
+ *	0x51->0x5F Reserved
+ */
 #define WIN_INIT			0x60
-#define WIN_SEEK			0x70
+/*
+ *	0x61->0x5F Reserved
+ */
+#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
+
 #define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
 #define WIN_DIAGNOSE			0x90
 #define WIN_SPECIFY			0x91 /* set drive geometry translation */
 #define WIN_DOWNLOAD_MICROCODE		0x92
 #define WIN_STANDBYNOW2			0x94
+#define WIN_STANDBY2			0x96
 #define WIN_SETIDLE2			0x97
 #define WIN_CHECKPOWERMODE2		0x98
 #define WIN_SLEEPNOW2			0x99
+/*
+ *	0x9A VENDOR
+ */
 #define WIN_PACKETCMD			0xA0 /* Send a packet command. */
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
 #define WIN_QUEUED_SERVICE		0xA2
@@ -212,10 +265,15 @@
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
 #define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
 #define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
 #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
 #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
 #define WIN_GETMEDIASTATUS		0xDA
+#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
+#define WIN_POSTBOOT			0xDC
+#define WIN_PREBOOT 			0xDD
 #define WIN_DOORLOCK			0xDE /* lock door on removable drives */
 #define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
 #define WIN_STANDBYNOW1			0xE0
@@ -227,6 +285,8 @@
 #define WIN_SLEEPNOW1			0xE6
 #define WIN_FLUSH_CACHE			0xE7
 #define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
+	/* SET_FEATURES 0x22 or 0xDD */
 #define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
 #define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
 #define WIN_MEDIAEJECT			0xED
@@ -289,6 +349,7 @@
 #	define XFER_PIO_SLOW	0x00	/* 0000|0000 */
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
+#define SETFEATURES_EN_SAME_R	0x22	/* for a region ATA-1 */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
 #define SETFEATURES_DIS_RETRY	0x33	/* Disable Retry */
 #define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
@@ -308,11 +369,13 @@
 #define SETFEATURES_EN_RETRY	0x99	/* Enable Retry */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_EN_REST	0xAC	/* ATA-1 */
 #define SETFEATURES_4B_RW_LONG	0xBB	/* Set Lenght of 4 bytes */
 #define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
-#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
-#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
+#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt ATAPI */
+#define SETFEATURES_EN_SAME_M	0xDD	/* for a entire device ATA-1 */
+#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt ATAPI */
 
 /* WIN_SECURITY sub-commands */
 
@@ -343,6 +406,9 @@
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x0304	/* get current IDE blockmode setting */
 #define HDIO_GET_QDMA		0x0305	/* get use-qdma flag */
+
+#define HDIO_SET_XFER		0x0306  /* set transfer rate via proc */
+
 #define HDIO_OBSOLETE_IDENTITY	0x0307	/* OBSOLETE, DO NOT USE: returns 142 bytes */
 #define HDIO_GET_KEEPSETTINGS	0x0308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_32BIT		0x0309	/* get current io_32bit setting */
@@ -390,6 +456,9 @@
 /* 0x330 is reserved - used to be HDIO_GETGEO_BIG */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
+#define HDIO_SET_IDE_SCSI      0x0338
+#define HDIO_SET_SCSI_IDE      0x0339
+
 #define __NEW_HD_DRIVE_ID
 
 /*
@@ -506,7 +575,10 @@
 					 * cmd set-feature supported extensions
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging
+					 *  4:	Streaming Feature Set
+					 *  3:	Media Card Pass Through
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
@@ -553,19 +625,22 @@
 					 * command set-feature default
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging enabled
+					 *  4:	Valid CONFIGURE STREAM executed
+					 *  3:	Media Card Pass Through enabled
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
 					 */
 	unsigned short  dma_ultra;	/* (word 88) */
-	unsigned short	word89;		/* reserved (word 89) */
-	unsigned short	word90;		/* reserved (word 90) */
+	unsigned short	trseuc;		/* time required for security erase */
+	unsigned short	trsEuc;		/* time required for enhanced erase */
 	unsigned short	CurAPMvalues;	/* current APM values */
-	unsigned short	word92;		/* reserved (word 92) */
+	unsigned short	mprc;		/* master password revision code */
 	unsigned short	hw_config;	/* hardware config (word 93)
-					 * 15:
-					 * 14:
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
 					 * 13:
 					 * 12:
 					 * 11:
@@ -579,13 +654,16 @@
 					 *  3:
 					 *  2:
 					 *  1:
-					 *  0:
+					 *  0:	Shall be ONE
 					 */
 	unsigned short	acoustic;	/* (word 94)
 					 * 15:8	Vendor's recommended value
 					 *  7:0	current value
 					 */
-	unsigned short	words95_99[5];	/* reserved words 95-99 */
+	unsigned short	msrqs;		/* min stream request size */
+	unsigned short	sxfert;		/* stream transfer time */
+	unsigned short	sal;		/* stream access latency */
+	unsigned int	spg;		/* stream performance granularity */
 	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
 	unsigned short	words104_125[22];/* reserved words 104-125 */
 	unsigned short	last_lun;	/* (word 126) */
@@ -634,7 +712,7 @@
 					 * 15:8 Checksum
 					 *  7:0 Signature
 					 */
-} __attribute__((packed));
+};
 
 /*
  * IDE "nice" flags. These are used on a per drive basis to determine
diff -Nru a/include/linux/highmem.h b/include/linux/highmem.h
--- a/include/linux/highmem.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/highmem.h	Sun Sep 15 19:19:29 2002
@@ -26,6 +26,7 @@
 
 #define kmap_atomic(page, idx)		page_address(page)
 #define kunmap_atomic(addr, idx)	do { } while (0)
+#define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
 
 #endif /* CONFIG_HIGHMEM */
 
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Sun Sep 15 19:19:34 2002
+++ b/include/linux/ide.h	Sun Sep 15 19:19:34 2002
@@ -3,7 +3,7 @@
 /*
  *  linux/include/linux/ide.h
  *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors
+ *  Copyright (C) 1994-2002  Linus Torvalds & authors
  */
 
 #include <linux/config.h>
@@ -14,18 +14,14 @@
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
 #include <linux/bio.h>
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/hdreg.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-#  define __IDEDMA_TIMEOUT
-#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-#  undef __IDEDMA_TIMEOUT
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-
 /*
  * 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).
@@ -42,7 +38,7 @@
  *
  * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
  */
-#undef REALLY_FAST_IO			/* define if ide ports are perfect */
+#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 SUPPORT_SLOW_DATA_PORTS		/* 1 to support slow data ports */
@@ -170,9 +166,6 @@
 #define IDE_BCOUNTL_REG		IDE_LCYL_REG
 #define IDE_BCOUNTH_REG		IDE_HCYL_REG
 
-#define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
-#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
-#define GET_ALTSTAT()		IN_BYTE(IDE_CONTROL_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)
@@ -180,6 +173,43 @@
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
 #define DATA_READY		(DRQ_STAT)
 
+#define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
+
+#define SATA_NR_PORTS		(3)	/* 16 possible ?? */
+
+#define SATA_STATUS_OFFSET	(0)
+#define SATA_STATUS_REG		(HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
+#define SATA_ERROR_OFFSET	(1)
+#define SATA_ERROR_REG		(HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
+#define SATA_CONTROL_OFFSET	(2)
+#define SATA_CONTROL_REG	(HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
+
+#define SATA_MISC_OFFSET	(0)
+#define SATA_MISC_REG		(HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
+#define SATA_PHY_OFFSET		(1)
+#define SATA_PHY_REG		(HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
+#define SATA_IEN_OFFSET		(2)
+#define SATA_IEN_REG		(HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
+
+/*
+ * Our Physical Region Descriptor (PRD) table should be large enough
+ * to handle the biggest I/O request we are likely to see.  Since requests
+ * can have no more than 256 sectors, and since the typical blocksize is
+ * two or more sectors, we could get by with a limit of 128 entries here for
+ * the usual worst case.  Most requests seem to include some contiguous blocks,
+ * further reducing the number of table entries required.
+ *
+ * The driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ *
+ * As it turns out though, we must allocate a full 4KB page for this,
+ * so the two PRD tables (ide0 & ide1) will each get half of that,
+ * allowing each to have about 256 entries (8 bytes each) from this.
+ */
+#define PRD_BYTES       8
+#define PRD_ENTRIES     (PAGE_SIZE / (2 * PRD_BYTES))
+
 /*
  * sector count bits
  */
@@ -215,21 +245,12 @@
 #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 CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
 #define SECTOR_SIZE	512
 #define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
-#ifndef SPLIT_WORD
-#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
-#endif
-#ifndef MAKE_WORD
-#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
-#endif
-
-
 /*
  * Timeouts for various operations:
  */
@@ -244,39 +265,6 @@
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
-#define SELECT_DRIVE(hwif,drive)				\
-{								\
-	if (hwif->selectproc)					\
-		hwif->selectproc(drive);			\
-	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
-}
-
-#define SELECT_INTERRUPT(hwif,drive)				\
-{								\
-	if (hwif->intrproc)					\
-		hwif->intrproc(drive);				\
-	else							\
-		OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);	\
-}
-
-#define SELECT_MASK(hwif,drive,mask)				\
-{								\
-	if (hwif->maskproc)					\
-		hwif->maskproc(drive,mask);			\
-}
-
-#define SELECT_READ_WRITE(hwif,drive,func)			\
-{								\
-	if (hwif->rwproc)					\
-		hwif->rwproc(drive,func);			\
-}
-
-#define QUIRK_LIST(hwif,drive)					\
-{								\
-	if (hwif->quirkproc)					\
-		(drive)->quirk_list = hwif->quirkproc(drive);	\
-}
-
 #define HOST(hwif,chipset)					\
 {								\
 	return ((hwif)->chipset == chipset) ? 1 : 0;		\
@@ -304,9 +292,34 @@
 		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives,
-		ide_pmac,	ide_etrax100
+		ide_pmac,	ide_etrax100,	ide_acorn
 } hwif_chipset_t;
 
+typedef struct ide_io_ops_s {
+	/* insert io operations here! */
+	void (*OUTB)(u8 addr, u32 port);
+	void (*OUTW)(u16 addr, u32 port);
+	void (*OUTL)(u32 addr, u32 port);
+	void (*OUTBP)(u8 addr, u32 port);
+	void (*OUTWP)(u16 addr, u32 port);
+	void (*OUTLP)(u32 addr, u32 port);
+	void (*OUTSW)(u32 port, void *addr, u32 count);
+	void (*OUTSWP)(u32 port, void *addr, u32 count);
+	void (*OUTSL)(u32 port, void *addr, u32 count);
+	void (*OUTSLP)(u32 port, void *addr, u32 count);
+
+	u8  (*INB)(u32 port);
+	u16 (*INW)(u32 port);
+	u32 (*INL)(u32 port);
+	u8  (*INBP)(u32 port);
+	u16 (*INWP)(u32 port);
+	u32 (*INLP)(u32 port);
+	void (*INSW)(u32 port, void *addr, u32 count);
+	void (*INSWP)(u32 port, void *addr, u32 count);
+	void (*INSL)(u32 port, void *addr, u32 count);
+	void (*INSLP)(u32 port, void *addr, u32 count);
+} ide_io_ops_t;
+
 /*
  * Structure to hold all information about the location of this port
  */
@@ -317,6 +330,11 @@
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
 	void		*priv;			/* interface specific data */
 	hwif_chipset_t  chipset;
+#if 0
+	ide_io_ops_t	*iops;			/* */
+#endif
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
 } hw_regs_t;
 
 /*
@@ -333,10 +351,27 @@
 			ide_ioreg_t ctrl,
 			ide_ioreg_t intr,
 			ide_ack_intr_t *ack_intr,
+#if 0
+			ide_io_ops_t *iops,
+#endif
 			int irq);
 
 #include <asm/ide.h>
 
+/* Currently only m68k, apus and m8xx need it */
+#ifdef IDE_ARCH_ACK_INTR
+extern int ide_irq_lock;
+# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
+#else
+# define ide_ack_intr(hwif) (1)
+#endif
+
+/* Currently only Atari needs it */
+#ifndef IDE_ARCH_LOCK
+# define ide_release_lock(lock)			do {} while (0)
+# define ide_get_lock(lock, hdlr, data)		do {} while (0)
+#endif /* IDE_ARCH_LOCK */
+
 /*
  * If the arch-dependant ide.h did not declare/define any OUT_BYTE
  * or IN_BYTE functions, we make some defaults here.
@@ -346,20 +381,30 @@
 # ifdef REALLY_FAST_IO
 #  define OUT_BYTE(b,p)		outb((b),(p))
 #  define OUT_WORD(w,p)		outw((w),(p))
+#  define OUT_LONG(l,p)		outl((l),(p))
 # else
 #  define OUT_BYTE(b,p)		outb_p((b),(p))
 #  define OUT_WORD(w,p)		outw_p((w),(p))
+#  define OUT_LONG(l,p)		outl_p((l),(p))
 # endif
+# define OUT_BYTE_P(b,p)	outb_p((b),(p))
+# define OUT_WORD_P(w,p)	outw_p((w),(p))
+# define OUT_LONG_P(l,p)	outl_p((l),(p))
 #endif
 
 #ifndef HAVE_ARCH_IN_BYTE
 # ifdef REALLY_FAST_IO
-#  define IN_BYTE(p)		(byte)inb(p)
-#  define IN_WORD(p)		(short)inw(p)
+#  define IN_BYTE(p)		(u8) inb(p)
+#  define IN_WORD(p)		(u16) inw(p)
+#  define IN_LONG(p)		(u32) inl(p)
 # else
-#  define IN_BYTE(p)		(byte)inb_p(p)
-#  define IN_WORD(p)		(short)inw_p(p)
+#  define IN_BYTE(p)		(u8) inb_p(p)
+#  define IN_WORD(p)		(u16) inw_p(p)
+#  define IN_LONG(p)		(u32) inl_p(p)
 # endif
+# define IN_BYTE_P(p)		(u8) inb_p(p)
+# define IN_WORD_P(p)		(u16) inw_p(p)
+# define IN_LONG_P(p)		(u32) inl_p(p)
 #endif
 
 /*
@@ -373,201 +418,453 @@
 #define ide_tape	0x1
 #define ide_floppy	0x0
 
+/*
+ * Special Driver Flags
+ *
+ * set_geometry	: respecify drive geometry
+ * recalibrate	: seek to cyl 0
+ * set_multmode	: set multmode count
+ * set_tune	: tune interface for drive
+ * serviced	: service command
+ * reserved	: unused
+ */
 typedef union {
-	unsigned all			: 8;	/* all of the bits together */
+	unsigned all			: 8;
 	struct {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned set_geometry	: 1;	/* respecify drive geometry */
-		unsigned recalibrate	: 1;	/* seek to cyl 0      */
-		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned set_tune	: 1;	/* tune interface for drive */
-		unsigned serviced	: 1;	/* service command */
-		unsigned reserved	: 3;	/* unused */
+		unsigned set_geometry	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_multmode	: 1;
+		unsigned set_tune	: 1;
+		unsigned serviced	: 1;
+		unsigned reserved	: 3;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	: 3;	/* unused */
-		unsigned serviced	: 1;	/* service command */
-		unsigned set_tune	: 1;	/* tune interface for drive */
-		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned recalibrate	: 1;	/* seek to cyl 0      */
-		unsigned set_geometry	: 1;	/* respecify drive geometry */
+		unsigned reserved	: 3;
+		unsigned serviced	: 1;
+		unsigned set_tune	: 1;
+		unsigned set_multmode	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_geometry	: 1;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 	} b;
 } special_t;
 
+/*
+ * ATA DATA Register Special.
+ * ATA NSECTOR Count Register().
+ * ATAPI Byte Count Register.
+ * Channel index ordering pairs.
+ */
+typedef union {
+	unsigned all			:16;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned low		:8;	/* LSB */
+		unsigned high		:8;	/* MSB */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned high		:8;	/* MSB */
+		unsigned low		:8;	/* LSB */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_nsector_t, ata_data_t, atapi_bcount_t, ata_index_t;
+
+/*
+ * ATA-IDE Error Register
+ *
+ * mark		: Bad address mark
+ * tzero	: Couldn't find track 0
+ * abrt		: Aborted Command
+ * mcr		: Media Change Request
+ * id		: ID field not found
+ * mce		: Media Change Event
+ * ecc		: Uncorrectable ECC error
+ * bdd		: dual meaing
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned mark		:1;
+		unsigned tzero		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned id		:1;
+		unsigned mce		:1;
+		unsigned ecc		:1;
+		unsigned bdd		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bdd		:1;
+		unsigned ecc		:1;
+		unsigned mce		:1;
+		unsigned id		:1;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned tzero		:1;
+		unsigned mark		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_error_t;
+
+/*
+ * ATA-IDE Select Register, aka Device-Head
+ *
+ * head		: always zeros here
+ * unit		: drive select number: 0/1
+ * bit5		: always 1
+ * lba		: using LBA instead of CHS
+ * bit7		: always 1
+ */
+typedef union {
+	unsigned all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned head		: 4;
+		unsigned unit		: 1;
+		unsigned bit5		: 1;
+		unsigned lba		: 1;
+		unsigned bit7		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bit7		: 1;
+		unsigned lba		: 1;
+		unsigned bit5		: 1;
+		unsigned unit		: 1;
+		unsigned head		: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} select_t, ata_select_t;
+
+/*
+ * The ATA-IDE Status Register.
+ * The ATAPI Status Register.
+ *
+ * check	: Error occurred
+ * idx		: Index Error
+ * corr		: Correctable error occurred
+ * drq		: Data is request by the device
+ * dsc		: Disk Seek Complete			: ata
+ *		: Media access command finished		: atapi
+ * df		: Device Fault				: ata
+ *		: Reserved				: atapi
+ * drdy		: Ready, Command Mode Capable		: ata
+ *		: Ignored for ATAPI commands		: atapi
+ * bsy		: Disk is Busy
+ *		: The device has access to the command block
+ */
 typedef union {
-	unsigned all			: 8;	/* all of the bits together */
+	unsigned all			:8;
 	struct {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number: 0/1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
+		unsigned check		:1;
+		unsigned idx		:1;
+		unsigned corr		:1;
+		unsigned drq		:1;
+		unsigned dsc		:1;
+		unsigned df		:1;
+		unsigned drdy		:1;
+		unsigned bsy		:1;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number: 0/1 */
-		unsigned head		: 4;	/* always zeros here */
+		unsigned bsy		:1;
+		unsigned drdy		:1;
+		unsigned df		:1;
+		unsigned dsc		:1;
+		unsigned drq		:1;
+		unsigned corr           :1;
+		unsigned idx		:1;
+		unsigned check		:1;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 	} b;
-} select_t;
+} ata_status_t, atapi_status_t;
 
+/*
+ * ATA-IDE Control Register
+ *
+ * bit0		: Should be set to zero
+ * nIEN		: device INTRQ to host
+ * SRST		: host soft reset bit
+ * bit3		: ATA-2 thingy, Should be set to 1
+ * reserved456	: Reserved
+ * HOB		: 48-bit address ordering, High Ordered Bit
+ */
 typedef union {
-	unsigned all			: 8;	/* all of the bits together */
+	unsigned all			: 8;
 	struct {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456    : 3;
-		unsigned HOB            : 1;	/* 48-bit address ordering */
+		unsigned nIEN		: 1;
+		unsigned SRST		: 1;
+		unsigned bit3		: 1;
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned HOB		: 1;	/* 48-bit address ordering */
+		unsigned HOB		: 1;
 		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned bit3		: 1;
+		unsigned SRST		: 1;
+		unsigned nIEN		: 1;
 		unsigned bit0		: 1;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 	} b;
-} control_t;
+} ata_control_t;
 
+/*
+ * ATAPI Feature Register
+ *
+ * dma		: Using DMA or PIO
+ * reserved321	: Reserved
+ * reserved654	: Reserved (Tag Type)
+ * reserved7	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned dma		:1;
+		unsigned reserved321	:3;
+		unsigned reserved654	:3;
+		unsigned reserved7	:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved7	:1;
+		unsigned reserved654	:3;
+		unsigned reserved321	:3;
+		unsigned dma		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_feature_t;
+
+/*
+ * ATAPI Interrupt Reason Register.
+ *
+ * cod		: Information transferred is command (1) or data (0)
+ * io		: The device requests us to read (1) or write (0)
+ * reserved	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned cod		:1;
+		unsigned io		:1;
+		unsigned reserved	:6;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	:6;
+		unsigned io		:1;
+		unsigned cod		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_ireason_t;
+
+/*
+ * The ATAPI error register.
+ *
+ * ili		: Illegal Length Indication
+ * eom		: End Of Media Detected
+ * abrt		: Aborted command - As defined by ATA
+ * mcr		: Media Change Requested - As defined by ATA
+ * sense_key	: Sense key of the last failed packet command
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned ili		:1;
+		unsigned eom		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned sense_key	:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned sense_key	:4;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned eom		:1;
+		unsigned ili		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_error_t;
+
+/*
+ * ATAPI floppy Drive Select Register
+ *
+ * sam_lun	: Logical unit number
+ * reserved3	: Reserved
+ * drv		: The responding drive will be drive 0 (0) or drive 1 (1)
+ * one5		: Should be set to 1
+ * reserved6	: Reserved
+ * one7		: Should be set to 1
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned sam_lun	:3;
+		unsigned reserved3	:1;
+		unsigned drv		:1;
+		unsigned one5		:1;
+		unsigned reserved6	:1;
+		unsigned one7		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned one7		:1;
+		unsigned reserved6	:1;
+		unsigned one5		:1;
+		unsigned drv		:1;
+		unsigned reserved3	:1;
+		unsigned sam_lun	:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_select_t;
 
 struct ide_driver_s;
 struct ide_settings_s;
 
 typedef struct ide_drive_s {
-	request_queue_t		 queue;	/* request queue */
+	char		name[4];	/* drive name, such as "hda" */
+        char            driver_req[10];	/* requests specific driver */
+
+	request_queue_t		queue;	/* request queue */
+
+	struct request		*rq;	/* current request */
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
+	struct ide_driver_s	*driver;/* (ide_driver_t *) */
+	void		*driver_data;	/* extra driver data */
+	struct hd_driveid	*id;	/* drive model identification info */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
+	devfs_handle_t		de;	/* directory for device */
+
+	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
+
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
 	unsigned long service_time;	/* service time of last request */
 	unsigned long timeout;		/* max time to wait for irq */
+
 	special_t	special;	/* special action flags */
-	byte     keep_settings;		/* restore settings after drive reset */
-	byte     using_dma;		/* disk is using dma for read/write */
-	byte	 retry_pio;		/* retrying dma capable host in pio */
-	byte	 state;			/* retry state */
-	byte     waiting_for_dma;	/* dma currently in progress */
-	byte     unmask;		/* flag: okay to unmask other irqs */
-	byte     slow;			/* flag: slow data port */
-	byte     bswap;			/* flag: byte swap data */
-	byte     dsc_overlap;		/* flag: DSC overlap */
-	byte     nice1;			/* flag: give potential excess bandwidth */
+	select_t	select;		/* basic drive/head select reg value */
+
+	u8	keep_settings;		/* restore settings after drive reset */
+	u8	autodma;		/* device can safely use dma on host */
+	u8	using_dma;		/* disk is using dma for read/write */
+	u8	using_tcq;		/* disk is using queueing */
+	u8	retry_pio;		/* retrying dma capable host in pio */
+	u8	state;			/* retry state */
+	u8	waiting_for_dma;	/* dma currently in progress */
+	u8	unmask;			/* okay to unmask other irqs */
+	u8	slow;			/* slow data port */
+	u8	bswap;			/* byte swap data */
+	u8	dsc_overlap;		/* DSC overlap */
+	u8	nice1;			/* give potential excess bandwidth */
+
 	unsigned present	: 1;	/* drive is physically present */
 	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
+	unsigned is_flash	: 1;	/* 1 if probed as flash */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
 	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
 	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
-	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
-	unsigned atapi_overlap	: 1;	/* flag: ATAPI overlap (not supported) */
-	unsigned nice0		: 1;	/* flag: give obvious excess bandwidth */
-	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
-	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
+	unsigned nobios		: 1;	/* do not probe bios for drive */
+	unsigned atapi_overlap	: 1;	/* ATAPI overlap (not supported) */
+	unsigned nice0		: 1;	/* give obvious excess bandwidth */
+	unsigned nice2		: 1;	/* give a share in our own bandwidth */
+	unsigned doorlocking	: 1;	/* for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
-	unsigned addressing;		/*	: 3;
+	unsigned addressing;		/*      : 3;
 					 *  0=28-bit
 					 *  1=48-bit
 					 *  2=48-bit doing 28-bit
 					 *  3=64-bit
 					 */
-	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
-	byte		media;		/* disk, cdrom, tape, floppy, ... */
-	select_t	select;		/* basic drive/head select reg value */
-	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
-	byte		ready_stat;	/* min status value for drive ready */
-	byte		mult_count;	/* current multiple sector setting */
-	byte 		mult_req;	/* requested multiple sector setting */
-	byte 		tune_req;	/* requested drive tuning setting */
-	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
-	byte		nowerr;		/* used for ignoring WRERR_STAT */
-	byte		sect0;		/* offset of first sector for DM6:DDO */
-	unsigned int	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 */
+
+	u8	scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
+        u8	quirk_list;	/* considered quirky, set for a specific host */
+        u8	suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
+        u8	init_speed;	/* transfer rate set at boot */
+        u8	current_speed;	/* current transfer rate set */
+        u8	dn;		/* now wide spread use */
+        u8	wcache;		/* status of write cache */
+	u8	acoustic;	/* acoustic management */
+	u8	media;		/* disk, cdrom, tape, floppy, ... */
+	u8	ctl;		/* "normal" value for IDE_CONTROL_REG */
+	u8	ready_stat;	/* min status value for drive ready */
+	u8	mult_count;	/* current multiple sector setting */
+	u8	mult_req;	/* requested multiple sector setting */
+	u8	tune_req;	/* requested drive tuning setting */
+	u8	io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+	u8	bad_wstat;	/* used for ignoring WRERR_STAT */
+	u8	nowerr;		/* used for ignoring WRERR_STAT */
+	u8	sect0;		/* offset of first sector for DM6:DDO */
+	u8	head;		/* "real" number of heads */
+	u8	sect;		/* "real" sectors per track */
+	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
+	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
-	unsigned long	capacity;	/* total number of sectors */
-	unsigned long long capacity48;	/* total number of sectors */
-	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-	struct hwif_s	  *hwif;	/* actually (ide_hwif_t *) */
-	struct hd_driveid *id;		/* drive model identification info */
-	char		name[4];	/* drive name, such as "hda" */
-	struct ide_driver_s *driver;	/* (ide_driver_t *) */
-	void		*driver_data;	/* extra driver data */
-	devfs_handle_t	de;		/* directory for device */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	struct ide_settings_s *settings;	/* /proc/ide/ drive settings */
-	char		driver_req[10];	/* requests specific driver */
+	unsigned int	drive_data;	/* use by tuneproc/selectproc */
+	unsigned int	usage;		/* current "open()" count for drive */
+	unsigned int	failures;	/* current failure count */
+	unsigned int	max_failures;	/* maximum allowed failure count */
+
+	u32		capacity;	/* total number of sectors */
+	u64		capacity48;	/* total number of sectors */
+
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
-	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
-	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
-	byte		init_speed;	/* transfer rate set at boot */
-	byte		current_speed;	/* current transfer rate set */
-	byte		dn;		/* now wide spread use */
-	byte		wcache;		/* status of write cache */
-	byte		acoustic;	/* acoustic management */
-	unsigned int	failures;	/* current failure count */
-	unsigned int	max_failures;	/* maximum allowed failure count */
 	struct list_head list;
 	struct gendisk *disk;
 } ide_drive_t;
 
-/*
- * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case the caller
- * should either try again later, or revert to PIO for the current request.
- */
-typedef enum {	ide_dma_read,	ide_dma_write,		ide_dma_begin,
-		ide_dma_end,	ide_dma_check,		ide_dma_on,
-		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
-		ide_dma_host_on,			ide_dma_host_off,
-		ide_dma_bad_drive,			ide_dma_good_drive,
-		ide_dma_verbose,			ide_dma_retune,
-		ide_dma_lostirq,			ide_dma_timeout
-} ide_dma_action_t;
-
-typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
-
-/*
- * An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
- * Arguments are: the drive, the buffer pointer, and the length (in bytes or
- * words depending on if it's an IDE or ATAPI call).
- *
- * If it is not defined for a controller, standard-code is used from ide.c.
- *
- * Controllers which are not memory-mapped in the standard way need to 
- * override that mechanism using this function to work.
- *
- */
-typedef enum { ideproc_ide_input_data,    ideproc_ide_output_data,
-	       ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
-} ide_ide_action_t;
-
-typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
+typedef struct ide_pio_ops_s {
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+} ide_pio_ops_t;
+
+typedef struct ide_dma_ops_s {
+	/* insert dma operations here! */
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+} ide_dma_ops_t;
 
 /*
  * mapping stuff, prepare for highmem...
@@ -597,171 +894,188 @@
 	return rq->buffer + task_rq_offset(rq);
 }
 
-extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+extern inline void ide_unmap_buffer(struct request *rq, char *buffer, unsigned long *flags)
 {
-	bio_kunmap_irq(buffer, flags);
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-extern inline char *ide_xfer_verbose (byte xfer_rate)
-{
-	switch(xfer_rate) {
-		case XFER_UDMA_7:	return("UDMA 7");
-		case XFER_UDMA_6:	return("UDMA 6");
-		case XFER_UDMA_5:	return("UDMA 5");
-		case XFER_UDMA_4:	return("UDMA 4");
-		case XFER_UDMA_3:	return("UDMA 3");
-		case XFER_UDMA_2:	return("UDMA 2");
-		case XFER_UDMA_1:	return("UDMA 1");
-		case XFER_UDMA_0:	return("UDMA 0");
-		case XFER_MW_DMA_2:	return("MW DMA 2");
-		case XFER_MW_DMA_1:	return("MW DMA 1");
-		case XFER_MW_DMA_0:	return("MW DMA 0");
-		case XFER_SW_DMA_2:	return("SW DMA 2");
-		case XFER_SW_DMA_1:	return("SW DMA 1");
-		case XFER_SW_DMA_0:	return("SW DMA 0");
-		case XFER_PIO_4:	return("PIO 4");
-		case XFER_PIO_3:	return("PIO 3");
-		case XFER_PIO_2:	return("PIO 2");
-		case XFER_PIO_1:	return("PIO 1");
-		case XFER_PIO_0:	return("PIO 0");
-		case XFER_PIO_SLOW:	return("PIO SLOW");
-		default:		return("XFER ERROR");
-	}
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-extern inline char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
-{
-	switch (dmafunc) {
-		case ide_dma_read:		return("ide_dma_read");
-		case ide_dma_write:		return("ide_dma_write");
-		case ide_dma_begin:		return("ide_dma_begin");
-		case ide_dma_end:		return("ide_dma_end:");
-		case ide_dma_check:		return("ide_dma_check");
-		case ide_dma_on:		return("ide_dma_on");
-		case ide_dma_off:		return("ide_dma_off");
-		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
-		case ide_dma_test_irq:		return("ide_dma_test_irq");
-		case ide_dma_host_on:		return("ide_dma_host_on");
-		case ide_dma_host_off:		return("ide_dma_host_off");
-		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
-		case ide_dma_good_drive:	return("ide_dma_good_drive");
-		case ide_dma_verbose:		return("ide_dma_verbose");
-		case ide_dma_retune:		return("ide_dma_retune");
-		case ide_dma_lostirq:		return("ide_dma_lostirq");
-		case ide_dma_timeout:		return("ide_dma_timeout");
-		default:			return("unknown");
-	}
+	if (rq->bio)
+		bio_kunmap_irq(buffer, flags);
 }
 
-/*
- * An ide_tuneproc_t() is used to set the speed of an IDE interface
- * to a particular PIO mode.  The "byte" parameter is used
- * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
- * indicates that the interface driver should "auto-tune" the PIO mode
- * according to the drive capabilities in drive->id;
- *
- * Not all interface types support tuning, and not all of those
- * support all possible PIO settings.  They may silently ignore
- * or round values as they see fit.
- */
-typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
-typedef int (ide_speedproc_t) (ide_drive_t *, byte);
-
-/*
- * This is used to provide support for strange interfaces
- */
-typedef void (ide_selectproc_t) (ide_drive_t *);
-typedef void (ide_resetproc_t) (ide_drive_t *);
-typedef int (ide_quirkproc_t) (ide_drive_t *);
-typedef void (ide_intrproc_t) (ide_drive_t *);
-typedef void (ide_maskproc_t) (ide_drive_t *, int);
-typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
-
-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
-
 #define IDE_CHIPSET_PCI_MASK	\
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
-typedef struct ide_pci_devid_s {
-	unsigned short	vid;
-	unsigned short	did;
-} ide_pci_devid_t;
-
-#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
-#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
+struct ide_pci_device_s;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
 typedef struct hwif_s {
-	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
+	struct hwif_s *next;		/* for linked-list in ide_hwgroup_t */
+	struct hwif_s *mate;		/* other hwif from same PCI chip */
 	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
-	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
-/*
- *     FIXME!! need a generic register set :-/  PPC guys ideas??
- *
- *     ide_mmioreg_t   mm_ports[IDE_NR_PORTS]; "task file registers"
- *
- */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+
+	char name[6];			/* name of interface, eg. "ide0" */
+
+		/* task file registers for pata and sata */
+	ide_ioreg_t	io_ports[IDE_NR_PORTS];
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
+
 	hw_regs_t	hw;		/* Hardware info */
 	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
-	int		addressing;	/* hosts addressing */
-	void		(*tuneproc)(ide_drive_t *, byte);	/* routine to tune PIO mode for drives */
-	int		(*speedproc)(ide_drive_t *, byte);	/* routine to retune DMA modes for drives */
-	void		(*selectproc)(ide_drive_t *);		/* tweaks hardware to select drive */
-	void		(*resetproc)(ide_drive_t *);		/* routine to reset controller after a disk reset */
-	void		(*intrproc)(ide_drive_t *);		/* special interrupt handling for shared pci interrupts */
-	void		(*maskproc)(ide_drive_t *, int);	/* special host masking for drive selection */
-	int		(*quirkproc)(ide_drive_t *);		/* check host's drive quirk list */
-	void		(*rwproc)(ide_drive_t *, ide_dma_action_t);	/* adjust timing based upon rq->cmd direction */
-	void		(*ideproc)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);	/* CPU-polled transfer routine */
-	int		(*dmaproc)(ide_dma_action_t, ide_drive_t *);	/* dma read/write/abort routine */
-	int		(*busproc)(ide_drive_t *, int);		/* driver soft-power interface */
-	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
-	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
-	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
+
+	u8 major;	/* our major number */
+	u8 index;	/* 0 for ide0; 1 for ide1; ... */
+	u8 channel;	/* for dual-port chips: 0=primary, 1=secondary */
+	u8 straight8;	/* Alan's straight 8 check */
+	u8 bus_state;	/* power state of the IDE bus */
+
+	u8 atapi_dma;	/* host supports atapi_dma */
+	u8 ultra_mask;
+	u8 mwdma_mask;
+	u8 swdma_mask;
+
+	hwif_chipset_t chipset;	/* sub-module for tuning.. */
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	struct pci_dev  *pci_dev;	/* for pci chipsets */
+	struct ide_pci_device_s	*cds;	/* chipset device struct */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#if 0
+	ide_hwif_ops_t	*hwifops;
+#else
+	/* routine is for HBA specific IDENTITY operations */
+	int	(*identify)(ide_drive_t *);
+	/* routine to tune PIO mode for drives */
+	void	(*tuneproc)(ide_drive_t *, u8);
+	/* routine to retune DMA modes for drives */
+	int	(*speedproc)(ide_drive_t *, u8);
+	/* tweaks hardware to select drive */
+	void	(*selectproc)(ide_drive_t *);
+	/* chipset polling based on hba specifics */
+	int	(*reset_poll)(ide_drive_t *);
+	/* chipset specific changes to default for device-hba resets */
+	void	(*pre_reset)(ide_drive_t *);
+	/* routine to reset controller after a disk reset */
+	void	(*resetproc)(ide_drive_t *);
+	/* special interrupt handling for shared pci interrupts */
+	void	(*intrproc)(ide_drive_t *);
+	/* special host masking for drive selection */
+	void	(*maskproc)(ide_drive_t *, int);
+	/* check host's drive quirk list */
+	int	(*quirkproc)(ide_drive_t *);
+	/* driver soft-power interface */
+	int	(*busproc)(ide_drive_t *, int);
+//	/* host rate limiter */
+//	u8	(*ratemask)(ide_drive_t *);
+//	/* device rate limiter */
+//	u8	(*ratefilter)(ide_drive_t *, u8);
+#endif
+
+#if 0
+	ide_pio_ops_t	*pioops;
+#else
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+#endif
+
+#if 0
+	ide_dma_ops_t	*dmaops;
+#else
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+#endif
+
+#if 0
+	ide_io_ops_t	*iops;
+#else
+	void (*OUTB)(u8 addr, u32 port);
+	void (*OUTW)(u16 addr, u32 port);
+	void (*OUTL)(u32 addr, u32 port);
+	void (*OUTBP)(u8 addr, u32 port);
+	void (*OUTWP)(u16 addr, u32 port);
+	void (*OUTLP)(u32 addr, u32 port);
+	void (*OUTSW)(u32 port, void *addr, u32 count);
+	void (*OUTSWP)(u32 port, void *addr, u32 count);
+	void (*OUTSL)(u32 port, void *addr, u32 count);
+	void (*OUTSLP)(u32 port, void *addr, u32 count);
+
+	u8  (*INB)(u32 port);
+	u16 (*INW)(u32 port);
+	u32 (*INL)(u32 port);
+	u8  (*INBP)(u32 port);
+	u16 (*INWP)(u32 port);
+	u32 (*INLP)(u32 port);
+	void (*INSW)(u32 port, void *addr, u32 count);
+	void (*INSWP)(u32 port, void *addr, u32 count);
+	void (*INSL)(u32 port, void *addr, u32 count);
+	void (*INSLP)(u32 port, void *addr, u32 count);
+#endif
+
+	/* dma physical region descriptor table (cpu view) */
+	unsigned int	*dmatable_cpu;
+	/* dma physical region descriptor table (dma view) */
+	dma_addr_t	dmatable_dma;
+	/* Scatter-gather list used to build the above */
+	struct scatterlist *sg_table;
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
 	int sg_dma_active;		/* is it in use */
-	struct hwif_s	*mate;		/* other hwif from same PCI chip */
+
+	int		mmio;		/* hosts iomio (0), mmio (1) or custom (2) select */
+	int		rqsize;		/* max sectors per request */
+	int		addressing;	/* hosts addressing */
+	int		irq;		/* our irq number */
+	int		initializing;	/* set while initializing self */
+
+	unsigned long	dma_master;	/* reference base addr dmabase */
 	unsigned long	dma_base;	/* base addr for dma ports */
+	unsigned long	dma_command;	/* dma command register */
+	unsigned long	dma_vendor1;	/* dma vendor 1 register */
+	unsigned long	dma_status;	/* dma status register */
+	unsigned long	dma_vendor3;	/* dma vendor 3 register */
+	unsigned long	dma_prdtable;	/* actual prd table address */
+	unsigned long	dma_base2;	/* extended base addr for dma ports */
+
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
 	unsigned long	select_data;	/* for use by chipset-specific code */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	int		irq;		/* our irq number */
-	byte		major;		/* our major number */
-	char 		name[6];	/* name of interface, eg. "ide0" */
-	byte		index;		/* 0 for ide0; 1 for ide1; ... */
-	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
+#if (DISK_RECOVERY_TIME > 0)
+	unsigned long	last_time;	/* time when previous rq was done */
+#endif
+
+
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
 	unsigned	present    : 1;	/* this interface exists */
-	unsigned	serialized : 1;	/* serialized operation with mate hwif */
+	unsigned	serialized : 1;	/* serialized all channel operation */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
-	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
+	unsigned	autodma    : 1;	/* auto-attempt using DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
-	unsigned	no_highmem : 1;	/* always use high i/o bounce */
-	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	struct pci_dev	*pci_dev;	/* for pci chipsets */
-	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-#if (DISK_RECOVERY_TIME > 0)
-	unsigned long	last_time;	/* time when previous rq was done */
-#endif
-	byte		straight8;	/* Alan's straight 8 check */
+	unsigned	highmem    : 1;	/* can do full 32-bit dma */
+	unsigned	no_dsc     : 1;	/* 0 default, 1 dsc_overlap disabled */
+
 	void		*hwif_data;	/* extra hwif data */
-	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
 /*
@@ -769,7 +1083,7 @@
  */
 typedef enum {
 	ide_stopped,	/* no drive operation was started */
-	ide_started	/* a drive operation was started, and a handler was set */
+	ide_started	/* a drive operation was started, handler was set */
 } ide_startstop_t;
 
 /*
@@ -778,26 +1092,41 @@
 typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
-
-/*
- * when ide_timer_expiry fires, invoke a handler of this type
- * to decide what to do.
- */
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
-	ide_handler_t		*handler;/* irq handler, if active */
-	ide_handler_t		*handler_save;/* irq handler, if active */
-	volatile int		busy;	/* BOOL: protects all fields below */
-	int			sleeping; /* BOOL: wake us up on timer expiry */
-	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 */
-	unsigned long		poll_timeout;	/* timeout value during long polls */
-	ide_expiry_t		*expiry;	/* queried upon timeouts */
-	int			pio_clock;	/* ide_system_bus_speed */
+		/* irq handler, if active */
+	ide_startstop_t	(*handler)(ide_drive_t *);
+		/* irq handler, suspended if active */
+	ide_startstop_t	(*handler_save)(ide_drive_t *);
+		/* BOOL: protects all fields below */
+	volatile int busy;
+		/* BOOL: wake us up on timer expiry */
+	int sleeping;
+		/* current drive */
+	ide_drive_t *drive;
+		/* ptr to current hwif in linked-list */
+	ide_hwif_t *hwif;
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		/* for pci chipsets */
+	struct pci_dev *pci_dev;
+		/* chipset device struct */
+	struct ide_pci_device_s *cds;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+		/* current request */
+	struct request *rq;
+		/* failsafe timer */
+	struct timer_list timer;
+		/* local copy of current write rq */
+	struct request wrq;
+		/* timeout value during long polls */
+	unsigned long poll_timeout;
+		/* queried upon timeouts */
+	int (*expiry)(ide_drive_t *);
+		/* ide_system_bus_speed */
+	int pio_clock;
 } ide_hwgroup_t;
 
 /* structure attached to the request for IDE_TASK_CMDS */
@@ -850,14 +1179,14 @@
 } ide_proc_entry_t;
 
 #ifdef CONFIG_PROC_FS
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_drives(ide_hwif_t *);
-void create_proc_ide_interfaces(void);
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
+extern void proc_ide_create(void);
+extern void proc_ide_destroy(void);
+extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_drives(ide_hwif_t *);
+extern void create_proc_ide_interfaces(void);
+extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
+extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -889,7 +1218,7 @@
 	struct module			*owner;
 	const char			*name;
 	const char			*version;
-	byte				media;
+	u8				media;
 	unsigned busy			: 1;
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
@@ -899,9 +1228,9 @@
 	int		(*resume)(ide_drive_t *);
 	int		(*flushcache)(ide_drive_t *);
 	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
-	int		(*end_request)(ide_drive_t *, int);
-	byte		(*sense)(ide_drive_t *, const char *, byte);
-	ide_startstop_t (*error)(ide_drive_t *, const char *, byte);
+	int		(*end_request)(ide_drive_t *, int, int);
+	u8		(*sense)(ide_drive_t *, const char *, u8);
+	ide_startstop_t	(*error)(ide_drive_t *, const char *, u8);
 	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 	int		(*open)(struct inode *, struct file *, ide_drive_t *);
 	void		(*release)(struct inode *, struct file *, ide_drive_t *);
@@ -910,8 +1239,8 @@
 	void		(*pre_reset)(ide_drive_t *);
 	unsigned long	(*capacity)(ide_drive_t *);
 	ide_startstop_t	(*special)(ide_drive_t *);
-	ide_proc_entry_t        *proc;
-	int		(*reinit)(ide_drive_t *);
+	ide_proc_entry_t	*proc;
+	int		(*attach)(ide_drive_t *);
 	void		(*ata_prebuilder)(ide_drive_t *);
 	void		(*atapi_prebuilder)(ide_drive_t *);
 	struct list_head drives;
@@ -935,6 +1264,13 @@
 	struct ide_module_s		*next;
 } ide_module_t;
 
+typedef struct ide_devices_s {
+	char			name[4];		/* hdX */
+	unsigned		attached	: 1;	/* native */
+	unsigned		alttached	: 1;	/* alternate */
+	struct ide_devices_s	*next;
+} ide_devices_t;
+
 /*
  * ide_hwifs[] is the master data structure used to keep track
  * of just about everything in ide.c.  Whenever possible, routines
@@ -945,7 +1281,15 @@
  */
 #ifndef _IDE_C
 extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
+extern ide_module_t	*ide_chipsets;
 extern	ide_module_t	*ide_probe;
+
+extern ide_devices_t   *idedisk;
+extern ide_devices_t   *idecd;
+extern ide_devices_t   *idefloppy;
+extern ide_devices_t   *idetape;
+extern ide_devices_t   *idescsi;
+
 #endif
 extern int noautodma;
 
@@ -957,38 +1301,47 @@
 #define DEVICE_NR(device)	(minor(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-int ide_end_request (ide_drive_t *drive, int uptodate);
+extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
 
 /*
  * 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, unsigned int timeout, ide_expiry_t *expiry);
+extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
+ *
+ * (drive, msg, status)
  */
 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.
  * The caller should return immediately after invoking this.
+ *
+ * (drive, msg, status)
  */
 ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
 
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
+ *
+ * (drive, command, nsector, handler)
  */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+extern void ide_cmd(ide_drive_t *, u8, u8, ide_handler_t *);
 
+extern void ide_fix_driveid(struct hd_driveid *);
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  * removing leading/trailing blanks and compressing internal blanks.
  * It is primarily used to tidy up the model name/number fields as
  * returned by the WIN_[P]IDENTIFY commands.
+ *
+ * (s, bytecount, byteswap)
  */
-void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+extern void ide_fixstring(u8 *, const int, const int);
 
 /*
  * This routine busy-waits for the drive status to be not "busy".
@@ -997,43 +1350,44 @@
  * cases return 1 after doing "*startstop = ide_error()", and the
  * caller should return the updated value of "startstop" in this case.
  * "startstop" is unchanged when the function returns 0;
+ * (startstop, drive, good, bad, timeout)
  */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 /*
  * 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.
  */
-int ide_xlate_1024 (kdev_t, int, int, const char *);
+extern int ide_xlate_1024 (kdev_t, int, int, const char *);
 
 /*
  * Convert kdev_t structure into ide_drive_t * one.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev);
+extern ide_drive_t *get_info_ptr (kdev_t i_rdev);
 
 /*
  * Return the current idea about the total capacity of this drive.
  */
-unsigned long current_capacity (ide_drive_t *drive);
+extern unsigned long current_capacity (ide_drive_t *drive);
 
-void ide_revalidate_drive (ide_drive_t *drive);
+extern void ide_revalidate_drive (ide_drive_t *drive);
 
 /*
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-ide_startstop_t ide_do_reset (ide_drive_t *);
+extern ide_startstop_t ide_do_reset (ide_drive_t *);
 
 /*
  * Re-Start an operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-int restart_request (ide_drive_t *, struct request *);
+extern int restart_request (ide_drive_t *, struct request *);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
-void ide_init_drive_cmd (struct request *rq);
+extern void ide_init_drive_cmd (struct request *rq);
 
 /*
  * "action" parameter type for ide_do_drive_cmd() below.
@@ -1070,23 +1424,35 @@
  * for the new rq to be completed. This is again intended for careful
  * use by the ATAPI tape/cdrom driver code.
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
 
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
+ *
+ * (ide_drive_t *drive, u8 stat, u8 err)
  */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
 /*
- * Issue ATA command and wait for completion. use for implementing commands in kernel
+ * Issue ATA command and wait for completion.
+ * Use for implementing commands in kernel
+ *
+ *  (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
  */
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
+
+/* (ide_drive_t *drive, u8 *buf) */
+extern int ide_wait_cmd_task(ide_drive_t *, u8 *);
 
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
- 
 typedef struct ide_task_s {
+/*
+ *	struct hd_drive_task_hdr	tf;
+ *	task_struct_t		tf;
+ *	struct hd_drive_hob_hdr		hobf;
+ *	hob_struct_t		hobf;
+ */
 	task_ioreg_t		tfRegister[8];
 	task_ioreg_t		hobRegister[8];
 	ide_reg_valid_t		tf_out_flags;
@@ -1101,6 +1467,11 @@
 } ide_task_t;
 
 typedef struct pkt_task_s {
+/*
+ *	struct hd_drive_task_hdr	pktf;
+ *	task_struct_t		pktf;
+ *	u8			pkcdb[12];
+ */
 	task_ioreg_t		tfRegister[8];
 	int			data_phase;
 	int			command_type;
@@ -1109,66 +1480,129 @@
 	void			*special;
 } pkt_task_t;
 
-void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+extern inline void SELECT_DRIVE(ide_drive_t *);
+extern inline void SELECT_INTERRUPT(ide_drive_t *);
+extern inline void SELECT_MASK(ide_drive_t *, int);
+extern inline void QUIRK_LIST(ide_drive_t *);
+
+extern void ata_input_data(ide_drive_t *, void *, u32);
+extern void ata_output_data(ide_drive_t *, void *, u32);
+extern void atapi_input_bytes(ide_drive_t *, void *, u32);
+extern void atapi_output_bytes(ide_drive_t *, void *, u32);
+extern void taskfile_input_data(ide_drive_t *, void *, u32);
+extern void taskfile_output_data(ide_drive_t *, void *, u32);
 
-int drive_is_ready (ide_drive_t *drive);
-int wait_for_ready (ide_drive_t *drive, int timeout);
+extern int drive_is_ready(ide_drive_t *);
+extern int wait_for_ready(ide_drive_t *, int /* timeout */);
 
 /*
  * taskfile io for disks for now...and builds request from ide_ioctl
  */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
 
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err);
+/* (ide_drive_t *drive, u8 stat, u8 err) */
+extern void ide_end_taskfile(ide_drive_t *, u8, u8);
 
 /*
  * Special Flagged Register Validation Caller
  */
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+
+extern ide_startstop_t set_multmode_intr(ide_drive_t *);
+extern ide_startstop_t set_geometry_intr(ide_drive_t *);
+extern ide_startstop_t recal_intr(ide_drive_t *);
+extern ide_startstop_t task_no_data_intr(ide_drive_t *);
+extern ide_startstop_t task_in_intr(ide_drive_t *);
+extern ide_startstop_t task_mulin_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_out_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_mulout_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_mulout_intr(ide_drive_t *);
+extern void ide_init_drive_taskfile(struct request *);
+
+extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
+
+extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
+
+extern ide_handler_t * ide_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
+
+extern ide_post_handler_t * ide_post_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-ide_startstop_t set_multmode_intr (ide_drive_t *drive);
-ide_startstop_t set_geometry_intr (ide_drive_t *drive);
-ide_startstop_t recal_intr (ide_drive_t *drive);
-ide_startstop_t task_no_data_intr (ide_drive_t *drive);
-ide_startstop_t task_in_intr (ide_drive_t *drive);
-ide_startstop_t task_mulin_intr (ide_drive_t *drive);
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
-ide_startstop_t task_out_intr (ide_drive_t *drive);
-ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq);
-ide_startstop_t task_mulout_intr (ide_drive_t *drive);
-void ide_init_drive_taskfile (struct request *rq);
-
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
-
-ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
-ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
-ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
 /* Expects args is a full set of TF registers and parses the command type */
-int ide_cmd_type_parser (ide_task_t *args);
+extern int ide_cmd_type_parser(ide_task_t *);
 
-int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+int ide_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_cmd_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_task_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+
+#if 0
+
+#define IDEFLOPPY_PC_BUFFER_SIZE        256
+#define IDETAPE_PC_BUFFER_SIZE          256
+#define IDE_PC_BUFFER_SIZE          256
+
+typedef struct ide_packet_command_s {
+		/* Actual packet bytes */
+	u8 c[12];
+		/* On each retry, we increment retries */
+	int retries;
+		/* Error code */
+	int error;
+		/* Bytes to transfer */
+	int request_transfer;
+		/* Bytes actually transferred */
+	int actually_transferred;
+		/* Size of our data buffer */
+	int buffer_size;
+
+	struct buffer_head *bh;
+	u8 *b_data;
+		/* The corresponding request */
+	struct request *rq;
+# if 0
+		/* Scatter gather table */
+	struct scatterlist *sg;
+# endif
+	int b_count;
+		/* Data buffer */
+	u8 *buffer;
+		/* Pointer into the above buffer */
+	u8 *current_position;
+		/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (ide_drive_t *);
+		/* Temporary buffer */
+	u8 pc_buffer[IDE_PC_BUFFER_SIZE];
+		/* Status/Action bit flags: long for set_bit */
+	unsigned long flags;
+} ide_pc_t;
+
+ide-cd orthoginal :-/
+struct packet_command {
+        char *buffer;
+        int buflen;
+        int stat;
+        int quiet;
+        int timeout;
+        struct request_sense *sense;
+        unsigned char c[12];
+};
+
+#endif
 
 #ifdef CONFIG_PKT_TASK_IOCTL
-int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern int pkt_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 #endif /* CONFIG_PKT_TASK_IOCTL */
 
-void ide_delay_50ms (void);
-int system_bus_clock(void);
+extern void ide_delay_50ms(void);
+extern int system_bus_clock(void);
 
-byte ide_auto_reduce_xfer (ide_drive_t *drive);
-int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
-int ide_config_drive_speed (ide_drive_t *drive, byte speed);
-byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, ide_task_t *args);
-int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf);
+extern u8 ide_auto_reduce_xfer(ide_drive_t *);
+extern int ide_driveid_update(ide_drive_t *);
+extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
+extern int ide_config_drive_speed(ide_drive_t *, u8);
+extern u8 eighty_ninty_three (ide_drive_t *);
+extern int set_transfer(ide_drive_t *, ide_task_t *);
+extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -1176,45 +1610,55 @@
  * The default is 40 for known PCI systems, 50 otherwise.
  * The "idebus=xx" parameter can be used to override this value.
  */
-int ide_system_bus_speed (void);
+extern int ide_system_bus_speed(void);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
  * to the hwgroup by sleeping for timeout jiffies.
  */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
+extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
 
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-request_queue_t *ide_get_queue (kdev_t dev);
+extern request_queue_t *ide_get_queue (kdev_t dev);
 
 /*
  * CompactFlash cards and their brethern pretend to be removable hard disks,
  * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ * This test catches them, and is invoked elsewhere when setting appropriate
+ * config bits.
  */
-int drive_is_flashcard (ide_drive_t *drive);
+extern int drive_is_flashcard (ide_drive_t *drive);
 
-int ide_spin_wait_hwgroup (ide_drive_t *drive);
-void ide_timer_expiry (unsigned long data);
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
-void do_ide_request (request_queue_t * q);
-void ide_init_subdrivers (void);
+extern int ide_spin_wait_hwgroup(ide_drive_t *);
+extern void ide_timer_expiry(unsigned long);
+extern void ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+extern void do_ide_request(request_queue_t *);
+extern void ide_init_subdrivers(void);
 
 #ifndef _IDE_C
 extern struct block_device_operations ide_fops[];
 extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
-int ata_attach(ide_drive_t *drive);
+extern int ata_attach(ide_drive_t *);
 
 #ifdef _IDE_C
 #ifdef CONFIG_BLK_DEV_IDE
-int ideprobe_init (void);
+extern int ideprobe_init(void);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+extern void ide_scan_pcibus(int scan_direction) __init;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 #endif /* CONFIG_BLK_DEV_IDE */
 #endif /* _IDE_C */
 
+extern void default_hwif_iops(ide_hwif_t *);
+extern void default_hwif_mmiops(ide_hwif_t *);
+extern void default_hwif_transport(ide_hwif_t *);
+
 int ide_register_driver(ide_driver_t *driver);
 void ide_unregister_driver(ide_driver_t *driver);
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
@@ -1222,85 +1666,113 @@
 int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
+
+#ifdef CONFIG_PROC_FS
+typedef struct ide_pci_host_proc_s {
+	char				*name;
+	u8				set;
+	get_info_t			*get_info;
+	struct proc_dir_entry		*parent;
+	struct ide_pci_host_proc_s	*next;
+} ide_pci_host_proc_t;
+
+void ide_pci_register_host_proc(ide_pci_host_proc_t *);
+#endif /* CONFIG_PROC_FS */
+
 #define ON_BOARD		1
 #define NEVER_BOARD		0
+
 #ifdef CONFIG_BLK_DEV_OFFBOARD
 #  define OFF_BOARD		ON_BOARD
 #else /* CONFIG_BLK_DEV_OFFBOARD */
 #  define OFF_BOARD		NEVER_BOARD
 #endif /* CONFIG_BLK_DEV_OFFBOARD */
 
+#define NODMA 0
+#define NOAUTODMA 1
+#define AUTODMA 2
+#define EOL 255
 
 typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
+	u8	reg;	/* byte pci reg holding the enable-bit */
+	u8	mask;	/* mask to isolate the enable-bit */
+	u8	val;	/* value of masked reg when "enabled" */
 } ide_pci_enablebit_t;
 
 typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
+	u16			vendor;
+	u16			device;
 	char			*name;
-	void			(*fixup_device)(struct pci_dev *, struct ide_pci_device_s *);
+	void			(*init_setup)(struct pci_dev *, struct ide_pci_device_s *);
 	unsigned int		(*init_chipset)(struct pci_dev *, const char *);
-	unsigned int		(*ata66_check)(ide_hwif_t *);
-	void			(*init_hwif)(ide_hwif_t *);
-	void			(*dma_init)(ide_hwif_t *, unsigned long);
+	void			(*init_iops)(ide_hwif_t *);
+	void                    (*init_hwif)(ide_hwif_t *);
+	void			(*init_dma)(ide_hwif_t *, unsigned long);
+	u8			channels;
+	u8			autodma;
 	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
+	u8			bootable;
 	unsigned int		extra;
+	struct ide_pci_device_s	*next;
 } ide_pci_device_t;
 
 #ifdef LINUX_PCI_H
-extern inline void ide_register_xp_fix(struct pci_dev *dev)
-{
-	int i;
-	unsigned short cmd;
-	unsigned long flags;
-	unsigned long base_address[4] = { 0x1f0, 0x3f4, 0x170, 0x374 };
-
-	local_irq_save(flags);
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	for (i=0; i<4; i++) {
-		dev->resource[i].start = 0;
-		dev->resource[i].end = 0;
-		dev->resource[i].flags = 0;
-	}
-	for (i=0; i<4; i++) {
-		dev->resource[i].start = base_address[i];
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-		pci_write_config_dword(dev,
-			(PCI_BASE_ADDRESS_0 + (i * 4)),
-			dev->resource[i].start);
-	}
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-	local_irq_restore(flags);
-}
-
-void ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) __init;
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
 #endif /* LINUX_PCI_H */
 
-unsigned long ide_find_free_region (unsigned short size) __init;
-void ide_scan_pcibus (int scan_direction) __init;
-#endif
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 #ifdef CONFIG_BLK_DEV_IDEDMA
 #define BAD_DMA_DRIVE		0
 #define GOOD_DMA_DRIVE		1
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
-void ide_destroy_dmatable (ide_drive_t *drive);
-ide_startstop_t ide_dma_intr (ide_drive_t *drive);
-int check_drive_lists (ide_drive_t *drive, int good_bad);
-int report_drive_dmaing (ide_drive_t *drive);
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-int ide_release_dma (ide_hwif_t *hwif);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
-unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+extern int ide_build_dmatable(ide_drive_t *, struct request *);
+extern void ide_destroy_dmatable(ide_drive_t *);
+extern ide_startstop_t ide_dma_intr(ide_drive_t *);
+extern int ide_release_dma(ide_hwif_t *);
+extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+
+extern int __ide_dma_host_off(ide_drive_t *);
+extern int __ide_dma_off_quietly(ide_drive_t *);
+extern int __ide_dma_off(ide_drive_t *);
+extern int __ide_dma_host_on(ide_drive_t *);
+extern int __ide_dma_on(ide_drive_t *);
+extern int __ide_dma_check(ide_drive_t *);
+extern int __ide_dma_read(ide_drive_t *);
+extern int __ide_dma_write(ide_drive_t *);
+extern int __ide_dma_begin(ide_drive_t *);
+extern int __ide_dma_end(ide_drive_t *);
+extern int __ide_dma_test_irq(ide_drive_t *);
+extern int __ide_dma_bad_drive(ide_drive_t *);
+extern int __ide_dma_good_drive(ide_drive_t *);
+extern int __ide_dma_count(ide_drive_t *);
+extern int __ide_dma_verbose(ide_drive_t *);
+extern int __ide_dma_retune(ide_drive_t *);
+extern int __ide_dma_lostirq(ide_drive_t *);
+extern int __ide_dma_timeout(ide_drive_t *);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+extern void hwif_unregister(ide_hwif_t *);
+
+extern void export_ide_init_queue(ide_drive_t *);
+extern u8 export_probe_for_drive(ide_drive_t *);
+extern int probe_hwif_init(ide_hwif_t *);
 
-void hwif_unregister (ide_hwif_t *hwif);
+static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
+{
+	return hwif->hwif_data;
+}
+
+static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
+{
+	hwif->hwif_data = data;
+}
 
-void export_ide_init_queue (ide_drive_t *drive);
-byte export_probe_for_drive (ide_drive_t *drive);
+/* ide-lib.c */
+extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
+extern u8 ide_rate_filter(u8 mode, u8 speed); 
+extern int ide_dma_enable(ide_drive_t *drive);
+extern char *ide_xfer_verbose(u8 xfer_rate);
 
 extern spinlock_t ide_lock;
 
diff -Nru a/include/linux/init_task.h b/include/linux/init_task.h
--- a/include/linux/init_task.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/init_task.h	Sun Sep 15 19:19:29 2002
@@ -18,15 +18,29 @@
 	.fd_array	= { NULL, } 			\
 }
 
+#define INIT_KIOCTX(name, which_mm) \
+{							\
+	.users		= ATOMIC_INIT(1),		\
+	.dead		= 0,				\
+	.mm		= &which_mm,			\
+	.user_id	= 0,				\
+	.next		= NULL,				\
+	.wait		= __WAIT_QUEUE_HEAD_INITIALIZER(name.wait), \
+	.ctx_lock	= SPIN_LOCK_UNLOCKED,		\
+	.reqs_active	= 0U,				\
+	.max_reqs	= ~0U,				\
+}
+
 #define INIT_MM(name) \
-{			 				\
-	.mm_rb		= RB_ROOT,			\
-	.pgd		= swapper_pg_dir, 		\
-	.mm_users	= ATOMIC_INIT(2), 		\
-	.mm_count	= ATOMIC_INIT(1), 		\
-	.mmap_sem	= __RWSEM_INITIALIZER(name.mmap_sem), \
-	.page_table_lock =  SPIN_LOCK_UNLOCKED, 	\
-	.mmlist		= LIST_HEAD_INIT(name.mmlist),	\
+{			 					\
+	.mm_rb		= RB_ROOT,				\
+	.pgd		= swapper_pg_dir, 			\
+	.mm_users	= ATOMIC_INIT(2), 			\
+	.mm_count	= ATOMIC_INIT(1), 			\
+	.mmap_sem	= __RWSEM_INITIALIZER(name.mmap_sem),	\
+	.page_table_lock =  SPIN_LOCK_UNLOCKED, 		\
+	.mmlist		= LIST_HEAD_INIT(name.mmlist),		\
+	.default_kioctx = INIT_KIOCTX(name.default_kioctx, name),	\
 }
 
 #define INIT_SIGNALS(sig) {	\
@@ -61,6 +75,7 @@
 	.parent		= &tsk,						\
 	.children	= LIST_HEAD_INIT(tsk.children),			\
 	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
+	.group_leader	= &tsk,						\
 	.thread_group	= LIST_HEAD_INIT(tsk.thread_group),		\
 	.wait_chldexit	= __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
 	.real_timer	= {						\
diff -Nru a/include/linux/llc.h b/include/linux/llc.h
--- a/include/linux/llc.h	Sun Sep 15 19:19:37 2002
+++ b/include/linux/llc.h	Sun Sep 15 19:19:37 2002
@@ -78,17 +78,6 @@
 #define LLC_SAP_DYN_STOP	0xDE
 #define LLC_SAP_DYN_TRIES	4
 
-struct sock;
-
-struct llc_ui_opt {
-	u16		     link;	/* network layer link number */
-	struct llc_sap	    *sap;	/* pointer to parent SAP */
-	struct sock	    *core_sk;
-	struct net_device   *dev;	/* device to send to remote */
-	struct sockaddr_llc  addr;	/* address sock is bound to */
-};
-
-#define llc_ui_sk(__sk) ((struct llc_ui_opt *)(__sk)->protinfo)
 #define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))
 
 #ifdef CONFIG_LLC_UI
diff -Nru a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
--- a/include/linux/lockd/bind.h	Sun Sep 15 19:19:34 2002
+++ b/include/linux/lockd/bind.h	Sun Sep 15 19:19:34 2002
@@ -19,14 +19,10 @@
  * This is the set of functions for lockd->nfsd communication
  */
 struct nlmsvc_binding {
-	void			(*exp_readlock)(void);
-	void			(*exp_unlock)(void);
-	struct svc_client *	(*exp_getclient)(struct sockaddr_in *);
 	u32			(*fopen)(struct svc_rqst *,
 						struct nfs_fh *,
 						struct file *);
 	void			(*fclose)(struct file *);
-	void			(*detach)(void);
 };
 
 extern struct nlmsvc_binding *	nlmsvc_ops;
@@ -34,7 +30,6 @@
 /*
  * Functions exported by the lockd module
  */
-extern void	nlmsvc_invalidate_client(struct svc_client *clnt);
 extern int	nlmclnt_proc(struct inode *, int, struct file_lock *);
 extern int	lockd_up(void);
 extern void	lockd_down(void);
diff -Nru a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
--- a/include/linux/lockd/lockd.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/lockd/lockd.h	Sun Sep 15 19:19:29 2002
@@ -39,13 +39,13 @@
 struct nlm_host {
 	struct nlm_host *	h_next;		/* linked list (hash table) */
 	struct sockaddr_in	h_addr;		/* peer address */
-	struct svc_client *	h_exportent;	/* NFS client */
 	struct rpc_clnt	*	h_rpcclnt;	/* RPC client to talk to peer */
 	char			h_name[20];	/* remote hostname */
 	u32			h_version;	/* interface version */
 	unsigned short		h_proto;	/* transport proto */
 	unsigned short		h_authflavor;	/* RPC authentication type */
 	unsigned short		h_reclaiming : 1,
+				h_server     : 1, /* server side, not client side */
 				h_inuse      : 1,
 				h_killed     : 1,
 				h_monitored  : 1;
@@ -143,13 +143,14 @@
  */
 struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
 struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
-struct nlm_host * nlm_lookup_host(struct svc_client *,
-					struct sockaddr_in *, int, int);
+struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void		  nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
 void		  nlm_release_host(struct nlm_host *);
 void		  nlm_shutdown_hosts(void);
+extern struct nlm_host *nlm_find_client(void);
+
 
 /*
  * Server-side lock handling
@@ -173,6 +174,7 @@
 void		  nlm_release_file(struct nlm_file *);
 void		  nlmsvc_mark_resources(void);
 void		  nlmsvc_free_host_resources(struct nlm_host *);
+void		  nlmsvc_invalidate_all(void);
 
 static __inline__ struct inode *
 nlmsvc_file_inode(struct nlm_file *file)
diff -Nru a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
--- a/include/linux/lockd/sm_inter.h	Sun Sep 15 19:19:50 2002
+++ b/include/linux/lockd/sm_inter.h	Sun Sep 15 19:19:50 2002
@@ -28,6 +28,7 @@
 	u32		prog;		/* RPC callback info */
 	u32		vers;
 	u32		proc;
+	u32		proto;		/* protocol (udp/tcp) plus server/client flag */
 };
 
 /*
diff -Nru a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
--- a/include/linux/lockd/xdr.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/lockd/xdr.h	Sun Sep 15 19:19:28 2002
@@ -76,6 +76,8 @@
 	int		len;
 	u32		state;
 	u32		addr;
+	u32		vers;
+	u32		proto;
 };
 
 /*
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/mm.h	Sun Sep 15 19:19:28 2002
@@ -159,9 +159,9 @@
 	struct list_head lru;		/* Pageout list, eg. active_list;
 					   protected by zone->lru_lock !! */
 	union {
-		struct pte_chain * chain;	/* Reverse pte mapping pointer.
+		struct pte_chain *chain;/* Reverse pte mapping pointer.
 					 * protected by PG_chainlock */
-		pte_t		 * direct;
+		pte_addr_t direct;
 	} pte;
 	unsigned long private;		/* mapping-private opaque data */
 
@@ -320,6 +320,16 @@
 			+ page_zone(page)->zone_start_pfn) << PAGE_SHIFT)
 
 #endif /* CONFIG_HIGHMEM || WANT_PAGE_VIRTUAL */
+
+/*
+ * Return true if this page is mapped into pagetables.  Subtle: test pte.direct
+ * rather than pte.chain.  Because sometimes pte.direct is 64-bit, and .chain
+ * is only 32-bit.
+ */
+static inline int page_mapped(struct page *page)
+{
+	return page->pte.direct != 0;
+}
 
 /*
  * Error return values for the *_nopage functions
diff -Nru a/include/linux/nfsd/auth.h b/include/linux/nfsd/auth.h
--- a/include/linux/nfsd/auth.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/nfsd/auth.h	Sun Sep 15 19:19:29 2002
@@ -23,23 +23,5 @@
  */
 void		nfsd_setuser(struct svc_rqst *, struct svc_export *);
 
-#if 0
-/*
- * These must match the actual size of uid_t and gid_t
- */
-#define UGID_BITS		(8 * sizeof(uid_t))
-#define UGID_SHIFT		8
-#define UGID_MASK		((1 << UGID_SHIFT) - 1)
-#define UGID_NRENTRIES		((1 << (UGID_BITS - UGID_SHIFT)) + 1)
-#define UGID_NONE		((unsigned short)-1)
-
-typedef struct svc_uidmap {
-	uid_t *			um_ruid[UGID_NRENTRIES];
-	uid_t *			um_luid[UGID_NRENTRIES];
-	gid_t *			um_rgid[UGID_NRENTRIES];
-	gid_t *			um_lgid[UGID_NRENTRIES];
-} svc_uidmap;
-#endif
-
 #endif /* __KERNEL__ */
 #endif /* LINUX_NFSD_AUTH_H */
diff -Nru a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
--- a/include/linux/nfsd/export.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/nfsd/export.h	Sun Sep 15 19:19:28 2002
@@ -45,38 +45,36 @@
 
 #ifdef __KERNEL__
 
-/* The following are hashtable sizes and must be powers of 2 */
-#define NFSCLNT_EXPMAX		16
-
 struct svc_client {
 	struct svc_client *	cl_next;
 	char			cl_ident[NFSCLNT_IDMAX];
-	int			cl_idlen;
-	int			cl_naddr;
-	struct in_addr		cl_addr[NFSCLNT_ADDRMAX];
-	struct svc_uidmap *	cl_umap;
-	struct list_head	cl_export[NFSCLNT_EXPMAX];
-	struct list_head	cl_expfsid[NFSCLNT_EXPMAX];
-	struct list_head	cl_list;
 };
 
 struct svc_export {
 	struct list_head	ex_hash;
-	struct list_head	ex_fsid_hash;
-	struct list_head	ex_list;
-	char			ex_path[NFS_MAXPATHLEN+1];
-	struct svc_export *	ex_parent;
 	struct svc_client *	ex_client;
 	int			ex_flags;
 	struct vfsmount *	ex_mnt;
 	struct dentry *		ex_dentry;
-	dev_t			ex_dev;
-	ino_t			ex_ino;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
 	int			ex_fsid;
 };
 
+/* an "export key" (expkey) maps a filehandlefragement to an
+ * svc_export for a given client.  There can be two per export, one
+ * for type 0 (dev/ino), one for type 1 (fsid)
+ */
+struct svc_expkey {
+	struct list_head	ek_hash;
+
+	struct svc_client	*ek_client;
+	int			ek_fsidtype;
+	u32			ek_fsid[2];
+
+	struct svc_export	*ek_export;
+};
+
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
 #define EX_ISSYNC(exp)		(!((exp)->ex_flags & NFSEXP_ASYNC))
 #define EX_RDONLY(exp)		((exp)->ex_flags & NFSEXP_READONLY)
@@ -94,16 +92,25 @@
 void			exp_readunlock(void);
 struct svc_client *	exp_getclient(struct sockaddr_in *sin);
 void			exp_putclient(struct svc_client *clp);
-struct svc_export *	exp_get(struct svc_client *clp, dev_t dev, ino_t ino);
-struct svc_export *	exp_get_fsid(struct svc_client *clp, int fsid);
+struct svc_expkey *	exp_find_key(struct svc_client *clp, int fsid_type, u32 *fsidv);
 struct svc_export *	exp_get_by_name(struct svc_client *clp,
 					struct vfsmount *mnt,
 					struct dentry *dentry);
+struct svc_export *	exp_parent(struct svc_client *clp, struct vfsmount *mnt,
+				   struct dentry *dentry);
 int			exp_rootfh(struct svc_client *, 
 					char *path, struct knfsd_fh *, int maxsize);
 int			nfserrno(int errno);
-void			exp_nlmdetach(void);
 
+static inline struct svc_export *
+exp_find(struct svc_client *clp, int fsid_type, u32 *fsidv)
+{
+	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv);
+	if (ek)
+		return ek->ek_export;
+	else
+		return NULL;
+}
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
--- a/include/linux/nfsd/nfsfh.h	Sun Sep 15 19:19:57 2002
+++ b/include/linux/nfsd/nfsfh.h	Sun Sep 15 19:19:57 2002
@@ -199,6 +199,19 @@
 
 } svc_fh;
 
+static inline void mk_fsid_v0(u32 *fsidv, dev_t dev, ino_t ino)
+{
+	fsidv[0] = htonl((MAJOR(dev)<<16) |
+			MINOR(dev));
+	fsidv[1] = ino_t_to_u32(ino);
+}
+
+static inline void mk_fsid_v1(u32 *fsidv, u32 fsid)
+{
+	fsidv[0] = fsid;
+}
+
+
 /*
  * Shorthand for dprintk()'s
  */
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/page-flags.h	Sun Sep 15 19:19:29 2002
@@ -52,7 +52,7 @@
 #define PG_referenced		 2
 #define PG_uptodate		 3
 
-#define PG_dirty_dontuse	 4
+#define PG_dirty	 	 4
 #define PG_lru			 5
 #define PG_active		 6
 #define PG_slab			 7	/* slab debug (Suparna wants this) */
@@ -120,37 +120,11 @@
 #define SetPageUptodate(page)	set_bit(PG_uptodate, &(page)->flags)
 #define ClearPageUptodate(page)	clear_bit(PG_uptodate, &(page)->flags)
 
-#define PageDirty(page)		test_bit(PG_dirty_dontuse, &(page)->flags)
-#define SetPageDirty(page)						\
-	do {								\
-		if (!test_and_set_bit(PG_dirty_dontuse,			\
-					&(page)->flags))		\
-			inc_page_state(nr_dirty);			\
-	} while (0)
-#define TestSetPageDirty(page)						\
-	({								\
-		int ret;						\
-		ret = test_and_set_bit(PG_dirty_dontuse,		\
-				&(page)->flags);			\
-		if (!ret)						\
-			inc_page_state(nr_dirty);			\
-		ret;							\
-	})
-#define ClearPageDirty(page)						\
-	do {								\
-		if (test_and_clear_bit(PG_dirty_dontuse,		\
-				&(page)->flags))			\
-			dec_page_state(nr_dirty);			\
-	} while (0)
-#define TestClearPageDirty(page)					\
-	({								\
-		int ret;						\
-		ret = test_and_clear_bit(PG_dirty_dontuse,		\
-				&(page)->flags);			\
-		if (ret)						\
-			dec_page_state(nr_dirty);			\
-		ret;							\
-	})
+#define PageDirty(page)		test_bit(PG_dirty, &(page)->flags)
+#define SetPageDirty(page)	set_bit(PG_dirty, &(page)->flags)
+#define TestSetPageDirty(page)	test_and_set_bit(PG_dirty, &(page)->flags)
+#define ClearPageDirty(page)	clear_bit(PG_dirty, &(page)->flags)
+#define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags)
 
 #define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
 #define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
@@ -234,5 +208,12 @@
  */
 extern struct address_space swapper_space;
 #define PageSwapCache(page) ((page)->mapping == &swapper_space)
+
+int test_clear_page_dirty(struct page *page);
+
+static inline void clear_page_dirty(struct page *page)
+{
+	test_clear_page_dirty(page);
+}
 
 #endif	/* PAGE_FLAGS_H */
diff -Nru a/include/linux/pagevec.h b/include/linux/pagevec.h
--- a/include/linux/pagevec.h	Sun Sep 15 19:20:24 2002
+++ b/include/linux/pagevec.h	Sun Sep 15 19:20:24 2002
@@ -20,6 +20,7 @@
 void __pagevec_lru_add(struct pagevec *pvec);
 void lru_add_drain(void);
 void pagevec_deactivate_inactive(struct pagevec *pvec);
+void pagevec_strip(struct pagevec *pvec);
 
 static inline void pagevec_init(struct pagevec *pvec)
 {
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sun Sep 15 19:19:39 2002
+++ b/include/linux/pci.h	Sun Sep 15 19:19:39 2002
@@ -507,7 +507,7 @@
 	for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
 
 void pcibios_fixup_bus(struct pci_bus *);
-int pcibios_enable_device(struct pci_dev *);
+int pcibios_enable_device(struct pci_dev *, int mask);
 char *pcibios_setup (char *str);
 
 /* Used only when drivers/pci/setup.c is used */
@@ -600,6 +600,7 @@
 extern spinlock_t pci_lock;
 
 int pci_enable_device(struct pci_dev *dev);
+int pci_enable_device_bars(struct pci_dev *dev, int mask);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
@@ -623,9 +624,11 @@
 void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
-#define HAVE_PCI_REQ_REGIONS
+#define HAVE_PCI_REQ_REGIONS	2
 int pci_request_regions(struct pci_dev *, char *);
 void pci_release_regions(struct pci_dev *);
+int pci_request_region(struct pci_dev *, int, char *);
+void pci_release_region(struct pci_dev *, int);
 
 /* New-style probing supporting hot-pluggable devices */
 int pci_register_driver(struct pci_driver *);
@@ -634,7 +637,6 @@
 void pci_remove_device(struct pci_dev *);
 struct pci_driver *pci_dev_driver(const struct pci_dev *);
 const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
-void pci_announce_device_to_drivers(struct pci_dev *);
 unsigned int pci_do_scan_bus(struct pci_bus *bus);
 struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
 
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Sun Sep 15 19:19:37 2002
+++ b/include/linux/pci_ids.h	Sun Sep 15 19:19:37 2002
@@ -370,7 +370,7 @@
 #define PCI_DEVICE_ID_AMD_FE_GATE_7006	0x7006
 #define PCI_DEVICE_ID_AMD_FE_GATE_7007	0x7007
 #define PCI_DEVICE_ID_AMD_FE_GATE_700C	0x700C
-#define PCI_DEVIDE_ID_AMD_FE_GATE_700D	0x700D
+#define PCI_DEVICE_ID_AMD_FE_GATE_700D	0x700D
 #define PCI_DEVICE_ID_AMD_FE_GATE_700E	0x700E
 #define PCI_DEVICE_ID_AMD_FE_GATE_700F	0x700F
 #define PCI_DEVICE_ID_AMD_COBRA_7400	0x7400
@@ -386,10 +386,15 @@
 #define PCI_DEVICE_ID_AMD_VIPER_7413	0x7413
 #define PCI_DEVICE_ID_AMD_VIPER_7414	0x7414
 #define PCI_DEVICE_ID_AMD_OPUS_7440	0x7440
+#	define PCI_DEVICE_ID_AMD_VIPER_7440	PCI_DEVICE_ID_AMD_OPUS_7440
 #define PCI_DEVICE_ID_AMD_OPUS_7441	0x7441
+#	define PCI_DEVICE_ID_AMD_VIPER_7441	PCI_DEVICE_ID_AMD_OPUS_7441
 #define PCI_DEVICE_ID_AMD_OPUS_7443	0x7443
+#	define PCI_DEVICE_ID_AMD_VIPER_7443	PCI_DEVICE_ID_AMD_OPUS_7443
 #define PCI_DEVICE_ID_AMD_OPUS_7448	0x7448
+# define	PCI_DEVICE_ID_AMD_VIPER_7448	PCI_DEVICE_ID_AMD_OPUS_7448
 #define PCI_DEVICE_ID_AMD_OPUS_7449	0x7449
+#	define PCI_DEVICE_ID_AMD_VIPER_7449	PCI_DEVICE_ID_AMD_OPUS_7449
 #define PCI_DEVICE_ID_AMD_8111_LAN	0x7462
 #define PCI_DEVICE_ID_AMD_8111_IDE	0x7469
 #define PCI_DEVICE_ID_AMD_8111_AUDIO	0x746d
@@ -476,19 +481,28 @@
 #define PCI_DEVICE_ID_SI_635		0x0635
 #define PCI_DEVICE_ID_SI_640		0x0640
 #define PCI_DEVICE_ID_SI_645		0x0645
+#define PCI_DEVICE_ID_SI_646		0x0646
+#define PCI_DEVICE_ID_SI_648		0x0648
 #define PCI_DEVICE_ID_SI_650		0x0650
+#define PCI_DEVICE_ID_SI_651		0x0651
+#define PCI_DEVICE_ID_SI_652		0x0652
 #define PCI_DEVICE_ID_SI_730		0x0730
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
 #define PCI_DEVICE_ID_SI_730_VGA	0x7300
 #define PCI_DEVICE_ID_SI_735		0x0735
 #define PCI_DEVICE_ID_SI_740		0x0740
 #define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_746		0x0746
+#define PCI_DEVICE_ID_SI_748		0x0748
 #define PCI_DEVICE_ID_SI_750		0x0750
+#define PCI_DEVICE_ID_SI_751		0x0751
+#define PCI_DEVICE_ID_SI_752		0x0752
 #define PCI_DEVICE_ID_SI_900		0x0900
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5300		0x5300
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5518		0x5518
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5591		0x5591
 #define PCI_DEVICE_ID_SI_5597		0x5597
@@ -616,6 +630,7 @@
 #define PCI_DEVICE_ID_PROMISE_20268	0x4d68
 #define PCI_DEVICE_ID_PROMISE_20268R	0x6268
 #define PCI_DEVICE_ID_PROMISE_20269	0x4d69
+#define PCI_DEVICE_ID_PROMISE_20270	0x6268
 #define PCI_DEVICE_ID_PROMISE_20271	0x6269
 #define PCI_DEVICE_ID_PROMISE_20275	0x1275
 #define PCI_DEVICE_ID_PROMISE_20276	0x5275
@@ -742,6 +757,9 @@
 #define PCI_DEVICE_ID_CMD_670		0x0670
 #define PCI_DEVICE_ID_CMD_680		0x0680
 
+#define PCI_DEVICE_ID_SII_680		0x0680
+#define PCI_DEVICE_ID_SII_3112		0x3112
+
 #define PCI_VENDOR_ID_VISION		0x1098
 #define PCI_DEVICE_ID_VISION_QD8500	0x0001
 #define PCI_DEVICE_ID_VISION_QD8580	0x0002
@@ -989,6 +1007,7 @@
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112 
 #define PCI_DEVICE_ID_VIA_8233A		0x3147
+#define PCI_DEVICE_ID_VIA_8235		0x3177
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_8231		0x8231
 #define PCI_DEVICE_ID_VIA_8231_4	0x8235
@@ -1122,9 +1141,11 @@
 #define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4	  0x0200
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5	  0x0201
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6    0x0203
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230
@@ -1540,6 +1561,7 @@
 #define PCI_DEVICE_ID_TIGON3_5701	0x1645
 #define PCI_DEVICE_ID_TIGON3_5702	0x1646
 #define PCI_DEVICE_ID_TIGON3_5703	0x1647
+#define PCI_DEVICE_ID_TIGON3_5704	0x1648
 #define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
 #define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
 #define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
@@ -1575,6 +1597,9 @@
 #define PCI_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 
+#define PCI_VENDOR_ID_HINT             0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013
+
 #define PCI_VENDOR_ID_3DLABS		0x3d3d
 #define PCI_DEVICE_ID_3DLABS_300SX	0x0001
 #define PCI_DEVICE_ID_3DLABS_500TX	0x0002
@@ -1637,6 +1662,7 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_82562ET	0x1031
 #define PCI_DEVICE_ID_INTEL_82801CAM	0x1038
 #define PCI_DEVICE_ID_INTEL_82815_MC	0x1130
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/sched.h	Sun Sep 15 19:19:29 2002
@@ -27,6 +27,7 @@
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
 #include <linux/compiler.h>
+#include <linux/completion.h>
 
 struct exec_domain;
 
@@ -50,7 +51,11 @@
 #define CLONE_CLEARTID	0x00200000	/* clear the userspace TID */
 #define CLONE_DETACHED	0x00400000	/* parent wants no child-exit signal */
 
-#define CLONE_SIGNAL	(CLONE_SIGHAND | CLONE_THREAD)
+/*
+ * List of flags we want to share for kernel threads,
+ * if only because they are not used by them anyway.
+ */
+#define CLONE_KERNEL	(CLONE_FS | CLONE_FILES | CLONE_SIGHAND)
 
 /*
  * These are the constant used to fake the fixed-point load-average
@@ -128,8 +133,6 @@
 	int sched_priority;
 };
 
-struct completion;
-
 #ifdef __KERNEL__
 
 #include <linux/spinlock.h>
@@ -170,7 +173,8 @@
 /* Maximum number of active map areas.. This is a random (large) number */
 #define MAX_MAP_COUNT	(65536)
 
-struct kioctx;
+#include <linux/aio.h>
+
 struct mm_struct {
 	struct vm_area_struct * mmap;		/* list of VMAs */
 	rb_root_t mm_rb;
@@ -203,6 +207,8 @@
 	/* aio bits */
 	rwlock_t		ioctx_list_lock;
 	struct kioctx		*ioctx_list;
+
+	struct kioctx		default_kioctx;
 };
 
 extern int mmlist_nr;
@@ -216,6 +222,12 @@
         task_t                  *curr_target;
 
 	struct sigpending	shared_pending;
+
+	/* thread group exit support */
+	int			group_exit;
+	int			group_exit_code;
+
+	struct task_struct	*group_exit_task;
 };
 
 /*
@@ -311,6 +323,7 @@
 	struct task_struct *parent;	/* parent process */
 	struct list_head children;	/* list of my children */
 	struct list_head sibling;	/* linkage in my parent's children list */
+	struct task_struct *group_leader;
 	struct list_head thread_group;
 
 	/* PID hash table linkage. */
@@ -545,8 +558,10 @@
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
 extern void unblock_all_signals(void);
+extern void release_task(struct task_struct * p);
 extern int send_sig_info(int, struct siginfo *, struct task_struct *);
 extern int force_sig_info(int, struct siginfo *, struct task_struct *);
+extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
 extern int kill_pg_info(int, struct siginfo *, pid_t);
 extern int kill_sl_info(int, struct siginfo *, pid_t);
 extern int kill_proc_info(int, struct siginfo *, pid_t);
@@ -554,6 +569,7 @@
 extern void do_notify_parent(struct task_struct *, int);
 extern void force_sig(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
+extern int __broadcast_thread_group(struct task_struct *p, int sig);
 extern int kill_pg(pid_t, int, int);
 extern int kill_sl(pid_t, int, int);
 extern int kill_proc(pid_t, int, int);
@@ -660,6 +676,7 @@
 extern void exit_mm(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
+extern void __exit_sighand(struct task_struct *);
 extern void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig);
 
 extern void reparent_to_init(void);
@@ -750,14 +767,16 @@
 #define remove_parent(p)	list_del_init(&(p)->sibling)
 #define add_parent(p, parent)	list_add_tail(&(p)->sibling,&(parent)->children)
 
-#define REMOVE_LINKS(p) do {				\
-	list_del_init(&(p)->tasks);			\
-	remove_parent(p);				\
+#define REMOVE_LINKS(p) do {					\
+	if (thread_group_leader(p))				\
+		list_del_init(&(p)->tasks);			\
+	remove_parent(p);					\
 	} while (0)
 
-#define SET_LINKS(p) do {				\
-	list_add_tail(&(p)->tasks,&init_task.tasks);	\
-	add_parent(p, (p)->parent);			\
+#define SET_LINKS(p) do {					\
+	if (thread_group_leader(p))				\
+		list_add_tail(&(p)->tasks,&init_task.tasks);	\
+	add_parent(p, (p)->parent);				\
 	} while (0)
 
 static inline struct task_struct *eldest_child(struct task_struct *p)
@@ -787,11 +806,18 @@
 #define next_task(p)	list_entry((p)->tasks.next, struct task_struct, tasks)
 #define prev_task(p)	list_entry((p)->tasks.prev, struct task_struct, tasks)
 
-#define for_each_task(p) \
+#define for_each_process(p) \
 	for (p = &init_task ; (p = next_task(p)) != &init_task ; )
 
-#define for_each_thread(task) \
-	for (task = next_thread(current) ; task != current ; task = next_thread(task))
+/*
+ * Careful: do_each_thread/while_each_thread is a double loop so
+ *          'break' will not work as expected - use goto instead.
+ */
+#define do_each_thread(g, t) \
+	for (g = t = &init_task ; (g = t = next_task(g)) != &init_task ; ) do
+
+#define while_each_thread(g, t) \
+	while ((t = next_thread(t)) != g)
 
 static inline task_t *next_thread(task_t *p)
 {
@@ -818,6 +844,9 @@
 }
 
 #define thread_group_leader(p)	(p->pid == p->tgid)
+
+#define delay_group_leader(p) \
+	(p->tgid == p->pid && !list_empty(&p->thread_group))
 
 extern void unhash_process(struct task_struct *p);
 
diff -Nru a/include/linux/serial.h b/include/linux/serial.h
--- a/include/linux/serial.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/serial.h	Sun Sep 15 19:19:29 2002
@@ -80,7 +80,6 @@
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1
 #define SERIAL_IO_MEM	2
-#define SERIAL_IO_GSC	3
 
 struct serial_uart_config {
 	char	*name;
diff -Nru a/include/linux/time.h b/include/linux/time.h
--- a/include/linux/time.h	Sun Sep 15 19:19:56 2002
+++ b/include/linux/time.h	Sun Sep 15 19:19:56 2002
@@ -113,7 +113,7 @@
 	)*60 + sec; /* finally seconds */
 }
 
-extern struct timeval xtime;
+extern struct timespec xtime;
 
 #define CURRENT_TIME (xtime.tv_sec)
 
diff -Nru a/include/linux/timex.h b/include/linux/timex.h
--- a/include/linux/timex.h	Sun Sep 15 19:19:28 2002
+++ b/include/linux/timex.h	Sun Sep 15 19:19:28 2002
@@ -155,6 +155,28 @@
 /* LATCH is used in the interval timer and ftape setup. */
 #define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
 
+/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
+ * improve accuracy by shifting LSH bits, hence calculating:
+ *     (NOM << LSH) / DEN
+ * This however means trouble for large NOM, because (NOM << LSH) may no
+ * longer fit in 32 bits. The following way of calculating this gives us
+ * some slack, under the following onditions:
+ *   - (NOM / DEN) fits in (32 - LSH) bits.
+ *   - (NOM % DEN) fits in (32 - LSH) bits.
+ */
+#define SH_DIV(NOM,DEN,LSH) (   ((NOM / DEN) << LSH)                    \
+                             + (((NOM % DEN) << LSH) + DEN / 2) / DEN)
+
+/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
+#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
+
+/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
+#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
+
+/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ and	*/
+/* a value TUSEC for TICK_USEC (can be set bij adjtimex)		*/
+#define TICK_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8))
+
 /*
  * syscall interface - used (mainly by NTP daemon)
  * to discipline kernel clock oscillator
@@ -251,7 +273,8 @@
  * Note: maximum error = NTP synch distance = dispersion + delay / 2;
  * estimated error = NTP dispersion.
  */
-extern long tick;                      /* timer interrupt period */
+extern unsigned long tick_usec;		/* USER_HZ period (usec) */
+extern unsigned long tick_nsec;		/* ACTHZ          period (nsec) */
 extern int tickadj;			/* amount of adjustment per tick */
 
 /*
diff -Nru a/include/linux/uio.h b/include/linux/uio.h
--- a/include/linux/uio.h	Sun Sep 15 19:19:29 2002
+++ b/include/linux/uio.h	Sun Sep 15 19:19:29 2002
@@ -34,4 +34,19 @@
                                 /* Beg pardon: BSD has 1024 --ANK */
 #endif
 
+/*
+ * Total number of bytes covered by an iovec
+ */
+static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
+{
+	unsigned long seg;
+	size_t ret = 0;
+
+	for (seg = 0; seg < nr_segs; seg++)
+		ret += iov[seg].iov_len;
+	return ret;
+}
+
+unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to);
+
 #endif
diff -Nru a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h
--- a/include/net/llc_c_ev.h	Sun Sep 15 19:19:29 2002
+++ b/include/net/llc_c_ev.h	Sun Sep 15 19:19:29 2002
@@ -122,27 +122,14 @@
 
 /* Event LLC_CONN_EV_TYPE_PDU interface */
 struct llc_conn_ev_pdu_if {
-	u8		ev;
-	u8		reason;
-};
-
-/* Event interface for timer-generated events */
-struct llc_conn_ev_tmr_if {
-	struct sock *sk;
-	u32	     component_handle;
-	void	    *timer_specific;
-};
-
-struct llc_conn_ev_rpt_sts_if {
-	u8 status;
+	u8 ev;
+	u8 reason;
 };
 
 union llc_conn_ev_if {
 	struct llc_conn_ev_simple_if  a;	/* 'a' for simple, easy ... */
 	struct llc_conn_ev_prim_if    prim;
 	struct llc_conn_ev_pdu_if     pdu;
-	struct llc_conn_ev_tmr_if     tmr;
-	struct llc_conn_ev_rpt_sts_if rsts;	/* report status */
 };
 
 struct llc_conn_state_ev {
diff -Nru a/include/net/llc_c_st.h b/include/net/llc_c_st.h
--- a/include/net/llc_c_st.h	Sun Sep 15 19:20:08 2002
+++ b/include/net/llc_c_st.h	Sun Sep 15 19:20:08 2002
@@ -33,15 +33,15 @@
 
 /* Connection state table structure */
 struct llc_conn_state_trans {
-   llc_conn_ev_t       ev;
-   u8		       next_state;
-   llc_conn_ev_qfyr_t *ev_qualifiers;
-   llc_conn_action_t  *ev_actions;
+	llc_conn_ev_t	   ev;
+	u8		   next_state;
+	llc_conn_ev_qfyr_t *ev_qualifiers;
+	llc_conn_action_t  *ev_actions;
 };
 
 struct llc_conn_state {
-   u8 current_state;
-   struct llc_conn_state_trans **transitions;
+	u8			    current_state;
+	struct llc_conn_state_trans **transitions;
 };
 
 extern struct llc_conn_state llc_conn_state_table[];
diff -Nru a/include/net/llc_conn.h b/include/net/llc_conn.h
--- a/include/net/llc_conn.h	Sun Sep 15 19:20:23 2002
+++ b/include/net/llc_conn.h	Sun Sep 15 19:20:23 2002
@@ -2,7 +2,7 @@
 #define LLC_CONN_H
 /*
  * Copyright (c) 1997 by Procom Technology, Inc.
- * 		 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * 		 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
  * This program can be redistributed or modified under the terms of the
  * GNU General Public License as published by the Free Software Foundation.
@@ -13,19 +13,17 @@
  */
 #include <linux/timer.h>
 #include <net/llc_if.h>
-
-#undef DEBUG_LLC_CONN_ALLOC
+#include <linux/llc.h>
 
 struct llc_timer {
 	struct timer_list timer;
-	u8		  running;	/* timer is running or no */
 	u16		  expire;	/* timer expire time */
 };
 
 struct llc_opt {
 	struct list_head    node;		/* entry in sap->sk_list.list */
 	struct sock	    *sk;		/* sock that has this llc_opt */
-	void		    *handler;		/* for upper layers usage */
+	struct sockaddr_llc addr;		/* address sock is bound to */
 	u8		    state;		/* state of connection */
 	struct llc_sap	    *sap;		/* pointer to parent SAP */
 	struct llc_addr	    laddr;		/* lsap/mac pair */
@@ -80,63 +78,14 @@
 
 struct llc_conn_state_ev;
 
-extern struct sock *__llc_sock_alloc(void);
-extern void __llc_sock_free(struct sock *sk, u8 free);
-
-#ifdef DEBUG_LLC_CONN_ALLOC
-#define dump_stack() printk(KERN_INFO "call trace: %p, %p, %p\n",	\
-				__builtin_return_address(0),		\
-				__builtin_return_address(1),		\
-				__builtin_return_address(2));
-#define llc_sock_alloc()	({					\
-	struct sock *__sk = __llc_sock_alloc();				\
-	if (__sk) {							\
-		llc_sk(__sk)->f_alloc = __FUNCTION__;			\
-		llc_sk(__sk)->l_alloc = __LINE__;			\
-	}								\
-	__sk;})
-#define __llc_sock_assert(__sk)						\
-	if (llc_sk(__sk)->f_free) {					\
-		printk(KERN_ERR						\
-		       "%p conn (alloc'd @ %s(%d)) "			\
-		       "already freed @ %s(%d) "			\
-		       "being used again @ %s(%d)\n",			\
-		       llc_sk(__sk),					\
-		       llc_sk(__sk)->f_alloc, llc_sk(__sk)->l_alloc,	\
-		       llc_sk(__sk)->f_free, llc_sk(__sk)->l_free,	\
-		       __FUNCTION__, __LINE__);				\
-		dump_stack();
-#define llc_sock_free(__sk)						\
-{									\
-	__llc_sock_assert(__sk)						\
-	} else {							\
-		__llc_sock_free(__sk, 0);				\
-		llc_sk(__sk)->f_free = __FUNCTION__;			\
-		llc_sk(__sk)->l_free = __LINE__;			\
-	}								\
-}
-#define llc_sock_assert(__sk)						\
-{									\
-	__llc_sock_assert(__sk);					\
-	return; }							\
-}
-#define llc_sock_assert_ret(__sk, __ret)				\
-{									\
-	__llc_sock_assert(__sk);					\
-	return __ret; }							\
-}
-#else /* DEBUG_LLC_CONN_ALLOC */
-#define llc_sock_alloc() __llc_sock_alloc()
-#define llc_sock_free(__sk) __llc_sock_free(__sk, 1)
-#define llc_sock_assert(__sk)
-#define llc_sock_assert_ret(__sk)
-#endif /* DEBUG_LLC_CONN_ALLOC */
+extern struct sock *llc_sk_alloc(int family, int priority);
+extern void llc_sk_free(struct sock *sk);
 
-extern void llc_sock_reset(struct sock *sk);
-extern int llc_sock_init(struct sock *sk);
+extern void llc_sk_reset(struct sock *sk);
+extern int llc_sk_init(struct sock *sk);
 
 /* Access to a connection */
-extern int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
 extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
 extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb);
 extern void llc_conn_free_ev(struct sk_buff *skb);
@@ -146,8 +95,11 @@
 					 u8 first_f_bit);
 extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr,
 				      u16 *how_many_unacked);
-extern struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
-				  struct llc_addr *laddr);
+extern struct sock *llc_lookup_established(struct llc_sap *sap,
+					   struct llc_addr *daddr,
+					   struct llc_addr *laddr);
+extern struct sock *llc_lookup_listener(struct llc_sap *sap,
+					struct llc_addr *laddr);
 extern u8 llc_data_accept_state(u8 state);
 extern void llc_build_offset_table(void);
 #endif /* LLC_CONN_H */
diff -Nru a/include/net/llc_evnt.h b/include/net/llc_evnt.h
--- a/include/net/llc_evnt.h	Sun Sep 15 19:19:29 2002
+++ b/include/net/llc_evnt.h	Sun Sep 15 19:19:29 2002
@@ -43,29 +43,18 @@
 
 struct llc_stat_ev_pdu_if {
 	u8 reason;
-	struct sk_buff *skb;
-};
-
-struct llc_stat_ev_tmr_if {
-	void *timer_specific;
-};
-
-struct llc_stat_ev_rpt_sts_if {
-	u8 status;
 };
 
 union llc_stat_ev_if {
 	struct llc_stat_ev_simple_if  a;	/* 'a' for simple, easy ... */
 	struct llc_stat_ev_prim_if    prim;
 	struct llc_stat_ev_pdu_if     pdu;
-	struct llc_stat_ev_tmr_if     tmr;
-	struct llc_stat_ev_rpt_sts_if rsts;	/* report status */
 };
 
 struct llc_station_state_ev {
-	u8			type;
+	u8		     type;
 	union llc_stat_ev_if data;
-	struct list_head	node; /* node in station->ev_q.list */
+	struct list_head     node; /* node in station->ev_q.list */
 };
 
 static __inline__ struct llc_station_state_ev *
diff -Nru a/include/net/llc_if.h b/include/net/llc_if.h
--- a/include/net/llc_if.h	Sun Sep 15 19:19:28 2002
+++ b/include/net/llc_if.h	Sun Sep 15 19:19:28 2002
@@ -14,13 +14,15 @@
 /* Defines LLC interface to network layer */
 /* Available primitives */
 #include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/llc.h>
 
 #define LLC_DATAUNIT_PRIM	0
 #define LLC_CONN_PRIM		1
 #define LLC_DATA_PRIM		2
 #define LLC_DISC_PRIM		3
 #define LLC_RESET_PRIM		4
-#define LLC_FLOWCONTROL_PRIM	5
+#define LLC_FLOWCONTROL_PRIM	5 /* Not supported at this time */
 #define LLC_DISABLE_PRIM	6
 #define LLC_XID_PRIM		7
 #define LLC_TEST_PRIM		8
@@ -65,46 +67,12 @@
 	u8 mac[IFHWADDRLEN];
 };
 
-/* Primitive-specific data */
-struct llc_prim_conn {
-	struct llc_addr	   saddr;	/* used by request only */
-	struct llc_addr	   daddr;	/* used by request only */
-	u8		   status;	/* reason for failure */
-	u8		   pri;		/* service_class */
-	struct net_device *dev;
-	struct sock	  *sk;		/* returned from REQUEST */
-	void		  *handler;	/* upper layer use,
-					   stored in llc_opt->handler */
-	u16		   link;
-	struct sk_buff	  *skb;		/* received SABME  */
-};
-
-struct llc_prim_disc {
-	struct sock *sk;
-	u16	     link;
-	u8	     reason;		/* not used by request */
-};
-
 struct llc_prim_reset {
 	struct sock *sk;
 	u16	     link;
 	u8	     reason;		/* used only by indicate */
 };
 
-struct llc_prim_flow_ctrl {
-	struct sock *sk;
-	u16	     link;
-	u32	     amount;
-};
-
-struct llc_prim_data {
-	struct sock    *sk;
-	u16		link;
-	u8		pri;
-	struct sk_buff *skb;		/* pointer to frame */
-	u8	 	status;		/* reason */
-};
-
  /* Sending data in conection-less mode */
 struct llc_prim_unit_data {
 	struct llc_addr	saddr;
@@ -129,11 +97,7 @@
 };
 
 union llc_u_prim_data {
-	struct llc_prim_conn	  conn;
-	struct llc_prim_disc	  disc;
 	struct llc_prim_reset	  res;
-	struct llc_prim_flow_ctrl fc;
-	struct llc_prim_data	  data;		/* data */
 	struct llc_prim_unit_data udata;	/* unit data */
 	struct llc_prim_xid	  xid;
 	struct llc_prim_test	  test;
@@ -152,4 +116,18 @@
 extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate,
 				    llc_prim_call_t network_confirm, u8 lsap);
 extern void llc_sap_close(struct llc_sap *sap);
+
+extern int llc_establish_connection(struct sock *sk, u8 *lmac,
+				    u8 *dmac, u8 dsap);
+extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb);
+extern void llc_build_and_send_ui_pkt(struct llc_sap *sap,
+				      struct sk_buff *skb,
+				      u8 *dmac, u8 dsap);
+extern void llc_build_and_send_xid_pkt(struct llc_sap *sap,
+				       struct sk_buff *skb,
+				       u8 *dmac, u8 dsap);
+extern void llc_build_and_send_test_pkt(struct llc_sap *sap,
+					struct sk_buff *skb,
+					u8 *dmac, u8 dsap);
+extern int llc_send_disc(struct sock *sk);
 #endif /* LLC_IF_H */
diff -Nru a/include/net/llc_mac.h b/include/net/llc_mac.h
--- a/include/net/llc_mac.h	Sun Sep 15 19:19:29 2002
+++ b/include/net/llc_mac.h	Sun Sep 15 19:19:29 2002
@@ -2,7 +2,7 @@
 #define LLC_MAC_H
 /*
  * Copyright (c) 1997 by Procom Technology, Inc.
- * 		 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * 		 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
  * This program can be redistributed or modified under the terms of the
  * GNU General Public License as published by the Free Software Foundation.
@@ -13,13 +13,12 @@
  */
 /* Defines MAC-layer interface to LLC layer */
 extern int mac_send_pdu(struct sk_buff *skb);
-extern int mac_indicate(struct sk_buff *skb, struct net_device *dev,
-			struct packet_type *pt);
+extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt);
 extern struct net_device *mac_dev_peer(struct net_device *current_dev,
 				       int type, u8 *mac);
-extern int llc_pdu_router(struct llc_sap *sap, struct sock *sk,
-			  struct sk_buff *skb, u8 type);
 extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da);
+extern int llc_conn_rcv(struct sock *sk, struct sk_buff *skb);
 
 static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type)
 {
@@ -31,4 +30,36 @@
 	return skb->cb[sizeof(skb->cb) - 1];
 }
 
+extern u8 llc_mac_null_var[IFHWADDRLEN];
+
+/**
+ *      llc_mac_null - determines if a address is a null mac address
+ *      @mac: Mac address to test if null.
+ *
+ *      Determines if a given address is a null mac address.  Returns 0 if the
+ *      address is not a null mac, 1 if the address is a null mac.
+ */
+static __inline__ int llc_mac_null(u8 *mac)
+{
+	return !memcmp(mac, llc_mac_null_var, IFHWADDRLEN);
+}
+
+static __inline__ int llc_addrany(struct llc_addr *addr)
+{
+	return llc_mac_null(addr->mac) && !addr->lsap;
+}
+
+/**
+ *	llc_mac_match - determines if two mac addresses are the same
+ *	@mac1: First mac address to compare.
+ *	@mac2: Second mac address to compare.
+ *
+ *	Determines if two given mac address are the same.  Returns 0 if there
+ *	is not a complete match up to len, 1 if a complete match up to len is
+ *	found.
+ */
+static __inline__ int llc_mac_match(u8 *mac1, u8 *mac2)
+{
+	return !memcmp(mac1, mac2, IFHWADDRLEN);
+}
 #endif /* LLC_MAC_H */
diff -Nru a/include/net/llc_main.h b/include/net/llc_main.h
--- a/include/net/llc_main.h	Sun Sep 15 19:19:34 2002
+++ b/include/net/llc_main.h	Sun Sep 15 19:19:34 2002
@@ -30,7 +30,6 @@
  *
  * @state - state of station
  * @xid_r_count - XID response PDU counter
- * @ack_tmr_running - 1 or 0
  * @mac_sa - MAC source address
  * @sap_list - list of related SAPs
  * @ev_q - events entering state mach.
@@ -40,7 +39,6 @@
 	u8			    state;
 	u8			    xid_r_count;
 	struct timer_list	    ack_timer;
-	u8			    ack_tmr_running;
 	u8			    retry_count;
 	u8			    maximum_retry;
 	u8			    mac_sa[6];
@@ -61,8 +59,8 @@
 extern void llc_free_sap(struct llc_sap *sap);
 extern struct llc_sap *llc_sap_find(u8 lsap);
 extern struct llc_station *llc_station_get(void);
-extern void llc_station_send_ev(struct llc_station *station,
-				struct sk_buff *skb);
+extern void llc_station_state_process(struct llc_station *station,
+				      struct sk_buff *skb);
 extern void llc_station_send_pdu(struct llc_station *station,
 				 struct sk_buff *skb);
 extern struct sk_buff *llc_alloc_frame(void);
diff -Nru a/include/net/llc_pdu.h b/include/net/llc_pdu.h
--- a/include/net/llc_pdu.h	Sun Sep 15 19:19:29 2002
+++ b/include/net/llc_pdu.h	Sun Sep 15 19:19:29 2002
@@ -237,35 +237,35 @@
 
 extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type);
 extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value);
-extern int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit);
-extern int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit);
-extern int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa);
-extern int llc_pdu_decode_da(struct sk_buff *skb, u8 *ds);
-extern int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap);
-extern int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap);
-extern int llc_decode_pdu_type(struct sk_buff *skb, u8 *destination);
+extern void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit);
+extern void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit);
+extern void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa);
+extern void llc_pdu_decode_da(struct sk_buff *skb, u8 *ds);
+extern void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap);
+extern void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap);
+extern void llc_decode_pdu_type(struct sk_buff *skb, u8 *destination);
 extern void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap,
 				u8 dsap, u8 cr);
-extern int llc_pdu_init_as_ui_cmd(struct sk_buff *skb);
-extern int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
+extern void llc_pdu_init_as_ui_cmd(struct sk_buff *skb);
+extern void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
 				   u8 rx_window);
-extern int llc_pdu_init_as_test_cmd(struct sk_buff *skb);
-extern int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit);
-extern int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr);
-extern int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
-extern int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
-extern int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
-extern int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit);
-extern int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit);
-extern int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
-				   u8 rx_window);
-extern int llc_pdu_init_as_test_rsp(struct sk_buff *skb,
-				    struct sk_buff *ev_skb);
-extern int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb,
-				    struct llc_pdu_sn *prev_pdu,
-				    u8 f_bit, u8 vs, u8 vr, u8 vzyxw);
-extern int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
-extern int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
-extern int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
-extern int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit);
+extern void llc_pdu_init_as_test_cmd(struct sk_buff *skb);
+extern void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit);
+extern void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr);
+extern void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
+extern void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
+extern void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
+extern void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit);
+extern void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit);
+extern void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
+				    u8 rx_window);
+extern void llc_pdu_init_as_test_rsp(struct sk_buff *skb,
+				     struct sk_buff *ev_skb);
+extern void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb,
+				     struct llc_pdu_sn *prev_pdu,
+				     u8 f_bit, u8 vs, u8 vr, u8 vzyxw);
+extern void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
+extern void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
+extern void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
+extern void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit);
 #endif /* LLC_PDU_H */
diff -Nru a/include/net/llc_s_ev.h b/include/net/llc_s_ev.h
--- a/include/net/llc_s_ev.h	Sun Sep 15 19:19:29 2002
+++ b/include/net/llc_s_ev.h	Sun Sep 15 19:19:29 2002
@@ -52,20 +52,10 @@
 	u8 reason;
 };
 
-struct llc_sap_ev_tmr_if {
-	void *timer_specific;
-};
-
-struct llc_sap_ev_rpt_sts_if {
-	u8 status;
-};
-
 union llc_sap_ev_if {
 	struct llc_sap_ev_simple_if	a;	/* 'a' for simple, easy ... */
 	struct llc_sap_ev_prim_if	prim;
 	struct llc_sap_ev_pdu_if	pdu;
-	struct llc_sap_ev_tmr_if	tmr;
-	struct llc_sap_ev_rpt_sts_if	rsts;	/* report status */
 };
 
 struct llc_prim_if_block;
diff -Nru a/include/net/llc_sap.h b/include/net/llc_sap.h
--- a/include/net/llc_sap.h	Sun Sep 15 19:19:28 2002
+++ b/include/net/llc_sap.h	Sun Sep 15 19:19:28 2002
@@ -17,8 +17,6 @@
  *
  * @p_bit - only lowest-order bit used
  * @f_bit - only lowest-order bit used
- * @req - provided by LLC layer
- * @resp - provided by LLC layer
  * @ind - provided by network layer
  * @conf - provided by network layer
  * @laddr - SAP value in this 'lsap'
@@ -31,8 +29,6 @@
 	u8			 state;
 	u8			 p_bit;
 	u8			 f_bit;
-	llc_prim_call_t		 req;
-	llc_prim_call_t		 resp;
 	llc_prim_call_t		 ind;
 	llc_prim_call_t		 conf;
 	struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
@@ -49,7 +45,7 @@
 
 extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk);
 extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
-extern void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb);
+extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
 #endif /* LLC_SAP_H */
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Sun Sep 15 19:19:29 2002
+++ b/init/main.c	Sun Sep 15 19:19:29 2002
@@ -38,10 +38,6 @@
 #include <asm/s390mach.h>
 #endif
 
-#ifdef CONFIG_MTRR
-#  include <asm/mtrr.h>
-#endif
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
@@ -375,7 +371,7 @@
 
 static void rest_init(void)
 {
-	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	kernel_thread(init, NULL, CLONE_KERNEL);
 	unlock_kernel();
  	cpu_idle();
 } 
@@ -490,15 +486,6 @@
  */
 static void __init do_basic_setup(void)
 {
-#if defined(CONFIG_MTRR)	/* Do this after SMP initialization */
-/*
- * We should probably create some architecture-dependent "fixup after
- * everything is up" style function where this would belong better
- * than in init/main.c..
- */
-	mtrr_init();
-#endif
-
 #ifdef CONFIG_SYSCTL
 	sysctl_init();
 #endif
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	Sun Sep 15 19:19:46 2002
+++ b/ipc/shm.c	Sun Sep 15 19:19:46 2002
@@ -154,13 +154,13 @@
 }
 
 static struct file_operations shm_file_operations = {
-	mmap:	shm_mmap
+	.mmap	= shm_mmap
 };
 
 static struct vm_operations_struct shm_vm_ops = {
-	open:	shm_open,	/* callback for a new vm-area open */
-	close:	shm_close,	/* callback for when the vm-area is released */
-	nopage:	shmem_nopage,
+	.open	= shm_open,	/* callback for a new vm-area open */
+	.close	= shm_close,	/* callback for when the vm-area is released */
+	.nopage	= shmem_nopage,
 };
 
 static int newseg (key_t key, int shmflg, size_t size)
diff -Nru a/kernel/capability.c b/kernel/capability.c
--- a/kernel/capability.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/capability.c	Sun Sep 15 19:19:29 2002
@@ -83,13 +83,13 @@
 			      kernel_cap_t *inheritable,
 			      kernel_cap_t *permitted)
 {
-     task_t *target;
+     task_t *g, *target;
 
-     for_each_task(target) {
+     do_each_thread(g, target) {
              if (target->pgrp != pgrp)
                      continue;
 	     security_ops->capset_set(target, effective, inheritable, permitted);
-     }
+     } while_each_thread(g, target);
 }
 
 /*
@@ -100,13 +100,13 @@
 			       kernel_cap_t *inheritable,
 			       kernel_cap_t *permitted)
 {
-     task_t *target;
+     task_t *g, *target;
 
-     for_each_task(target) {
+     do_each_thread(g, target) {
              if (target == current || target->pid == 1)
                      continue;
 	     security_ops->capset_set(target, effective, inheritable, permitted);
-     }
+     } while_each_thread(g, target);
 }
 
 /*
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Sun Sep 15 19:19:30 2002
+++ b/kernel/exit.c	Sun Sep 15 19:19:30 2002
@@ -29,10 +29,9 @@
 
 int getrusage(struct task_struct *, int, struct rusage *);
 
-static inline void __unhash_process(struct task_struct *p)
+static struct dentry * __unhash_process(struct task_struct *p)
 {
 	struct dentry *proc_dentry;
-	write_lock_irq(&tasklist_lock);
 	nr_threads--;
 	unhash_pid(p);
 	REMOVE_LINKS(p);
@@ -47,15 +46,13 @@
 			proc_dentry = NULL;
 		spin_unlock(&dcache_lock);
 	}
-	write_unlock_irq(&tasklist_lock);
-	if (unlikely(proc_dentry != NULL)) {
-		shrink_dcache_parent(proc_dentry);
-		dput(proc_dentry);
-	}
+	return proc_dentry;
 }
 
-static void release_task(struct task_struct * p)
+void release_task(struct task_struct * p)
 {
+	struct dentry *proc_dentry;
+
 	if (p->state != TASK_ZOMBIE)
 		BUG();
 #ifdef CONFIG_SMP
@@ -71,16 +68,22 @@
 		write_unlock_irq(&tasklist_lock);
 	}
 	BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children));
-	unhash_process(p);
-	exit_sighand(p);
+	write_lock_irq(&tasklist_lock);
+	__exit_sighand(p);
+	proc_dentry = __unhash_process(p);
+	p->parent->cutime += p->utime + p->cutime;
+	p->parent->cstime += p->stime + p->cstime;
+	p->parent->cmin_flt += p->min_flt + p->cmin_flt;
+	p->parent->cmaj_flt += p->maj_flt + p->cmaj_flt;
+	p->parent->cnswap += p->nswap + p->cnswap;
+	sched_exit(p);
+	write_unlock_irq(&tasklist_lock);
 
-	release_thread(p);
-	if (p != current) {
-		current->cmin_flt += p->min_flt + p->cmin_flt;
-		current->cmaj_flt += p->maj_flt + p->cmaj_flt;
-		current->cnswap += p->nswap + p->cnswap;
-		sched_exit(p);
+	if (unlikely(proc_dentry != NULL)) {
+		shrink_dcache_parent(proc_dentry);
+		dput(proc_dentry);
 	}
+	release_thread(p);
 	put_task_struct(p);
 }
 
@@ -88,7 +91,16 @@
 
 void unhash_process(struct task_struct *p)
 {
-	return __unhash_process(p);
+	struct dentry *proc_dentry;
+
+	write_lock_irq(&tasklist_lock);
+	proc_dentry = __unhash_process(p);
+	write_unlock_irq(&tasklist_lock);
+
+	if (unlikely(proc_dentry != NULL)) {
+		shrink_dcache_parent(proc_dentry);
+		dput(proc_dentry);
+	}
 }
 
 /*
@@ -103,7 +115,7 @@
 
 	fallback = -1;
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
  		if (p->session <= 0)
  			continue;
 		if (p->pgrp == pgrp) {
@@ -125,38 +137,45 @@
  *
  * "I ask you, have you ever known what it is to be an orphan?"
  */
-static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
+static int __will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
 {
 	struct task_struct *p;
 
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
 		if ((p == ignored_task) || (p->pgrp != pgrp) ||
 		    (p->state == TASK_ZOMBIE) ||
 		    (p->parent->pid == 1))
 			continue;
 		if ((p->parent->pgrp != pgrp) &&
 		    (p->parent->session == p->session)) {
-			read_unlock(&tasklist_lock);
  			return 0;
 		}
 	}
-	read_unlock(&tasklist_lock);
 	return 1;	/* (sighing) "Often!" */
 }
 
+static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
+{
+	int retval;
+
+	read_lock(&tasklist_lock);
+	retval = __will_become_orphaned_pgrp(pgrp, ignored_task);
+	read_unlock(&tasklist_lock);
+
+	return retval;
+}
+
 int is_orphaned_pgrp(int pgrp)
 {
 	return will_become_orphaned_pgrp(pgrp, 0);
 }
 
-static inline int has_stopped_jobs(int pgrp)
+static inline int __has_stopped_jobs(int pgrp)
 {
 	int retval = 0;
 	struct task_struct * p;
 
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	for_each_process(p) {
 		if (p->pgrp != pgrp)
 			continue;
 		if (p->state != TASK_STOPPED)
@@ -164,7 +183,17 @@
 		retval = 1;
 		break;
 	}
+	return retval;
+}
+
+static inline int has_stopped_jobs(int pgrp)
+{
+	int retval;
+
+	read_lock(&tasklist_lock);
+	retval = __has_stopped_jobs(pgrp);
 	read_unlock(&tasklist_lock);
+
 	return retval;
 }
 
@@ -253,6 +282,8 @@
 		p->real_parent = child_reaper;
 	else
 		p->real_parent = reaper;
+	if (p->parent == p->real_parent)
+		BUG();
 
 	if (p->pdeath_signal)
 		send_sig(p->pdeath_signal, p, 0);
@@ -416,13 +447,7 @@
 	struct task_struct *p, *reaper = father;
 	struct list_head *_p;
 
-	write_lock_irq(&tasklist_lock);
-
-	if (father->exit_signal != -1)
-		reaper = prev_thread(reaper);
-	else
-		reaper = child_reaper;
-
+	reaper = father->group_leader;
 	if (reaper == father)
 		reaper = child_reaper;
 
@@ -436,13 +461,13 @@
 	 */
 	list_for_each(_p, &father->children) {
 		p = list_entry(_p,struct task_struct,sibling);
-		reparent_thread(p, reaper, child_reaper);
+		if (father == p->real_parent)
+			reparent_thread(p, reaper, child_reaper);
 	}
 	list_for_each(_p, &father->ptrace_children) {
 		p = list_entry(_p,struct task_struct,ptrace_list);
 		reparent_thread(p, reaper, child_reaper);
 	}
-	write_unlock_irq(&tasklist_lock);
 }
 
 static inline void zap_thread(task_t *p, task_t *father, int traced)
@@ -457,9 +482,16 @@
 		p->ptrace = ptrace_flag;
 		__ptrace_link(p, trace_task);
 	} else {
-		/* Otherwise, if we were tracing this thread, untrace it.  */
+		/*
+		 * Otherwise, if we were tracing this thread, untrace it.
+		 * If we were only tracing the thread (i.e. not its real
+		 * parent), stop here.
+		 */
 		ptrace_unlink (p);
-
+		if (p->parent != father) {
+			BUG_ON(p->parent != p->real_parent);
+			return;
+		}
 		list_del_init(&p->sibling);
 		p->parent = p->real_parent;
 		list_add_tail(&p->sibling, &p->parent->children);
@@ -477,12 +509,10 @@
 	    (p->session == current->session)) {
 		int pgrp = p->pgrp;
 
-		write_unlock_irq(&tasklist_lock);
-		if (is_orphaned_pgrp(pgrp) && has_stopped_jobs(pgrp)) {
-			kill_pg(pgrp,SIGHUP,1);
-			kill_pg(pgrp,SIGCONT,1);
+		if (__will_become_orphaned_pgrp(pgrp, 0) && __has_stopped_jobs(pgrp)) {
+			__kill_pg_info(SIGHUP, (void *)1, pgrp);
+			__kill_pg_info(SIGCONT, (void *)1, pgrp);
 		}
-		write_lock_irq(&tasklist_lock);
 	}
 }
 
@@ -493,7 +523,8 @@
 static void exit_notify(void)
 {
 	struct task_struct *t;
-	struct list_head *_p, *_n;
+
+	write_lock_irq(&tasklist_lock);
 
 	forget_original_parent(current);
 	/*
@@ -510,10 +541,10 @@
 	
 	if ((t->pgrp != current->pgrp) &&
 	    (t->session == current->session) &&
-	    will_become_orphaned_pgrp(current->pgrp, current) &&
-	    has_stopped_jobs(current->pgrp)) {
-		kill_pg(current->pgrp,SIGHUP,1);
-		kill_pg(current->pgrp,SIGCONT,1);
+	    __will_become_orphaned_pgrp(current->pgrp, current) &&
+	    __has_stopped_jobs(current->pgrp)) {
+		__kill_pg_info(SIGHUP, (void *)1, current->pgrp);
+		__kill_pg_info(SIGCONT, (void *)1, current->pgrp);
 	}
 
 	/* Let father know we died 
@@ -548,24 +579,16 @@
 	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 	 */
 
-	write_lock_irq(&tasklist_lock);
-	current->state = TASK_ZOMBIE;
 	if (current->exit_signal != -1)
 		do_notify_parent(current, current->exit_signal);
 
-zap_again:
-	list_for_each_safe(_p, _n, &current->children)
-		zap_thread(list_entry(_p,struct task_struct,sibling), current, 0);
-	list_for_each_safe(_p, _n, &current->ptrace_children)
-		zap_thread(list_entry(_p,struct task_struct,ptrace_list), current, 1);
-	/*
-	 * zap_thread might drop the tasklist lock, thus we could
-	 * have new children queued back from the ptrace list into the
-	 * child list:
-	 */
-	if (unlikely(!list_empty(&current->children) ||
-			!list_empty(&current->ptrace_children)))
-		goto zap_again;
+	while (!list_empty(&current->children))
+		zap_thread(list_entry(current->children.next,struct task_struct,sibling), current, 0);
+	while (!list_empty(&current->ptrace_children))
+		zap_thread(list_entry(current->ptrace_children.next,struct task_struct,ptrace_list), current, 1);
+	BUG_ON(!list_empty(&current->children));
+
+	current->state = TASK_ZOMBIE;
 	/*
 	 * No need to unlock IRQs, we'll schedule() immediately
 	 * anyway. In the preemption case this also makes it
@@ -647,9 +670,37 @@
 	do_exit((error_code&0xff)<<8);
 }
 
-static inline int eligible_child(pid_t pid, int options, task_t *p)
+/*
+ * this kills every thread in the thread group. Note that any externally
+ * wait4()-ing process will get the correct exit code - even if this 
+ * thread is not the thread group leader.
+ */
+asmlinkage long sys_exit_group(int error_code)
 {
-	if (pid>0) {
+	unsigned int exit_code = (error_code & 0xff) << 8;
+
+	if (!list_empty(&current->thread_group)) {
+		struct signal_struct *sig = current->sig;
+
+		spin_lock_irq(&sig->siglock);
+		if (sig->group_exit) {
+			spin_unlock_irq(&sig->siglock);
+
+			/* another thread was faster: */
+			do_exit(sig->group_exit_code);
+		}
+		sig->group_exit = 1;
+		sig->group_exit_code = exit_code;
+		__broadcast_thread_group(current, SIGKILL);
+		spin_unlock_irq(&sig->siglock);
+	}
+
+	do_exit(exit_code);
+}
+
+static int eligible_child(pid_t pid, int options, task_t *p)
+{
+	if (pid > 0) {
 		if (p->pid != pid)
 			return 0;
 	} else if (!pid) {
@@ -675,6 +726,12 @@
 	if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
 	    && !(options & __WALL))
 		return 0;
+	/*
+	 * Do not consider thread group leaders that are
+	 * in a non-empty thread group:
+	 */
+	if (current->tgid != p->tgid && delay_group_leader(p))
+		return 2;
 
 	if (security_ops->task_wait(p))
 		return 0;
@@ -700,11 +757,16 @@
 	do {
 		struct task_struct *p;
 		struct list_head *_p;
+		int ret;
+
 		list_for_each(_p,&tsk->children) {
 			p = list_entry(_p,struct task_struct,sibling);
-			if (!eligible_child(pid, options, p))
+
+			ret = eligible_child(pid, options, p);
+			if (!ret)
 				continue;
 			flag = 1;
+
 			switch (p->state) {
 			case TASK_STOPPED:
 				if (!p->exit_code)
@@ -727,12 +789,19 @@
 				}
 				goto end_wait4;
 			case TASK_ZOMBIE:
-				current->cutime += p->utime + p->cutime;
-				current->cstime += p->stime + p->cstime;
+				/*
+				 * Eligible but we cannot release it yet:
+				 */
+				if (ret == 2)
+					continue;
 				read_unlock(&tasklist_lock);
 				retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0;
-				if (!retval && stat_addr)
-					retval = put_user(p->exit_code, stat_addr);
+				if (!retval && stat_addr) {
+					if (p->sig->group_exit)
+						retval = put_user(p->sig->group_exit_code, stat_addr);
+					else
+						retval = put_user(p->exit_code, stat_addr);
+				}
 				if (retval)
 					goto end_wait4; 
 				retval = p->pid;
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/fork.c	Sun Sep 15 19:19:29 2002
@@ -161,7 +161,7 @@
 
 static int get_pid(unsigned long flags)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	int pid;
 
 	if (flags & CLONE_IDLETASK)
@@ -178,10 +178,9 @@
 		next_safe = pid_max;
 		read_lock(&tasklist_lock);
 	repeat:
-		for_each_task(p) {
+		do_each_thread(g, p) {
 			if (p->pid == last_pid	||
 			   p->pgrp == last_pid	||
-			   p->tgid == last_pid	||
 			   p->session == last_pid) {
 				if (++last_pid >= next_safe) {
 					if (last_pid >= pid_max)
@@ -194,11 +193,10 @@
 				next_safe = p->pid;
 			if (p->pgrp > last_pid && next_safe > p->pgrp)
 				next_safe = p->pgrp;
-			if (p->tgid > last_pid && next_safe > p->tgid)
-				next_safe = p->tgid;
 			if (p->session > last_pid && next_safe > p->session)
 				next_safe = p->session;
-		}
+		} while_each_thread(g, p);
+
 		read_unlock(&tasklist_lock);
 	}
 	pid = last_pid;
@@ -299,12 +297,16 @@
 #define allocate_mm()	(kmem_cache_alloc(mm_cachep, SLAB_KERNEL))
 #define free_mm(mm)	(kmem_cache_free(mm_cachep, (mm)))
 
+#include <linux/init_task.h>
+
 static struct mm_struct * mm_init(struct mm_struct * mm)
 {
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
+	mm->ioctx_list_lock = RW_LOCK_UNLOCKED;
+	mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
 	mm->pgd = pgd_alloc(mm);
 	if (mm->pgd)
 		return mm;
@@ -629,7 +631,10 @@
 		return -1;
 	spin_lock_init(&sig->siglock);
 	atomic_set(&sig->count, 1);
-	memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
+	sig->group_exit = 0;
+	sig->group_exit_code = 0;
+	sig->group_exit_task = NULL;
+	memcpy(sig->action, current->sig->action, sizeof(sig->action));
 	sig->curr_target = NULL;
 	init_sigpending(&sig->shared_pending);
 
@@ -668,10 +673,13 @@
 		return ERR_PTR(-EINVAL);
 
 	/*
-	 * Thread groups must share signals as well:
+	 * Thread groups must share signals as well, and detached threads
+	 * can only be started up within the thread group.
 	 */
-	if (clone_flags & CLONE_THREAD)
-		clone_flags |= CLONE_SIGHAND;
+	if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))
+		return ERR_PTR(-EINVAL);
+	if ((clone_flags & CLONE_DETACHED) && !(clone_flags & CLONE_THREAD))
+		return ERR_PTR(-EINVAL);
 
 	retval = security_ops->task_create(clone_flags);
 	if (retval)
@@ -790,6 +798,12 @@
 	if (clone_flags & CLONE_CLEARTID)
 		p->user_tid = user_tid;
 
+	/*
+	 * Syscall tracing should be turned off in the child regardless
+	 * of CLONE_PTRACE.
+	 */
+	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
+
 	/* Our parent execution domain becomes current domain
 	   These must match for thread signalling to apply */
 	   
@@ -837,6 +851,7 @@
 	 * Let it rip!
 	 */
 	p->tgid = p->pid;
+	p->group_leader = p;
 	INIT_LIST_HEAD(&p->thread_group);
 	INIT_LIST_HEAD(&p->ptrace_children);
 	INIT_LIST_HEAD(&p->ptrace_list);
@@ -853,7 +868,18 @@
 
 	if (clone_flags & CLONE_THREAD) {
 		spin_lock(&current->sig->siglock);
+		/*
+		 * Important: if an exit-all has been started then
+		 * do not create this new thread - the whole thread
+		 * group is supposed to exit anyway.
+		 */
+		if (current->sig->group_exit) {
+			spin_unlock(&current->sig->siglock);
+			write_unlock_irq(&tasklist_lock);
+			goto bad_fork_cleanup_namespace;
+		}
 		p->tgid = current->tgid;
+		p->group_leader = current->group_leader;
 		list_add(&p->thread_group, &current->thread_group);
 		spin_unlock(&current->sig->siglock);
 	}
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Sun Sep 15 19:19:28 2002
+++ b/kernel/ksyms.c	Sun Sep 15 19:19:28 2002
@@ -42,6 +42,7 @@
 #include <linux/highuid.h>
 #include <linux/brlock.h>
 #include <linux/fs.h>
+#include <linux/uio.h>
 #include <linux/tty.h>
 #include <linux/in6.h>
 #include <linux/completion.h>
@@ -343,6 +344,9 @@
 EXPORT_SYMBOL(read_dev_sector);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL_GPL(generic_file_direct_IO);
+EXPORT_SYMBOL(generic_file_readv);
+EXPORT_SYMBOL(generic_file_writev);
+EXPORT_SYMBOL(iov_shorten);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/sched.c	Sun Sep 15 19:19:29 2002
@@ -479,17 +479,17 @@
 {
 	local_irq_disable();
 	if (p->first_time_slice) {
-		current->time_slice += p->time_slice;
-		if (unlikely(current->time_slice > MAX_TIMESLICE))
-			current->time_slice = MAX_TIMESLICE;
+		p->parent->time_slice += p->time_slice;
+		if (unlikely(p->parent->time_slice > MAX_TIMESLICE))
+			p->parent->time_slice = MAX_TIMESLICE;
 	}
 	local_irq_enable();
 	/*
 	 * If the child was a (relative-) CPU hog then decrease
 	 * the sleep_avg of the parent as well.
 	 */
-	if (p->sleep_avg < current->sleep_avg)
-		current->sleep_avg = (current->sleep_avg * EXIT_WEIGHT +
+	if (p->sleep_avg < p->parent->sleep_avg)
+		p->parent->sleep_avg = (p->parent->sleep_avg * EXIT_WEIGHT +
 			p->sleep_avg) / (EXIT_WEIGHT + 1);
 }
 
@@ -940,7 +940,7 @@
 	struct list_head *queue;
 	int idx;
 
-	if (unlikely(in_interrupt()))
+	if (unlikely(in_atomic()))
 		BUG();
 
 #if CONFIG_DEBUG_HIGHMEM
@@ -1838,7 +1838,7 @@
 
 void show_state(void)
 {
-	task_t *p;
+	task_t *g, *p;
 
 #if (BITS_PER_LONG == 32)
 	printk("\n"
@@ -1850,14 +1850,15 @@
 	printk("  task                 PC        stack   pid father child younger older\n");
 #endif
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		/*
 		 * reset the NMI-timeout, listing all files on a slow
 		 * console might take alot of time:
 		 */
 		touch_nmi_watchdog();
 		show_task(p);
-	}
+	} while_each_thread(g, p);
+
 	read_unlock(&tasklist_lock);
 }
 
@@ -2054,8 +2055,7 @@
 	case CPU_ONLINE:
 		printk("Starting migration thread for cpu %li\n",
 		       (long)hcpu);
-		kernel_thread(migration_thread, hcpu,
-			      CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+		kernel_thread(migration_thread, hcpu, CLONE_KERNEL);
 		while (!cpu_rq((long)hcpu)->migration_thread)
 			yield();
 		break;
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Sun Sep 15 19:19:34 2002
+++ b/kernel/signal.c	Sun Sep 15 19:19:34 2002
@@ -73,12 +73,21 @@
 ----------------------------------------------------------
 */
 
+/* Some systems do not have a SIGSTKFLT and the kernel never
+ * generates such signals anyways.
+ */
+#ifdef SIGSTKFLT
+#define M_SIGSTKFLT	M(SIGSTKFLT)
+#else
+#define M_SIGSTKFLT	0
+#endif
+
 #define M(sig) (1UL << (sig))
 
 #define SIG_USER_SPECIFIC_MASK (\
 	M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   |  M(SIGBUS)    | \
 	M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGPIPE)   |  M(SIGXFSZ)   | \
-	M(SIGPROF)   |  M(SIGSYS)    |  M(SIGSTKFLT) |  M(SIGCONT)   )
+	M(SIGPROF)   |  M(SIGSYS)    |  M_SIGSTKFLT |  M(SIGCONT)   )
 
 #define SIG_USER_LOAD_BALANCE_MASK (\
         M(SIGHUP)    |  M(SIGINT)    |  M(SIGQUIT)   |  M(SIGUSR1)   | \
@@ -95,7 +104,7 @@
 	M(SIGKILL)   |  M(SIGUSR1)   |  M(SIGSEGV)   |  M(SIGUSR2)   | \
 	M(SIGPIPE)   |  M(SIGALRM)   |  M(SIGTERM)   |  M(SIGXCPU)   | \
 	M(SIGXFSZ)   |  M(SIGVTALRM) |  M(SIGPROF)   |  M(SIGPOLL)   | \
-	M(SIGSYS)    |  M(SIGSTKFLT) |  M(SIGPWR)    |  M(SIGCONT)   | \
+	M(SIGSYS)    |  M_SIGSTKFLT  |  M(SIGPWR)    |  M(SIGCONT)   | \
         M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   )
 
 #define SIG_KERNEL_ONLY_MASK (\
@@ -109,14 +118,18 @@
 #define T(sig, mask) \
 	((1UL << (sig)) & mask)
 
-#define sig_user_specific(sig)		T(sig, SIG_USER_SPECIFIC_MASK)
+#define sig_user_specific(sig) \
+		(((sig) < SIGRTMIN)  && T(sig, SIG_USER_SPECIFIC_MASK))
 #define sig_user_load_balance(sig) \
-		(T(sig, SIG_USER_LOAD_BALANCE_MASK) || ((sig) >= SIGRTMIN))
-#define sig_kernel_specific(sig)	T(sig, SIG_KERNEL_SPECIFIC_MASK)
+		(((sig) >= SIGRTMIN) || T(sig, SIG_USER_LOAD_BALANCE_MASK))
+#define sig_kernel_specific(sig) \
+		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_SPECIFIC_MASK))
 #define sig_kernel_broadcast(sig) \
-		(T(sig, SIG_KERNEL_BROADCAST_MASK) || ((sig) >= SIGRTMIN))
-#define sig_kernel_only(sig)		T(sig, SIG_KERNEL_ONLY_MASK)
-#define sig_kernel_coredump(sig)	T(sig, SIG_KERNEL_COREDUMP_MASK)
+		(((sig) >= SIGRTMIN) || T(sig, SIG_KERNEL_BROADCAST_MASK))
+#define sig_kernel_only(sig) \
+		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+		(((sig) < SIGRTMIN)  && T(sig, SIG_KERNEL_COREDUMP_MASK))
 
 #define sig_user_defined(t, sig) \
 	(((t)->sig->action[(sig)-1].sa.sa_handler != SIG_DFL) &&	\
@@ -221,20 +234,28 @@
 	flush_sigqueue(&t->pending);
 }
 
+static inline void __remove_thread_group(struct task_struct *tsk, struct signal_struct *sig)
+{
+	if (tsk == sig->curr_target)
+		sig->curr_target = next_thread(tsk);
+	list_del_init(&tsk->thread_group);
+}
+
 void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig)
 {
 	write_lock_irq(&tasklist_lock);
 	spin_lock(&tsk->sig->siglock);
 
-	if (tsk == sig->curr_target)
-		sig->curr_target = next_thread(tsk);
-	list_del_init(&tsk->thread_group);
+	__remove_thread_group(tsk, sig);
 
 	spin_unlock(&tsk->sig->siglock);
 	write_unlock_irq(&tasklist_lock);
 }
 
-void exit_sighand(struct task_struct *tsk)
+/*
+ * This function expects the tasklist_lock write-locked.
+ */
+void __exit_sighand(struct task_struct *tsk)
 {
 	struct signal_struct * sig = tsk->sig;
 
@@ -242,19 +263,55 @@
 		BUG();
 	if (!atomic_read(&sig->count))
 		BUG();
-	remove_thread_group(tsk, sig);
+	spin_lock(&sig->siglock);
+	spin_lock(&tsk->sigmask_lock);
+	tsk->sig = NULL;
+	if (atomic_dec_and_test(&sig->count)) {
+		__remove_thread_group(tsk, sig);
+		spin_unlock(&sig->siglock);
+		flush_sigqueue(&sig->shared_pending);
+		kmem_cache_free(sigact_cachep, sig);
+	} else {
+		struct task_struct *leader = tsk->group_leader;
 
-	spin_lock_irq(&tsk->sigmask_lock);
-	if (sig) {
-		tsk->sig = NULL;
-		if (atomic_dec_and_test(&sig->count)) {
-			flush_sigqueue(&sig->shared_pending);
-			kmem_cache_free(sigact_cachep, sig);
+		/*
+		 * If there is any task waiting for the group exit
+		 * then notify it:
+		 */
+		if (sig->group_exit_task && atomic_read(&sig->count) <= 2) {
+			wake_up_process(sig->group_exit_task);
+			sig->group_exit_task = NULL;
+		}
+		/*
+		 * If we are the last non-leader member of the thread
+		 * group, and the leader is zombie, then notify the
+		 * group leader's parent process.
+		 *
+		 * (subtle: here we also rely on the fact that if we are the
+		 *  thread group leader then we are not zombied yet.)
+		 */
+		if (atomic_read(&sig->count) == 1 &&
+					leader->state == TASK_ZOMBIE) {
+
+			__remove_thread_group(tsk, sig);
+			spin_unlock(&sig->siglock);
+			do_notify_parent(leader, leader->exit_signal);
+		} else {
+			__remove_thread_group(tsk, sig);
+			spin_unlock(&sig->siglock);
 		}
 	}
 	clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
 	flush_sigqueue(&tsk->pending);
-	spin_unlock_irq(&tsk->sigmask_lock);
+
+	spin_unlock(&tsk->sigmask_lock);
+}
+
+void exit_sighand(struct task_struct *tsk)
+{
+	write_lock_irq(&tasklist_lock);
+	__exit_sighand(tsk);
+	write_unlock_irq(&tasklist_lock);
 }
 
 /*
@@ -286,6 +343,9 @@
 	recalc_sigpending();
 	current->flags |= PF_SIGNALED;
 
+	if (current->sig->group_exit)
+		exit_code = current->sig->group_exit_code;
+
 	do_exit(exit_code);
 	/* NOTREACHED */
 }
@@ -881,27 +941,36 @@
  * control characters do (^C, ^Z etc)
  */
 
-int
-kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
+int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
 {
 	int retval = -EINVAL;
 	if (pgrp > 0) {
 		struct task_struct *p;
 
 		retval = -ESRCH;
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pgrp == pgrp && thread_group_leader(p)) {
+		for_each_process(p) {
+			if (p->pgrp == pgrp) {
 				int err = send_sig_info(sig, info, p);
 				if (retval)
 					retval = err;
 			}
 		}
-		read_unlock(&tasklist_lock);
 	}
 	return retval;
 }
 
+int
+kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
+{
+	int retval;
+
+	read_lock(&tasklist_lock);
+	retval = __kill_pg_info(sig, info, pgrp);
+	read_unlock(&tasklist_lock);
+
+	return retval;
+}
+
 /*
  * kill_sl_info() sends a signal to the session leader: this is used
  * to send SIGHUP to the controlling process of a terminal when
@@ -917,7 +986,7 @@
 
 		retval = -ESRCH;
 		read_lock(&tasklist_lock);
-		for_each_task(p) {
+		for_each_process(p) {
 			if (p->leader && p->session == sess) {
 				int err = send_sig_info(sig, info, p);
 				if (retval)
@@ -961,8 +1030,8 @@
 		struct task_struct * p;
 
 		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid > 1 && p != current && thread_group_leader(p)) {
+		for_each_process(p) {
+			if (p->pid > 1 && p != current) {
 				int err = send_sig_info(sig, info, p);
 				++count;
 				if (err != -EPERM)
@@ -1046,6 +1115,8 @@
 	struct siginfo info;
 	int why, status;
 
+	if (!tsk->ptrace && delay_group_leader(tsk))
+		return;
 	if (sig == -1)
 		BUG();
 
@@ -1220,6 +1291,7 @@
 
 #endif
 
+EXPORT_SYMBOL(recalc_sigpending);
 EXPORT_SYMBOL(dequeue_signal);
 EXPORT_SYMBOL(flush_signals);
 EXPORT_SYMBOL(force_sig);
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/softirq.c	Sun Sep 15 19:19:29 2002
@@ -395,8 +395,7 @@
 	int hotcpu = (unsigned long)hcpu;
 
 	if (action == CPU_ONLINE) {
-		if (kernel_thread(ksoftirqd, hcpu,
-				  CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0) {
+		if (kernel_thread(ksoftirqd, hcpu, CLONE_KERNEL) < 0) {
 			printk("ksoftirqd for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
 		}
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/suspend.c	Sun Sep 15 19:19:29 2002
@@ -204,14 +204,14 @@
 int freeze_processes(void)
 {
 	int todo, start_time;
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
 	do {
 		todo = 0;
 		read_lock(&tasklist_lock);
-		for_each_task(p) {
+		do_each_thread(g, p) {
 			unsigned long flags;
 			INTERESTING(p);
 			if (p->flags & PF_FROZEN)
@@ -224,7 +224,7 @@
 			signal_wake_up(p);
 			spin_unlock_irqrestore(&p->sigmask_lock, flags);
 			todo++;
-		}
+		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
 		yield();
 		if (time_after(jiffies, start_time + TIMEOUT)) {
@@ -240,18 +240,19 @@
 
 void thaw_processes(void)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 
 	printk( "Restarting tasks..." );
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		INTERESTING(p);
 		
 		if (p->flags & PF_FROZEN) p->flags &= ~PF_FROZEN;
 		else
 			printk(KERN_INFO " Strange, %s not stopped\n", p->comm );
 		wake_up_process(p);
-	}
+	} while_each_thread(g, p);
+
 	read_unlock(&tasklist_lock);
 	printk( " done\n" );
 	MDELAY(500);
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/sys.c	Sun Sep 15 19:19:29 2002
@@ -227,7 +227,7 @@
 
 asmlinkage long sys_setpriority(int which, int who, int niceval)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	int error;
 
 	if (which > 2 || which < 0)
@@ -241,7 +241,7 @@
 		niceval = 19;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		int no_nice;
 		if (!proc_sel(p, which, who))
 			continue;
@@ -262,8 +262,8 @@
 			continue;
 		}
 		set_user_nice(p, niceval);
+	} while_each_thread(g, p);
 
-	}
 	read_unlock(&tasklist_lock);
 
 	return error;
@@ -277,21 +277,21 @@
  */
 asmlinkage long sys_getpriority(int which, int who)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	long retval = -ESRCH;
 
 	if (which > 2 || which < 0)
 		return -EINVAL;
 
 	read_lock(&tasklist_lock);
-	for_each_task (p) {
+	do_each_thread(g, p) {
 		long niceval;
 		if (!proc_sel(p, which, who))
 			continue;
 		niceval = 20 - task_nice(p);
 		if (niceval > retval)
 			retval = niceval;
-	}
+	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 
 	return retval;
@@ -882,12 +882,12 @@
 	if (p->leader)
 		goto out;
 	if (pgid != pid) {
-		struct task_struct * tmp;
-		for_each_task (tmp) {
+		struct task_struct *g, *tmp;
+		do_each_thread(g, tmp) {
 			if (tmp->pgrp == pgid &&
 			    tmp->session == current->session)
 				goto ok_pgid;
-		}
+		} while_each_thread(g, tmp);
 		goto out;
 	}
 
@@ -956,14 +956,14 @@
 
 asmlinkage long sys_setsid(void)
 {
-	struct task_struct * p;
+	struct task_struct *g, *p;
 	int err = -EPERM;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p)
 		if (p->pgrp == current->pid)
 			goto out;
-	}
+	while_each_thread(g, p);
 
 	current->leader = 1;
 	current->session = current->pgrp = current->pid;
diff -Nru a/kernel/time.c b/kernel/time.c
--- a/kernel/time.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/time.c	Sun Sep 15 19:19:29 2002
@@ -82,7 +82,7 @@
 		return -EFAULT;
 	write_lock_irq(&xtime_lock);
 	xtime.tv_sec = value;
-	xtime.tv_usec = 0;
+	xtime.tv_nsec = 0;
 	last_time_offset = 0;
 	time_adjust = 0;	/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
@@ -231,7 +231,8 @@
 
 	/* if the quartz is off by more than 10% something is VERY wrong ! */
 	if (txc->modes & ADJ_TICK)
-		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
+		if (txc->tick <  900000/USER_HZ ||
+		    txc->tick > 1100000/USER_HZ)
 			return -EINVAL;
 
 	write_lock_irq(&xtime_lock);
@@ -344,13 +345,8 @@
 		} /* STA_PLL || STA_PPSTIME */
 	    } /* txc->modes & ADJ_OFFSET */
 	    if (txc->modes & ADJ_TICK) {
-		/* if the quartz is off by more than 10% something is
-		   VERY wrong ! */
-		if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) {
-		    result = -EINVAL;
-		    goto leave;
-		}
-		tick = txc->tick;
+		tick_usec = txc->tick;
+		tick_nsec = TICK_NSEC(tick_usec);
 	    }
 	} /* txc->modes */
 leave:	if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
@@ -380,7 +376,7 @@
 	txc->constant	   = time_constant;
 	txc->precision	   = time_precision;
 	txc->tolerance	   = time_tolerance;
-	txc->tick	   = tick;
+	txc->tick	   = tick_usec;
 	txc->ppsfreq	   = pps_freq;
 	txc->jitter	   = pps_jitter >> PPS_AVG;
 	txc->shift	   = pps_shift;
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Sun Sep 15 19:19:29 2002
+++ b/kernel/timer.c	Sun Sep 15 19:19:29 2002
@@ -33,10 +33,11 @@
  * Timekeeping variables
  */
 
-long tick = (1000000 + HZ/2) / HZ;	/* timer interrupt period */
+unsigned long tick_usec = TICK_USEC; 		/* ACTHZ          period (usec) */
+unsigned long tick_nsec = TICK_NSEC(TICK_USEC);	/* USER_HZ period (nsec) */
 
 /* The current time */
-struct timeval xtime __attribute__ ((aligned (16)));
+struct timespec xtime __attribute__ ((aligned (16)));
 
 /* Don't completely fail for HZ > 500.  */
 int tickadj = 500/HZ ? : 1;		/* microsecs */
@@ -63,7 +64,6 @@
 long time_reftime;			/* time at last adjustment (s)	*/
 
 long time_adjust;
-long time_adjust_step;
 
 unsigned long event;
 
@@ -465,6 +465,8 @@
 /* in the NTP reference this is called "hardclock()" */
 static void update_wall_time_one_tick(void)
 {
+	long time_adjust_step;
+
 	if ( (time_adjust_step = time_adjust) != 0 ) {
 	    /* We are doing an adjtime thing. 
 	     *
@@ -483,21 +485,21 @@
 	    /* Reduce by this step the amount of time left  */
 	    time_adjust -= time_adjust_step;
 	}
-	xtime.tv_usec += tick + time_adjust_step;
+	xtime.tv_nsec += tick_nsec + time_adjust_step * 1000;
 	/*
 	 * Advance the phase, once it gets to one microsecond, then
 	 * advance the tick more.
 	 */
 	time_phase += time_adj;
 	if (time_phase <= -FINEUSEC) {
-		long ltemp = -time_phase >> SHIFT_SCALE;
-		time_phase += ltemp << SHIFT_SCALE;
-		xtime.tv_usec -= ltemp;
+		long ltemp = -time_phase >> (SHIFT_SCALE - 10);
+		time_phase += ltemp << (SHIFT_SCALE - 10);
+		xtime.tv_nsec -= ltemp;
 	}
 	else if (time_phase >= FINEUSEC) {
-		long ltemp = time_phase >> SHIFT_SCALE;
-		time_phase -= ltemp << SHIFT_SCALE;
-		xtime.tv_usec += ltemp;
+		long ltemp = time_phase >> (SHIFT_SCALE - 10);
+		time_phase -= ltemp << (SHIFT_SCALE - 10);
+		xtime.tv_nsec += ltemp;
 	}
 }
 
@@ -515,8 +517,8 @@
 		update_wall_time_one_tick();
 	} while (ticks);
 
-	if (xtime.tv_usec >= 1000000) {
-	    xtime.tv_usec -= 1000000;
+	if (xtime.tv_nsec >= 1000000000) {
+	    xtime.tv_nsec -= 1000000000;
 	    xtime.tv_sec++;
 	    second_overflow();
 	}
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Sun Sep 15 19:19:30 2002
+++ b/mm/filemap.c	Sun Sep 15 19:19:30 2002
@@ -13,11 +13,13 @@
 #include <linux/slab.h>
 #include <linux/compiler.h>
 #include <linux/fs.h>
+#include <linux/aio.h>
 #include <linux/kernel_stat.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
+#include <linux/uio.h>
 #include <linux/iobuf.h>
 #include <linux/hash.h>
 #include <linux/writeback.h>
@@ -181,7 +183,7 @@
 	if (PagePrivate(page))
 		do_invalidatepage(page, 0);
 
-	ClearPageDirty(page);
+	clear_page_dirty(page);
 	ClearPageUptodate(page);
 	remove_from_page_cache(page);
 	page_cache_release(page);
@@ -280,7 +282,7 @@
 	for (curr = head->next; curr != head; curr = curr->next) {
 		page = list_entry(curr, struct page, list);
 		if (page->index > start)
-			ClearPageDirty(page);
+			clear_page_dirty(page);
 	}
 }
 
@@ -348,7 +350,7 @@
 		} else
 			unlocked = 0;
 
-		ClearPageDirty(page);
+		clear_page_dirty(page);
 		ClearPageUptodate(page);
 	}
 
@@ -557,8 +559,8 @@
 	error = radix_tree_insert(&mapping->page_tree, offset, page);
 	if (!error) {
 		SetPageLocked(page);
-		ClearPageDirty(page);
 		___add_to_page_cache(page, mapping, offset);
+		ClearPageDirty(page);
 	} else {
 		page_cache_release(page);
 	}
@@ -1121,14 +1123,19 @@
  * This is the "read()" routine for all filesystems
  * that can use the page cache directly.
  */
-ssize_t
-generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+static ssize_t
+__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+		unsigned long nr_segs, loff_t *ppos)
 {
+	struct file *filp = iocb->ki_filp;
 	ssize_t retval;
+	unsigned long seg;
+	size_t count = iov_length(iov, nr_segs);
 
 	if ((ssize_t) count < 0)
 		return -EINVAL;
 
+	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
 	if (filp->f_flags & O_DIRECT) {
 		loff_t pos = *ppos, size;
 		struct address_space *mapping;
@@ -1141,10 +1148,13 @@
 			goto out; /* skip atime */
 		size = inode->i_size;
 		if (pos < size) {
-			if (pos + count > size)
+			if (pos + count > size) {
 				count = size - pos;
-			retval = generic_file_direct_IO(READ, inode,
-							buf, pos, count);
+				nr_segs = iov_shorten((struct iovec *)iov,
+							nr_segs, count);
+			}
+			retval = generic_file_direct_IO(READ, inode, 
+					iov, pos, nr_segs);
 			if (retval > 0)
 				*ppos = pos + retval;
 		}
@@ -1152,27 +1162,56 @@
 		goto out;
 	}
 
-	retval = -EFAULT;
-	if (access_ok(VERIFY_WRITE, buf, count)) {
-		retval = 0;
+	for (seg = 0; seg < nr_segs; seg++) {
+		if (!access_ok(VERIFY_WRITE,iov[seg].iov_base,iov[seg].iov_len))
+			return -EFAULT;
+	}
 
-		if (count) {
+	retval = 0;
+	if (count) {
+		for (seg = 0; seg < nr_segs; seg++) {
 			read_descriptor_t desc;
 
 			desc.written = 0;
-			desc.count = count;
-			desc.buf = buf;
+			desc.buf = iov[seg].iov_base;
+			desc.count = iov[seg].iov_len;
+			if (desc.count == 0)
+				continue;
 			desc.error = 0;
 			do_generic_file_read(filp,ppos,&desc,file_read_actor);
-			retval = desc.written;
-			if (!retval)
+			retval += desc.written;
+			if (!retval) {
 				retval = desc.error;
+				break;
+			}
 		}
 	}
 out:
 	return retval;
 }
 
+ssize_t
+generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t *ppos)
+{
+	struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+
+	return __generic_file_aio_read(iocb, &local_iov, 1, ppos);
+}
+
+ssize_t
+generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+	struct iovec local_iov = { .iov_base = buf, .iov_len = count };
+	struct kiocb kiocb;
+	ssize_t ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&kiocb);
+	return ret;
+}
+
 static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
 {
 	ssize_t written;
@@ -1926,11 +1965,14 @@
  * it for writing by marking it dirty.
  *							okir@monad.swb.de
  */
-ssize_t generic_file_write_nolock(struct file *file, const char *buf,
-				  size_t count, loff_t *ppos)
+ssize_t
+generic_file_write_nolock(struct file *file, const struct iovec *iov,
+				unsigned long nr_segs, loff_t *ppos)
 {
 	struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
 	struct address_space_operations *a_ops = mapping->a_ops;
+	const size_t ocount = iov_length(iov, nr_segs);
+	size_t count =	ocount;
 	struct inode 	*inode = mapping->host;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	long		status = 0;
@@ -1942,12 +1984,19 @@
 	unsigned	bytes;
 	time_t		time_now;
 	struct pagevec	lru_pvec;
+	struct iovec	*cur_iov;
+	unsigned	iov_bytes;	/* Cumulative count to the end of the
+					   current iovec */
+	unsigned long	seg;
+	char		*buf;
 
 	if (unlikely((ssize_t)count < 0))
 		return -EINVAL;
 
-	if (unlikely(!access_ok(VERIFY_READ, buf, count)))
-		return -EFAULT;
+	for (seg = 0; seg < nr_segs; seg++) {
+		if (!access_ok(VERIFY_READ,iov[seg].iov_base,iov[seg].iov_len))
+			return -EFAULT;
+	}
 
 	pos = *ppos;
 	if (unlikely(pos < 0))
@@ -2045,9 +2094,13 @@
 		mark_inode_dirty_sync(inode);
 	}
 
+	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
 	if (unlikely(file->f_flags & O_DIRECT)) {
-		written = generic_file_direct_IO(WRITE, inode,
-						(char *)buf, pos, count);
+		if (count != ocount)
+			nr_segs = iov_shorten((struct iovec *)iov,
+						nr_segs, count);
+		written = generic_file_direct_IO(WRITE, inode, 
+					iov, pos, nr_segs);
 		if (written > 0) {
 			loff_t end = pos + written;
 			if (end > inode->i_size && !S_ISBLK(inode->i_mode)) {
@@ -2065,6 +2118,9 @@
 		goto out_status;
 	}
 
+	cur_iov = (struct iovec *)iov;
+	iov_bytes = cur_iov->iov_len;
+	buf = cur_iov->iov_base;
 	do {
 		unsigned long index;
 		unsigned long offset;
@@ -2075,6 +2131,8 @@
 		bytes = PAGE_CACHE_SIZE - offset;
 		if (bytes > count)
 			bytes = count;
+		if (bytes + written > iov_bytes)
+			bytes = iov_bytes - written;
 
 		/*
 		 * Bring in the user page that we will copy from _first_.
@@ -2084,7 +2142,7 @@
 		 */
 		fault_in_pages_readable(buf, bytes);
 
-		page = __grab_cache_page(mapping, index, &cached_page, &lru_pvec);
+		page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
 		if (!page) {
 			status = -ENOMEM;
 			break;
@@ -2115,6 +2173,11 @@
 				count -= status;
 				pos += status;
 				buf += status;
+				if (written == iov_bytes && count) {
+					cur_iov++;
+					iov_bytes += cur_iov->iov_len;
+					buf = cur_iov->iov_base;
+				}
 			}
 		}
 		if (!PageReferenced(page))
@@ -2151,10 +2214,36 @@
 {
 	struct inode	*inode = file->f_dentry->d_inode->i_mapping->host;
 	int		err;
+	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
 
 	down(&inode->i_sem);
-	err = generic_file_write_nolock(file, buf, count, ppos);
+	err = generic_file_write_nolock(file, &local_iov, 1, ppos);
 	up(&inode->i_sem);
 
 	return err;
+}
+
+ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
+			unsigned long nr_segs, loff_t *ppos)
+{
+	struct kiocb kiocb;
+	ssize_t ret;
+
+	init_sync_kiocb(&kiocb, filp);
+	ret = __generic_file_aio_read(&kiocb, iov, nr_segs, ppos);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&kiocb);
+	return ret;
+}
+
+ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
+			unsigned long nr_segs, loff_t * ppos) 
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	ssize_t ret;
+
+	down(&inode->i_sem);
+	ret = generic_file_write_nolock(file, iov, nr_segs, ppos);
+	up(&inode->i_sem);
+	return ret;
 }
diff -Nru a/mm/oom_kill.c b/mm/oom_kill.c
--- a/mm/oom_kill.c	Sun Sep 15 19:19:28 2002
+++ b/mm/oom_kill.c	Sun Sep 15 19:19:28 2002
@@ -116,10 +116,10 @@
 static struct task_struct * select_bad_process(void)
 {
 	int maxpoints = 0;
-	struct task_struct *p = NULL;
+	struct task_struct *g, *p;
 	struct task_struct *chosen = NULL;
 
-	for_each_task(p) {
+	do_each_thread(g, p)
 		if (p->pid) {
 			int points = badness(p);
 			if (points > maxpoints) {
@@ -127,7 +127,7 @@
 				maxpoints = points;
 			}
 		}
-	}
+	while_each_thread(g, p);
 	return chosen;
 }
 
@@ -166,7 +166,7 @@
  */
 static void oom_kill(void)
 {
-	struct task_struct *p, *q;
+	struct task_struct *g, *p, *q;
 	
 	read_lock(&tasklist_lock);
 	p = select_bad_process();
@@ -176,9 +176,11 @@
 		panic("Out of memory and no killable processes...\n");
 
 	/* kill all processes that share the ->mm (i.e. all threads) */
-	for_each_task(q) {
-		if(q->mm == p->mm) oom_kill_task(q);
-	}
+	do_each_thread(g, q)
+		if (q->mm == p->mm)
+			oom_kill_task(q);
+	while_each_thread(g, q);
+
 	read_unlock(&tasklist_lock);
 
 	/*
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Sun Sep 15 19:20:00 2002
+++ b/mm/page-writeback.c	Sun Sep 15 19:20:00 2002
@@ -38,7 +38,12 @@
  * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
  * will look to see if it needs to force writeback or throttling.
  */
-static int ratelimit_pages = 32;
+static long ratelimit_pages = 32;
+
+/*
+ * The total number of pages in the machine.
+ */
+static long total_pages;
 
 /*
  * When balance_dirty_pages decides that the caller needs to perform some
@@ -60,17 +65,17 @@
 /*
  * Start background writeback (via pdflush) at this level
  */
-int dirty_background_ratio = 40;
+int dirty_background_ratio = 10;
 
 /*
  * The generator of dirty data starts async writeback at this level
  */
-int dirty_async_ratio = 50;
+int dirty_async_ratio = 40;
 
 /*
  * The generator of dirty data performs sync writeout at this level
  */
-int dirty_sync_ratio = 60;
+int dirty_sync_ratio = 50;
 
 /*
  * The interval between `kupdate'-style writebacks, in centiseconds
@@ -107,18 +112,17 @@
  */
 void balance_dirty_pages(struct address_space *mapping)
 {
-	const int tot = nr_free_pagecache_pages();
 	struct page_state ps;
-	int background_thresh, async_thresh, sync_thresh;
+	long background_thresh, async_thresh, sync_thresh;
 	unsigned long dirty_and_writeback;
 	struct backing_dev_info *bdi;
 
 	get_page_state(&ps);
 	dirty_and_writeback = ps.nr_dirty + ps.nr_writeback;
 
-	background_thresh = (dirty_background_ratio * tot) / 100;
-	async_thresh = (dirty_async_ratio * tot) / 100;
-	sync_thresh = (dirty_sync_ratio * tot) / 100;
+	background_thresh = (dirty_background_ratio * total_pages) / 100;
+	async_thresh = (dirty_async_ratio * total_pages) / 100;
+	sync_thresh = (dirty_sync_ratio * total_pages) / 100;
 	bdi = mapping->backing_dev_info;
 
 	if (dirty_and_writeback > sync_thresh) {
@@ -171,13 +175,14 @@
  */
 static void background_writeout(unsigned long _min_pages)
 {
-	const int tot = nr_free_pagecache_pages();
-	const int background_thresh = (dirty_background_ratio * tot) / 100;
 	long min_pages = _min_pages;
+	long background_thresh;
 	int nr_to_write;
 
 	CHECK_EMERGENCY_SYNC
 
+	background_thresh = (dirty_background_ratio * total_pages) / 100;
+
 	do {
 		struct page_state ps;
 
@@ -269,7 +274,7 @@
 
 static void set_ratelimit(void)
 {
-	ratelimit_pages = nr_free_pagecache_pages() / (num_online_cpus() * 32);
+	ratelimit_pages = total_pages / (num_online_cpus() * 32);
 	if (ratelimit_pages < 16)
 		ratelimit_pages = 16;
 	if (ratelimit_pages * PAGE_CACHE_SIZE > 4096 * 1024)
@@ -288,8 +293,29 @@
 	.next		= NULL,
 };
 
+/*
+ * If the machine has a large highmem:lowmem ratio then scale back the default
+ * dirty memory thresholds: allowing too much dirty highmem pins an excessive
+ * number of buffer_heads.
+ */
 static int __init page_writeback_init(void)
 {
+	long buffer_pages = nr_free_buffer_pages();
+	long correction;
+
+	total_pages = nr_free_pagecache_pages();
+
+	correction = (100 * 4 * buffer_pages) / total_pages;
+
+	if (correction < 100) {
+		dirty_background_ratio *= correction;
+		dirty_background_ratio /= 100;
+		dirty_async_ratio *= correction;
+		dirty_async_ratio /= 100;
+		dirty_sync_ratio *= correction;
+		dirty_sync_ratio /= 100;
+	}
+
 	init_timer(&wb_timer);
 	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
 	wb_timer.data = 0;
@@ -350,7 +376,7 @@
 #if 0
 		if (!PageWriteback(page) && PageDirty(page)) {
 			lock_page(page);
-			if (!PageWriteback(page) && TestClearPageDirty(page)) {
+			if (!PageWriteback(page)&&test_clear_page_dirty(page)) {
 				int ret;
 
 				ret = page->mapping->a_ops->writepage(page);
@@ -395,7 +421,7 @@
 
 	write_lock(&mapping->page_lock);
 	list_del(&page->list);
-	if (TestClearPageDirty(page)) {
+	if (test_clear_page_dirty(page)) {
 		list_add(&page->list, &mapping->locked_pages);
 		page_cache_get(page);
 		write_unlock(&mapping->page_lock);
@@ -487,6 +513,8 @@
 	if (!TestSetPageDirty(page)) {
 		write_lock(&mapping->page_lock);
 		if (page->mapping) {	/* Race with truncate? */
+			if (!mapping->backing_dev_info->memory_backed)
+				inc_page_state(nr_dirty);
 			list_del(&page->list);
 			list_add(&page->list, &mapping->dirty_pages);
 		}
@@ -523,6 +551,8 @@
 		if (mapping) {
 			write_lock(&mapping->page_lock);
 			if (page->mapping) {	/* Race with truncate? */
+				if (!mapping->backing_dev_info->memory_backed)
+					inc_page_state(nr_dirty);
 				list_del(&page->list);
 				list_add(&page->list, &mapping->dirty_pages);
 			}
@@ -534,4 +564,18 @@
 }
 EXPORT_SYMBOL(__set_page_dirty_nobuffers);
 
+/*
+ * Clear a page's dirty flag, while caring for dirty memory accounting. 
+ * Returns true if the page was previously dirty.
+ */
+int test_clear_page_dirty(struct page *page)
+{
+	if (TestClearPageDirty(page)) {
+		struct address_space *mapping = page->mapping;
 
+		if (mapping && !mapping->backing_dev_info->memory_backed)
+			dec_page_state(nr_dirty);
+		return 1;
+	}
+	return 0;
+}
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Sun Sep 15 19:19:28 2002
+++ b/mm/page_alloc.c	Sun Sep 15 19:19:28 2002
@@ -93,7 +93,7 @@
 	BUG_ON(PageLocked(page));
 	BUG_ON(PageActive(page));
 	BUG_ON(PageWriteback(page));
-	BUG_ON(page->pte.chain != NULL);
+	BUG_ON(page->pte.direct != 0);
 	if (PageDirty(page))
 		ClearPageDirty(page);
 	BUG_ON(page_count(page) != 0);
@@ -184,7 +184,7 @@
 	BUG_ON(PageActive(page));
 	BUG_ON(PageDirty(page));
 	BUG_ON(PageWriteback(page));
-	BUG_ON(page->pte.chain != NULL);
+	BUG_ON(page->pte.direct != 0);
 	page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
 			1 << PG_referenced | 1 << PG_arch_1 |
 			1 << PG_checked);
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Sun Sep 15 19:20:24 2002
+++ b/mm/pdflush.c	Sun Sep 15 19:20:24 2002
@@ -202,8 +202,7 @@
 
 static void start_one_pdflush_thread(void)
 {
-	kernel_thread(pdflush, NULL,
-			CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	kernel_thread(pdflush, NULL, CLONE_KERNEL);
 }
 
 static int __init pdflush_init(void)
diff -Nru a/mm/rmap.c b/mm/rmap.c
--- a/mm/rmap.c	Sun Sep 15 19:20:23 2002
+++ b/mm/rmap.c	Sun Sep 15 19:20:23 2002
@@ -40,20 +40,35 @@
  * here, the page struct for the page table page contains the process
  * it belongs to and the offset within that process.
  *
- * A singly linked list should be fine for most, if not all, workloads.
- * On fork-after-exec the mapping we'll be removing will still be near
- * the start of the list, on mixed application systems the short-lived
- * processes will have their mappings near the start of the list and
- * in systems with long-lived applications the relative overhead of
- * exit() will be lower since the applications are long-lived.
+ * We use an array of pte pointers in this structure to minimise cache misses
+ * while traversing reverse maps.
  */
+#define NRPTE ((L1_CACHE_BYTES - sizeof(void *))/sizeof(pte_addr_t))
+
 struct pte_chain {
-	struct pte_chain * next;
-	pte_t * ptep;
+	struct pte_chain *next;
+	pte_addr_t ptes[NRPTE];
 };
 
 static kmem_cache_t	*pte_chain_cache;
 
+/*
+ * pte_chain list management policy:
+ *
+ * - If a page has a pte_chain list then it is shared by at least two processes,
+ *   because a single sharing uses PageDirect. (Well, this isn't true yet,
+ *   coz this code doesn't collapse singletons back to PageDirect on the remove
+ *   path).
+ * - A pte_chain list has free space only in the head member - all succeeding
+ *   members are 100% full.
+ * - If the head element has free space, it occurs in its leading slots.
+ * - All free space in the pte_chain is at the start of the head member.
+ * - Insertion into the pte_chain puts a pte pointer in the last free slot of
+ *   the head member.
+ * - Removal from a pte chain moves the head pte of the head member onto the
+ *   victim pte and frees the head member if it became empty.
+ */
+
 /**
  * pte_chain_alloc - allocate a pte_chain struct
  *
@@ -63,32 +78,30 @@
  */
 static inline struct pte_chain *pte_chain_alloc(void)
 {
-	return kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC);
+	struct pte_chain *ret;
+
+	ret = kmem_cache_alloc(pte_chain_cache, GFP_ATOMIC);
+#ifdef DEBUG_RMAP
+	{
+		int i;
+		for (i = 0; i < NRPTE; i++)
+			BUG_ON(ret->ptes[i]);
+		BUG_ON(ret->next);
+	}
+#endif
+	return ret;
 }
 
 /**
  * pte_chain_free - free pte_chain structure
  * @pte_chain: pte_chain struct to free
- * @prev_pte_chain: previous pte_chain on the list (may be NULL)
- * @page: page this pte_chain hangs off (may be NULL)
- *
- * This function unlinks pte_chain from the singly linked list it
- * may be on and adds the pte_chain to the free list. May also be
- * called for new pte_chain structures which aren't on any list yet.
- * Caller needs to hold the pte_chain_lock if the page is non-NULL.
  */
-static inline void pte_chain_free(struct pte_chain * pte_chain,
-		struct pte_chain * prev_pte_chain, struct page * page)
+static inline void pte_chain_free(struct pte_chain *pte_chain)
 {
-	if (prev_pte_chain)
-		prev_pte_chain->next = pte_chain->next;
-	else if (page)
-		page->pte.chain = pte_chain->next;
-
+	pte_chain->next = NULL;
 	kmem_cache_free(pte_chain_cache, pte_chain);
 }
 
-
 /**
  ** VM stuff below this comment
  **/
@@ -100,6 +113,9 @@
  * Quick test_and_clear_referenced for all mappings to a page,
  * returns the number of processes which referenced the page.
  * Caller needs to hold the pte_chain_lock.
+ *
+ * If the page has a single-entry pte_chain, collapse that back to a PageDirect
+ * representation.  This way, it's only done under memory pressure.
  */
 int page_referenced(struct page * page)
 {
@@ -110,13 +126,36 @@
 		referenced++;
 
 	if (PageDirect(page)) {
-		if (ptep_test_and_clear_young(page->pte.direct))
+		pte_t *pte = rmap_ptep_map(page->pte.direct);
+		if (ptep_test_and_clear_young(pte))
 			referenced++;
+		rmap_ptep_unmap(pte);
 	} else {
+		int nr_chains = 0;
+
 		/* Check all the page tables mapping this page. */
 		for (pc = page->pte.chain; pc; pc = pc->next) {
-			if (ptep_test_and_clear_young(pc->ptep))
-				referenced++;
+			int i;
+
+			for (i = NRPTE-1; i >= 0; i--) {
+				pte_addr_t pte_paddr = pc->ptes[i];
+				pte_t *p;
+
+				if (!pte_paddr)
+					break;
+				p = rmap_ptep_map(pte_paddr);
+				if (ptep_test_and_clear_young(p))
+					referenced++;
+				rmap_ptep_unmap(p);
+				nr_chains++;
+			}
+		}
+		if (nr_chains == 1) {
+			pc = page->pte.chain;
+			page->pte.direct = pc->ptes[NRPTE-1];
+			SetPageDirect(page);
+			pc->ptes[NRPTE-1] = 0;
+			pte_chain_free(pc);
 		}
 	}
 	return referenced;
@@ -132,8 +171,9 @@
  */
 void page_add_rmap(struct page * page, pte_t * ptep)
 {
-	struct pte_chain * pte_chain;
-	unsigned long pfn = pte_pfn(*ptep);
+	pte_addr_t pte_paddr = ptep_to_paddr(ptep);
+	struct pte_chain *pte_chain;
+	int i;
 
 #ifdef DEBUG_RMAP
 	if (!page || !ptep)
@@ -144,49 +184,74 @@
 		BUG();
 #endif
 
-	if (!pfn_valid(pfn) || PageReserved(page))
+	if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
 		return;
 
-#ifdef DEBUG_RMAP
 	pte_chain_lock(page);
+
+#ifdef DEBUG_RMAP
+	/*
+	 * This stuff needs help to get up to highmem speed.
+	 */
 	{
 		struct pte_chain * pc;
 		if (PageDirect(page)) {
-			if (page->pte.direct == ptep)
+			if (page->pte.direct == pte_paddr)
 				BUG();
 		} else {
 			for (pc = page->pte.chain; pc; pc = pc->next) {
-				if (pc->ptep == ptep)
-					BUG();
+				for (i = 0; i < NRPTE; i++) {
+					pte_addr_t p = pc->ptes[i];
+
+					if (p && p == pte_paddr)
+						BUG();
+				}
 			}
 		}
 	}
-	pte_chain_unlock(page);
 #endif
 
-	pte_chain_lock(page);
+	if (page->pte.direct == 0) {
+		page->pte.direct = pte_paddr;
+		SetPageDirect(page);
+		goto out;
+	}
 
 	if (PageDirect(page)) {
 		/* Convert a direct pointer into a pte_chain */
-		pte_chain = pte_chain_alloc();
-		pte_chain->ptep = page->pte.direct;
-		pte_chain->next = NULL;
-		page->pte.chain = pte_chain;
 		ClearPageDirect(page);
-	}
-	if (page->pte.chain) {
-		/* Hook up the pte_chain to the page. */
 		pte_chain = pte_chain_alloc();
-		pte_chain->ptep = ptep;
-		pte_chain->next = page->pte.chain;
+		pte_chain->ptes[NRPTE-1] = page->pte.direct;
+		pte_chain->ptes[NRPTE-2] = pte_paddr;
+		page->pte.direct = 0;
 		page->pte.chain = pte_chain;
-	} else {
-		page->pte.direct = ptep;
-		SetPageDirect(page);
+		goto out;
+	}
+
+	pte_chain = page->pte.chain;
+	if (pte_chain->ptes[0]) {	/* It's full */
+		struct pte_chain *new;
+
+		new = pte_chain_alloc();
+		new->next = pte_chain;
+		page->pte.chain = new;
+		new->ptes[NRPTE-1] = pte_paddr;
+		goto out;
 	}
 
+	BUG_ON(!pte_chain->ptes[NRPTE-1]);
+
+	for (i = NRPTE-2; i >= 0; i--) {
+		if (!pte_chain->ptes[i]) {
+			pte_chain->ptes[i] = pte_paddr;
+			goto out;
+		}
+	}
+	BUG();
+out:
 	pte_chain_unlock(page);
 	inc_page_state(nr_reverse_maps);
+	return;
 }
 
 /**
@@ -201,32 +266,52 @@
  */
 void page_remove_rmap(struct page * page, pte_t * ptep)
 {
-	struct pte_chain * pc, * prev_pc = NULL;
-	unsigned long pfn = page_to_pfn(page);
+	pte_addr_t pte_paddr = ptep_to_paddr(ptep);
+	struct pte_chain *pc;
 
 	if (!page || !ptep)
 		BUG();
-	if (!pfn_valid(pfn) || PageReserved(page))
+	if (!pfn_valid(page_to_pfn(page)) || PageReserved(page))
 		return;
 
 	pte_chain_lock(page);
 
+	BUG_ON(page->pte.direct == 0);
+ 
 	if (PageDirect(page)) {
-		if (page->pte.direct == ptep) {
-			page->pte.direct = NULL;
+		if (page->pte.direct == pte_paddr) {
+			page->pte.direct = 0;
+			dec_page_state(nr_reverse_maps);
 			ClearPageDirect(page);
 			goto out;
 		}
 	} else {
-		for (pc = page->pte.chain; pc; prev_pc = pc, pc = pc->next) {
-			if (pc->ptep == ptep) {
-				pte_chain_free(pc, prev_pc, page);
-				/* Check whether we can convert to direct */
-				pc = page->pte.chain;
-				if (!pc->next) {
-					page->pte.direct = pc->ptep;
-					SetPageDirect(page);
-					pte_chain_free(pc, NULL, NULL);
+		struct pte_chain *start = page->pte.chain;
+		int victim_i = -1;
+
+		for (pc = start; pc; pc = pc->next) {
+			int i;
+
+			if (pc->next)
+				prefetch(pc->next);
+			for (i = 0; i < NRPTE; i++) {
+				pte_addr_t pa = pc->ptes[i];
+
+				if (!pa)
+					continue;
+				if (victim_i == -1)
+					victim_i = i;
+				if (pa != pte_paddr)
+					continue;
+				pc->ptes[i] = start->ptes[victim_i];
+				dec_page_state(nr_reverse_maps);
+				start->ptes[victim_i] = 0;
+				if (victim_i == NRPTE-1) {
+					/* Emptied a pte_chain */
+					page->pte.chain = start->next;
+					pte_chain_free(start);
+				} else {
+					/* Do singleton->PageDirect here */
 				}
 				goto out;
 			}
@@ -237,17 +322,19 @@
 	printk(KERN_ERR "page_remove_rmap: pte_chain %p not present.\n", ptep);
 	printk(KERN_ERR "page_remove_rmap: only found: ");
 	if (PageDirect(page)) {
-		printk("%p ", page->pte.direct);
+		printk("%llx", (u64)page->pte.direct);
 	} else {
-		for (pc = page->pte.chain; pc; pc = pc->next)
-			printk("%p ", pc->ptep);
+		for (pc = page->pte.chain; pc; pc = pc->next) {
+			int i;
+			for (i = 0; i < NRPTE; i++)
+				printk(" %d:%llx", i, (u64)pc->ptes[i]);
+		}
 	}
 	printk("\n");
 	printk(KERN_ERR "page_remove_rmap: driver cleared PG_reserved ?\n");
 #endif
 
 out:
-	dec_page_state(nr_reverse_maps);
 	pte_chain_unlock(page);
 	return;
 }
@@ -266,9 +353,10 @@
  *		pte_chain_lock		page_launder()
  *		    mm->page_table_lock	try_to_unmap_one(), trylock
  */
-static int FASTCALL(try_to_unmap_one(struct page *, pte_t *));
-static int try_to_unmap_one(struct page * page, pte_t * ptep)
+static int FASTCALL(try_to_unmap_one(struct page *, pte_addr_t));
+static int try_to_unmap_one(struct page * page, pte_addr_t paddr)
 {
+	pte_t *ptep = rmap_ptep_map(paddr);
 	unsigned long address = ptep_to_address(ptep);
 	struct mm_struct * mm = ptep_to_mm(ptep);
 	struct vm_area_struct * vma;
@@ -282,8 +370,11 @@
 	 * We need the page_table_lock to protect us from page faults,
 	 * munmap, fork, etc...
 	 */
-	if (!spin_trylock(&mm->page_table_lock))
+	if (!spin_trylock(&mm->page_table_lock)) {
+		rmap_ptep_unmap(ptep);
 		return SWAP_AGAIN;
+	}
+
 
 	/* During mremap, it's possible pages are not in a VMA. */
 	vma = find_vma(mm, address);
@@ -305,8 +396,7 @@
 
 	/* Store the swap location in the pte. See handle_pte_fault() ... */
 	if (PageSwapCache(page)) {
-		swp_entry_t entry;
-		entry.val = page->index;
+		swp_entry_t entry = { .val = page->index };
 		swap_duplicate(entry);
 		set_pte(ptep, swp_entry_to_pte(entry));
 	}
@@ -320,6 +410,7 @@
 	ret = SWAP_SUCCESS;
 
 out_unlock:
+	rmap_ptep_unmap(ptep);
 	spin_unlock(&mm->page_table_lock);
 	return ret;
 }
@@ -339,8 +430,9 @@
  */
 int try_to_unmap(struct page * page)
 {
-	struct pte_chain * pc, * next_pc, * prev_pc = NULL;
+	struct pte_chain *pc, *next_pc, *start;
 	int ret = SWAP_SUCCESS;
+	int victim_i = -1;
 
 	/* This page should not be on the pageout lists. */
 	if (PageReserved(page))
@@ -354,39 +446,60 @@
 	if (PageDirect(page)) {
 		ret = try_to_unmap_one(page, page->pte.direct);
 		if (ret == SWAP_SUCCESS) {
-			page->pte.direct = NULL;
+			page->pte.direct = 0;
 			ClearPageDirect(page);
 		}
-	} else {		
-		for (pc = page->pte.chain; pc; pc = next_pc) {
-			next_pc = pc->next;
-			switch (try_to_unmap_one(page, pc->ptep)) {
-				case SWAP_SUCCESS:
-					/* Free the pte_chain struct. */
-					pte_chain_free(pc, prev_pc, page);
-					continue;
-				case SWAP_AGAIN:
-					/* Skip this pte, remembering status. */
-					prev_pc = pc;
-					ret = SWAP_AGAIN;
-					continue;
-				case SWAP_FAIL:
-					ret = SWAP_FAIL;
-					goto give_up;
-				case SWAP_ERROR:
-					ret = SWAP_ERROR;
-					goto give_up;
+		goto out;
+	}		
+
+	start = page->pte.chain;
+	for (pc = start; pc; pc = next_pc) {
+		int i;
+
+		next_pc = pc->next;
+		if (next_pc)
+			prefetch(next_pc);
+		for (i = 0; i < NRPTE; i++) {
+			pte_addr_t pte_paddr = pc->ptes[i];
+
+			if (!pte_paddr)
+				continue;
+			if (victim_i == -1) 
+				victim_i = i;
+
+			switch (try_to_unmap_one(page, pte_paddr)) {
+			case SWAP_SUCCESS:
+				/*
+				 * Release a slot.  If we're releasing the
+				 * first pte in the first pte_chain then
+				 * pc->ptes[i] and start->ptes[victim_i] both
+				 * refer to the same thing.  It works out.
+				 */
+				pc->ptes[i] = start->ptes[victim_i];
+				start->ptes[victim_i] = 0;
+				dec_page_state(nr_reverse_maps);
+				victim_i++;
+				if (victim_i == NRPTE) {
+					page->pte.chain = start->next;
+					pte_chain_free(start);
+					start = page->pte.chain;
+					victim_i = 0;
+				}
+				break;
+			case SWAP_AGAIN:
+				/* Skip this pte, remembering status. */
+				ret = SWAP_AGAIN;
+				continue;
+			case SWAP_FAIL:
+				ret = SWAP_FAIL;
+				goto out;
+			case SWAP_ERROR:
+				ret = SWAP_ERROR;
+				goto out;
 			}
 		}
-give_up:
-		/* Check whether we can convert to direct pte pointer */
-		pc = page->pte.chain;
-		if (pc && !pc->next) {
-			page->pte.direct = pc->ptep;
-			SetPageDirect(page);
-			pte_chain_free(pc, NULL, NULL);
-		}
 	}
+out:
 	return ret;
 }
 
@@ -395,13 +508,20 @@
  ** functions.
  **/
 
+static void pte_chain_ctor(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct pte_chain *pc = p;
+
+	memset(pc, 0, sizeof(*pc));
+}
+
 void __init pte_chain_init(void)
 {
 	pte_chain_cache = kmem_cache_create(	"pte_chain",
 						sizeof(struct pte_chain),
 						0,
 						0,
-						NULL,
+						pte_chain_ctor,
 						NULL);
 
 	if (!pte_chain_cache)
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Sun Sep 15 19:19:37 2002
+++ b/mm/shmem.c	Sun Sep 15 19:19:37 2002
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
 #include <linux/shmem_fs.h>
 
 #include <asm/uaccess.h>
@@ -56,6 +57,11 @@
 static struct inode_operations shmem_dir_inode_operations;
 static struct vm_operations_struct shmem_vm_ops;
 
+static struct backing_dev_info shmem_backing_dev_info = {
+	.ra_pages	= 0,	/* No readahead */
+	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+};
+
 LIST_HEAD (shmem_inodes);
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
 atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */
@@ -789,6 +795,7 @@
 		inode->i_blocks = 0;
 		inode->i_rdev = NODEV;
 		inode->i_mapping->a_ops = &shmem_aops;
+		inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		info = SHMEM_I(inode);
 		spin_lock_init (&info->lock);
diff -Nru a/mm/swap.c b/mm/swap.c
--- a/mm/swap.c	Sun Sep 15 19:19:34 2002
+++ b/mm/swap.c	Sun Sep 15 19:19:34 2002
@@ -20,6 +20,7 @@
 #include <linux/pagevec.h>
 #include <linux/init.h>
 #include <linux/mm_inline.h>
+#include <linux/buffer_head.h>
 #include <linux/prefetch.h>
 
 /* How many pages do we try to swap or page in/out together? */
@@ -220,6 +221,23 @@
 	if (zone)
 		spin_unlock_irq(&zone->lru_lock);
 	pagevec_release(pvec);
+}
+
+/*
+ * Try to drop buffers from the pages in a pagevec
+ */
+void pagevec_strip(struct pagevec *pvec)
+{
+	int i;
+
+	for (i = 0; i < pagevec_count(pvec); i++) {
+		struct page *page = pvec->pages[i];
+
+		if (PagePrivate(page) && !TestSetPageLocked(page)) {
+			try_to_release_page(page, 0);
+			unlock_page(page);
+		}
+	}
 }
 
 /*
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Sun Sep 15 19:19:37 2002
+++ b/mm/swap_state.c	Sun Sep 15 19:19:37 2002
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
 #include <linux/buffer_head.h>	/* block_sync_page() */
 
 #include <asm/pgtable.h>
@@ -25,20 +26,26 @@
 	.i_mapping	= &swapper_space,
 };
 
+static struct backing_dev_info swap_backing_dev_info = {
+	.ra_pages	= 0,	/* No readahead */
+	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+};
+
 extern struct address_space_operations swap_aops;
 
 struct address_space swapper_space = {
-	.page_tree	= RADIX_TREE_INIT(GFP_ATOMIC),
-	.page_lock	= RW_LOCK_UNLOCKED,
-	.clean_pages	= LIST_HEAD_INIT(swapper_space.clean_pages),
-	.dirty_pages	= LIST_HEAD_INIT(swapper_space.dirty_pages),
-	.io_pages	= LIST_HEAD_INIT(swapper_space.io_pages),
-	.locked_pages	= LIST_HEAD_INIT(swapper_space.locked_pages),
-	.host		= &swapper_inode,
-	.a_ops		= &swap_aops,
-	.i_shared_lock	= SPIN_LOCK_UNLOCKED,
-	.private_lock	= SPIN_LOCK_UNLOCKED,
-	.private_list	= LIST_HEAD_INIT(swapper_space.private_list),
+	.page_tree		= RADIX_TREE_INIT(GFP_ATOMIC),
+	.page_lock		= RW_LOCK_UNLOCKED,
+	.clean_pages		= LIST_HEAD_INIT(swapper_space.clean_pages),
+	.dirty_pages		= LIST_HEAD_INIT(swapper_space.dirty_pages),
+	.io_pages		= LIST_HEAD_INIT(swapper_space.io_pages),
+	.locked_pages		= LIST_HEAD_INIT(swapper_space.locked_pages),
+	.host			= &swapper_inode,
+	.a_ops			= &swap_aops,
+	.backing_dev_info	= &swap_backing_dev_info,
+	.i_shared_lock		= SPIN_LOCK_UNLOCKED,
+	.private_lock		= SPIN_LOCK_UNLOCKED,
+	.private_list		= LIST_HEAD_INIT(swapper_space.private_list),
 };
 
 #define INC_CACHE_INFO(x)	do { swap_cache_info.x++; } while (0)
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Sun Sep 15 19:19:29 2002
+++ b/mm/vmscan.c	Sun Sep 15 19:19:29 2002
@@ -75,7 +75,7 @@
 	struct address_space *mapping = page->mapping;
 
 	/* Page is in somebody's page tables. */
-	if (page->pte.chain)
+	if (page_mapped(page))
 		return 1;
 
 	/* XXX: does this happen ? */
@@ -140,7 +140,7 @@
 		 *
 		 * XXX: implement swap clustering ?
 		 */
-		if (page->pte.chain && !mapping && !PagePrivate(page)) {
+		if (page_mapped(page) && !mapping && !PagePrivate(page)) {
 			pte_chain_unlock(page);
 			if (!add_to_swap(page))
 				goto activate_locked;
@@ -151,7 +151,7 @@
 		 * The page is mapped into the page tables of one or more
 		 * processes. Try to unmap it here.
 		 */
-		if (page->pte.chain && mapping) {
+		if (page_mapped(page) && mapping) {
 			switch (try_to_unmap(page)) {
 			case SWAP_ERROR:
 			case SWAP_FAIL:
@@ -208,7 +208,7 @@
 		 * Otherwise, leave the page on the LRU so it is swappable.
 		 */
 		if (PagePrivate(page)) {
-			if (!try_to_release_page(page, 0))
+			if (!try_to_release_page(page, gfp_mask))
 				goto keep_locked;
 			if (!mapping && page_count(page) == 1)
 				goto free_it;
@@ -408,9 +408,9 @@
 	while (!list_empty(&l_hold)) {
 		page = list_entry(l_hold.prev, struct page, lru);
 		list_del(&page->lru);
-		if (page->pte.chain) {
+		if (page_mapped(page)) {
 			pte_chain_lock(page);
-			if (page->pte.chain && page_referenced(page)) {
+			if (page_mapped(page) && page_referenced(page)) {
 				pte_chain_unlock(page);
 				list_add(&page->lru, &l_active);
 				continue;
@@ -433,10 +433,17 @@
 		list_move(&page->lru, &zone->inactive_list);
 		if (!pagevec_add(&pvec, page)) {
 			spin_unlock_irq(&zone->lru_lock);
+			if (buffer_heads_over_limit)
+				pagevec_strip(&pvec);
 			__pagevec_release(&pvec);
 			spin_lock_irq(&zone->lru_lock);
 		}
 	}
+	if (buffer_heads_over_limit) {
+		spin_unlock_irq(&zone->lru_lock);
+		pagevec_strip(&pvec);
+		spin_lock_irq(&zone->lru_lock);
+	}
 	while (!list_empty(&l_active)) {
 		page = list_entry(l_active.prev, struct page, lru);
 		prefetchw_prev_lru_page(page, &l_active, flags);
@@ -698,7 +705,7 @@
 {
 	printk("Starting kswapd\n");
 	swap_setup();
-	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+	kernel_thread(kswapd, NULL, CLONE_KERNEL);
 	return 0;
 }
 
diff -Nru a/net/802/p8022.c b/net/802/p8022.c
--- a/net/802/p8022.c	Sun Sep 15 19:19:29 2002
+++ b/net/802/p8022.c	Sun Sep 15 19:19:29 2002
@@ -28,18 +28,8 @@
 static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
 			 unsigned char *dest)
 {
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-
-	prim.data                 = &prim_data;
-	prim.sap                  = dl->sap;
-	prim.prim                 = LLC_DATAUNIT_PRIM;
-	prim_data.test.skb        = skb;
-	prim_data.test.saddr.lsap = dl->sap->laddr.lsap;
-	prim_data.test.daddr.lsap = dl->sap->laddr.lsap;
-	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
-	memcpy(prim_data.test.daddr.mac, dest, IFHWADDRLEN);
-	return dl->sap->req(&prim);
+	llc_build_and_send_ui_pkt(dl->sap, skb, dest, dl->sap->laddr.lsap);
+	return 0;
 }
 
 struct datalink_proto *register_8022_client(unsigned char type,
diff -Nru a/net/802/psnap.c b/net/802/psnap.c
--- a/net/802/psnap.c	Sun Sep 15 19:19:45 2002
+++ b/net/802/psnap.c	Sun Sep 15 19:19:45 2002
@@ -86,19 +86,9 @@
 static int snap_request(struct datalink_proto *dl,
 			struct sk_buff *skb, u8 *dest)
 {
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-
 	memcpy(skb_push(skb, 5), dl->type, 5);
-	prim.data                 = &prim_data;
-	prim.sap                  = snap_sap;
-	prim.prim                 = LLC_DATAUNIT_PRIM;
-	prim_data.test.skb        = skb;
-	prim_data.test.saddr.lsap = snap_sap->laddr.lsap;
-	prim_data.test.daddr.lsap = snap_sap->laddr.lsap;
-	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
-	memcpy(prim_data.test.daddr.mac, dest, IFHWADDRLEN);
-	return snap_sap->req(&prim);
+	llc_build_and_send_ui_pkt(snap_sap, skb, dest, snap_sap->laddr.lsap);
+	return 0;
 }
 
 /*
diff -Nru a/net/8021q/vlan.c b/net/8021q/vlan.c
--- a/net/8021q/vlan.c	Sun Sep 15 19:20:20 2002
+++ b/net/8021q/vlan.c	Sun Sep 15 19:20:20 2002
@@ -626,7 +626,7 @@
 			ret = unregister_vlan_dev(dev,
 						  VLAN_DEV_INFO(vlandev)->vlan_id);
 
-			unregister_netdev(vlandev);
+			unregister_netdevice(vlandev);
 
 			/* Group was destroyed? */
 			if (ret == 1)
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Sun Sep 15 19:19:46 2002
+++ b/net/core/dev.c	Sun Sep 15 19:19:46 2002
@@ -694,10 +694,14 @@
 	 *	Call device private open method
 	 */
 	if (try_inc_mod_count(dev->owner)) {
+		set_bit(__LINK_STATE_START, &dev->state);
 		if (dev->open) {
 			ret = dev->open(dev);
-			if (ret && dev->owner)
-				__MOD_DEC_USE_COUNT(dev->owner);
+			if (ret) {
+				clear_bit(__LINK_STATE_START, &dev->state);
+				if (dev->owner)
+					__MOD_DEC_USE_COUNT(dev->owner);
+			}
 		}
 	} else {
 		ret = -ENODEV;
@@ -712,8 +716,6 @@
 		 *	Set the flags.
 		 */
 		dev->flags |= IFF_UP;
-
-		set_bit(__LINK_STATE_START, &dev->state);
 
 		/*
 		 *	Initialize multicasting status
diff -Nru a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
--- a/net/ipv4/ip_options.c	Sun Sep 15 19:19:29 2002
+++ b/net/ipv4/ip_options.c	Sun Sep 15 19:19:29 2002
@@ -266,7 +266,7 @@
 	for (l = opt->optlen; l > 0; ) {
 		switch (*optptr) {
 		      case IPOPT_END:
-			for (optptr++, l--; l>0; l--) {
+			for (optptr++, l--; l>0; optptr++, l--) {
 				if (*optptr != IPOPT_END) {
 					*optptr = IPOPT_END;
 					opt->is_changed = 1;
diff -Nru a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
--- a/net/ipv4/netfilter/ipt_owner.c	Sun Sep 15 19:20:24 2002
+++ b/net/ipv4/netfilter/ipt_owner.c	Sun Sep 15 19:20:24 2002
@@ -14,12 +14,12 @@
 static int
 match_comm(const struct sk_buff *skb, const char *comm)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	struct files_struct *files;
 	int i;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		if(strncmp(p->comm, comm, sizeof(p->comm)))
 			continue;
 
@@ -38,7 +38,7 @@
 			read_unlock(&files->file_lock);
 		}
 		task_unlock(p);
-	}
+	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
 	return 0;
 }
@@ -77,12 +77,12 @@
 static int
 match_sid(const struct sk_buff *skb, pid_t sid)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	struct file *file = skb->sk->socket->file;
 	int i, found=0;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		struct files_struct *files;
 		if (p->session != sid)
 			continue;
@@ -100,9 +100,10 @@
 			read_unlock(&files->file_lock);
 		}
 		task_unlock(p);
-		if(found)
-			break;
-	}
+		if (found)
+			goto out;
+	} while_each_thread(g, p);
+out:
 	read_unlock(&tasklist_lock);
 
 	return found;
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Sun Sep 15 19:19:29 2002
+++ b/net/ipv4/tcp_input.c	Sun Sep 15 19:19:29 2002
@@ -3289,17 +3289,24 @@
 			if ((s32)(tp->rcv_tsval - tp->ts_recent) < 0)
 				goto slow_path;
 
-			/* Predicted packet is in window by definition.
-			 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
-			 * Hence, check seq<=rcv_wup reduces to:
+			/* DO NOT update ts_recent here, if checksum fails
+			 * and timestamp was corrupted part, it will result
+			 * in a hung connection since we will drop all
+			 * future packets due to the PAWS test.
 			 */
-			if (tp->rcv_nxt == tp->rcv_wup)
-				tcp_store_ts_recent(tp);
 		}
 
 		if (len <= tcp_header_len) {
 			/* Bulk data transfer: sender */
 			if (len == tcp_header_len) {
+				/* Predicted packet is in window by definition.
+				 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+				 * Hence, check seq<=rcv_wup reduces to:
+				 */
+				if (tcp_header_len ==
+				    (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
+				    tp->rcv_nxt == tp->rcv_wup)
+					tcp_store_ts_recent(tp);
 				/* We know that such packets are checksummed
 				 * on entry.
 				 */
@@ -3325,11 +3332,29 @@
 					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 					NET_INC_STATS_BH(TCPHPHitsToUser);
 					eaten = 1;
+					/* Predicted packet is in window by definition.
+					 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+					 * Hence, check seq<=rcv_wup reduces to:
+					 */
+					if (tcp_header_len ==
+					    (sizeof(struct tcphdr) +
+					     TCPOLEN_TSTAMP_ALIGNED) &&
+					    tp->rcv_nxt == tp->rcv_wup)
+						tcp_store_ts_recent(tp);
 				}
 			}
 			if (!eaten) {
 				if (tcp_checksum_complete_user(sk, skb))
 					goto csum_error;
+
+				/* Predicted packet is in window by definition.
+				 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
+				 * Hence, check seq<=rcv_wup reduces to:
+				 */
+				if (tcp_header_len ==
+				    (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) &&
+				    tp->rcv_nxt == tp->rcv_wup)
+					tcp_store_ts_recent(tp);
 
 				if ((int)skb->truesize > sk->forward_alloc)
 					goto step5;
diff -Nru a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
--- a/net/ipv6/netfilter/ip6t_owner.c	Sun Sep 15 19:20:20 2002
+++ b/net/ipv6/netfilter/ip6t_owner.c	Sun Sep 15 19:20:20 2002
@@ -49,12 +49,12 @@
 static int
 match_sid(const struct sk_buff *skb, pid_t sid)
 {
-	struct task_struct *p;
+	struct task_struct *g, *p;
 	struct file *file = skb->sk->socket->file;
 	int i, found=0;
 
 	read_lock(&tasklist_lock);
-	for_each_task(p) {
+	do_each_thread(g, p) {
 		struct files_struct *files;
 		if (p->session != sid)
 			continue;
@@ -72,9 +72,10 @@
 			read_unlock(&files->file_lock);
 		}
 		task_unlock(p);
-		if(found)
-			break;
-	}
+		if (found)
+			goto out;
+	} while_each_thread(g, p);
+out:
 	read_unlock(&tasklist_lock);
 
 	return found;
diff -Nru a/net/llc/llc_actn.c b/net/llc/llc_actn.c
--- a/net/llc/llc_actn.c	Sun Sep 15 19:19:29 2002
+++ b/net/llc/llc_actn.c	Sun Sep 15 19:19:29 2002
@@ -34,7 +34,6 @@
 	station->ack_timer.data     = (unsigned long)station;
 	station->ack_timer.function = llc_station_ack_tmr_callback;
 	add_timer(&station->ack_timer);
-	station->ack_tmr_running = 1;
 	return 0;
 }
 
@@ -134,14 +133,12 @@
 static void llc_station_ack_tmr_callback(unsigned long timeout_data)
 {
 	struct llc_station *station = (struct llc_station *)timeout_data;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	station->ack_tmr_running = 0;
 	if (skb) {
 		struct llc_station_state_ev *ev = llc_station_ev(skb);
 
 		ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
-		ev->data.tmr.timer_specific = NULL;
-		llc_station_send_ev(station, skb);
+		llc_station_state_process(station, skb);
 	}
 }
diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
--- a/net/llc/llc_c_ac.c	Sun Sep 15 19:20:24 2002
+++ b/net/llc/llc_c_ac.c	Sun Sep 15 19:20:24 2002
@@ -48,7 +48,6 @@
 
 		llc->remote_busy_flag = 0;
 		del_timer(&llc->busy_state_timer.timer);
-		llc->busy_state_timer.running = 0;
 		nr = LLC_I_GET_NR(pdu);
 		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
 	}
@@ -65,24 +64,14 @@
 	sap = llc_sap_find(dsap);
 	if (sap) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-		struct llc_prim_if_block *prim = &sap->llc_ind_prim;
-		union llc_u_prim_data *prim_data = prim->data;
 		struct llc_opt *llc = llc_sk(sk);
 
-		prim_data->conn.daddr.lsap = dsap;
 		llc_pdu_decode_sa(skb, llc->daddr.mac);
 		llc_pdu_decode_da(skb, llc->laddr.mac);
 		llc->dev = skb->dev;
-		prim_data->conn.pri = 0;
-		prim_data->conn.sk  = sk;
-		prim_data->conn.dev = skb->dev;
-		memcpy(&prim_data->conn.daddr, &llc->laddr, sizeof(llc->laddr));
-		memcpy(&prim_data->conn.saddr, &llc->daddr, sizeof(llc->daddr));
-		prim->data   = prim_data;
-		prim->prim   = LLC_CONN_PRIM;
-		prim->sap    = llc->sap;
-		ev->flag     = 1;
-		ev->ind_prim = prim;
+		/* FIXME: find better way to notify upper layer */
+		ev->flag     = LLC_CONN_PRIM + 1;
+		ev->ind_prim = (void *)1;
 		rc = 0;
 	}
 	return rc;
@@ -91,42 +80,22 @@
 int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
-	struct llc_sap *sap = llc->sap;
-	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
-	union llc_u_prim_data *prim_data = prim->data;
 
-	prim_data->conn.sk     = sk;
-	prim_data->conn.pri    = 0;
-	prim_data->conn.status = ev->status;
-	prim_data->conn.link   = llc->link;
-	prim_data->conn.dev    = skb->dev;
-	prim->data   = prim_data;
-	prim->prim   = LLC_CONN_PRIM;
-	prim->sap    = sap;
-	ev->flag     = 1;
-	ev->cfm_prim = prim;
+	ev->flag     = LLC_CONN_PRIM + 1;
+	ev->cfm_prim = (void *)1;
 	return 0;
 }
 
 static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
-	struct llc_sap *sap = llc->sap;
-	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
-	union llc_u_prim_data *prim_data = prim->data;
 
-	prim_data->data.sk     = sk;
-	prim_data->data.pri    = 0;
-	prim_data->data.link   = llc->link;
-	prim_data->data.status = LLC_STATUS_RECEIVED;
-	prim_data->data.skb    = NULL;
-	prim->data	       = prim_data;
-	prim->prim	       = LLC_DATA_PRIM;
-	prim->sap	       = sap;
-	ev->flag	       = 1;
-	ev->cfm_prim	       = prim;
+	/*
+	 * FIXME: find better way to tell upper layer that the packet was
+	 * confirmed by the other endpoint
+	 */
+	ev->flag     = LLC_DATA_PRIM + 1;
+	ev->cfm_prim = (void *)1;
 	return 0;
 }
 
@@ -164,19 +133,15 @@
 		rc = 1;
 	}
 	if (!rc) {
-		struct llc_opt *llc = llc_sk(sk);
-		struct llc_sap *sap = llc->sap;
-		struct llc_prim_if_block *prim = &sap->llc_ind_prim;
-		union llc_u_prim_data *prim_data = prim->data;
-
-		prim_data->disc.sk     = sk;
-		prim_data->disc.reason = reason;
-		prim_data->disc.link   = llc->link;
-		prim->data	       = prim_data;
-		prim->prim	       = LLC_DISC_PRIM;
-		prim->sap	       = llc->sap;
-		ev->flag	       = 1;
-		ev->ind_prim	       = prim;
+		/*
+		 * FIXME: ev needs reason field,
+		 * perhaps the ev->status is enough,
+		 * have to check,
+		 * better way to signal its a disc
+		 */
+		/* prim_data->disc.reason = reason; */
+		ev->flag     = LLC_DISC_PRIM + 1;
+		ev->ind_prim = (void *)1;
 	}
 	return rc;
 }
@@ -184,19 +149,11 @@
 int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
-	struct llc_sap *sap = llc->sap;
-	struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
-	union llc_u_prim_data *prim_data = prim->data;
 
-	prim_data->disc.sk     = sk;
-	prim_data->disc.reason = ev->status;
-	prim_data->disc.link   = llc->link;
-	prim->data	       = prim_data;
-	prim->prim	       = LLC_DISC_PRIM;
-	prim->sap	       = sap;
-	ev->flag	       = 1;
-	ev->cfm_prim	       = prim;
+	/* here we use the ev->status, humm */
+	/* prim_data->disc.reason = ev->status; */
+	ev->flag     = LLC_DISC_PRIM + 1;
+	ev->cfm_prim = (void *)1;
 	return 0;
 }
 
@@ -294,10 +251,8 @@
 {
 	struct llc_opt *llc = llc_sk(sk);
 
-	if (llc->data_flag == 2) {
+	if (llc->data_flag == 2)
 		del_timer(&llc->rej_sent_timer.timer);
-		llc->rej_sent_timer.running = 0;
-	}
 	return 0;
 }
 
@@ -714,7 +669,6 @@
 		llc->busy_state_timer.timer.data     = (unsigned long)sk;
 		llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
 		add_timer(&llc->busy_state_timer.timer);
-		llc->busy_state_timer.running = 1;
 	}
 	return 0;
 }
@@ -957,7 +911,6 @@
 	llc->pf_cycle_timer.timer.data     = (unsigned long)sk;
 	llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
 	add_timer(&llc->pf_cycle_timer.timer);
-	llc->pf_cycle_timer.running = 1;
 	return 0;
 }
 
@@ -1204,13 +1157,9 @@
 	struct llc_opt *llc = llc_sk(sk);
 
 	del_timer(&llc->pf_cycle_timer.timer);
-	llc->pf_cycle_timer.running = 0;
 	del_timer(&llc->ack_timer.timer);
-	llc->ack_timer.running = 0;
 	del_timer(&llc->rej_sent_timer.timer);
-	llc->rej_sent_timer.running = 0;
 	del_timer(&llc->busy_state_timer.timer);
-	llc->busy_state_timer.running = 0;
 	llc->ack_must_be_send = 0;
 	llc->ack_pf = 0;
 	return 0;
@@ -1221,11 +1170,8 @@
 	struct llc_opt *llc = llc_sk(sk);
 
 	del_timer(&llc->rej_sent_timer.timer);
-	llc->rej_sent_timer.running = 0;
 	del_timer(&llc->pf_cycle_timer.timer);
-	llc->pf_cycle_timer.running = 0;
 	del_timer(&llc->busy_state_timer.timer);
-	llc->busy_state_timer.running = 0;
 	llc->ack_must_be_send = 0;
 	llc->ack_pf = 0;
 	return 0;
@@ -1240,7 +1186,6 @@
 	llc->ack_timer.timer.data     = (unsigned long)sk;
 	llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
 	add_timer(&llc->ack_timer.timer);
-	llc->ack_timer.running = 1;
 	return 0;
 }
 
@@ -1254,7 +1199,6 @@
 	llc->rej_sent_timer.timer.data     = (unsigned long)sk;
 	llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
 	add_timer(&llc->rej_sent_timer.timer);
-	llc->rej_sent_timer.running = 1;
 	return 0;
 }
 
@@ -1263,13 +1207,12 @@
 {
 	struct llc_opt *llc = llc_sk(sk);
 
-	if (!llc->ack_timer.running) {
+	if (!timer_pending(&llc->ack_timer.timer)) {
 		llc->ack_timer.timer.expires  = jiffies +
 						llc->ack_timer.expire * HZ;
 		llc->ack_timer.timer.data     = (unsigned long)sk;
 		llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
 		add_timer(&llc->ack_timer.timer);
-		llc->ack_timer.running = 1;
 	}
 	return 0;
 }
@@ -1277,7 +1220,6 @@
 int llc_conn_ac_stop_ack_timer(struct sock *sk, struct sk_buff *skb)
 {
 	del_timer(&llc_sk(sk)->ack_timer.timer);
-	llc_sk(sk)->ack_timer.running = 0;
 	return 0;
 }
 
@@ -1286,7 +1228,6 @@
 	struct llc_opt *llc = llc_sk(sk);
 
 	del_timer(&llc->pf_cycle_timer.timer);
-	llc->pf_cycle_timer.running = 0;
 	llc->p_flag = 0;
 	return 0;
 }
@@ -1294,7 +1235,6 @@
 int llc_conn_ac_stop_rej_timer(struct sock *sk, struct sk_buff *skb)
 {
 	del_timer(&llc_sk(sk)->rej_sent_timer.timer);
-	llc_sk(sk)->rej_sent_timer.running = 0;
 	return 0;
 }
 
@@ -1312,7 +1252,6 @@
 	if (acked > 0 || (llc->dev->flags & IFF_LOOPBACK)) {
 		llc->retry_count = 0;
 		del_timer(&llc->ack_timer.timer);
-		llc->ack_timer.running = 0;
 		if (llc->failed_data_req) {
 			/* already, we did not accept data from upper layer
 			 * (tx_window full or unacceptable state). Now, we
@@ -1327,7 +1266,6 @@
 			llc->ack_timer.timer.data     = (unsigned long)sk;
 			llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
 			add_timer(&llc->ack_timer.timer);
-			llc->ack_timer.running = 1;
 	       }
 	} else if (llc->failed_data_req) {
 		llc_pdu_decode_pf_bit(skb, &fbit);
@@ -1342,12 +1280,15 @@
 int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
-	u8 f_bit;
 
-	if (!LLC_PDU_IS_RSP(pdu) &&
-	    !llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) {
-		llc_sk(sk)->p_flag = 0;
-		llc_conn_ac_stop_p_timer(sk, skb);
+	if (!LLC_PDU_IS_RSP(pdu)) {
+		u8 f_bit;
+
+		llc_pdu_decode_pf_bit(skb, &f_bit);
+		if (f_bit) {
+			llc_sk(sk)->p_flag = 0;
+			llc_conn_ac_stop_p_timer(sk, skb);
+		}
 	}
 	return 0;
 }
@@ -1459,61 +1400,65 @@
 void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	llc_sk(sk)->pf_cycle_timer.running = 0;
+	bh_lock_sock(sk);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
+		skb->sk  = sk;
 		ev->type = LLC_CONN_EV_TYPE_P_TMR;
-		ev->data.tmr.timer_specific = NULL;
 		llc_process_tmr_ev(sk, skb);
 	}
+	bh_unlock_sock(sk);
 }
 
 static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	llc_sk(sk)->busy_state_timer.running = 0;
+	bh_lock_sock(sk);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
+		skb->sk  = sk;
 		ev->type = LLC_CONN_EV_TYPE_BUSY_TMR;
-		ev->data.tmr.timer_specific = NULL;
 		llc_process_tmr_ev(sk, skb);
 	}
+	bh_unlock_sock(sk);
 }
 
 void llc_conn_ack_tmr_cb(unsigned long timeout_data)
 {
 	struct sock* sk = (struct sock *)timeout_data;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	llc_sk(sk)->ack_timer.running = 0;
+	bh_lock_sock(sk);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
+		skb->sk  = sk;
 		ev->type = LLC_CONN_EV_TYPE_ACK_TMR;
-		ev->data.tmr.timer_specific = NULL;
 		llc_process_tmr_ev(sk, skb);
 	}
+	bh_unlock_sock(sk);
 }
 
 static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	llc_sk(sk)->rej_sent_timer.running = 0;
+	bh_lock_sock(sk);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
+		skb->sk  = sk;
 		ev->type = LLC_CONN_EV_TYPE_REJ_TMR;
-		ev->data.tmr.timer_specific = NULL;
 		llc_process_tmr_ev(sk, skb);
 	}
+	bh_unlock_sock(sk);
 }
 
 int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
@@ -1541,14 +1486,11 @@
  *	llc_conn_disc - removes connection from SAP list and frees it
  *	@sk: closed connection
  *	@skb: occurred event
- *
- *	Returns 2, to indicate the state machine that the connection was freed.
  */
 int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
 {
-	llc_sap_unassign_sock(llc_sk(sk)->sap, sk);
-	llc_sock_free(sk);
-	return 2;
+	/* FIXME: this thing seems to want to die */
+	return 0;
 }
 
 /**
@@ -1560,7 +1502,7 @@
  */
 int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
 {
-	llc_sock_reset(sk);
+	llc_sk_reset(sk);
 	return 0;
 }
 
@@ -1589,24 +1531,21 @@
  *	This function is called from timer callback functions. When connection
  *	is busy (during sending a data frame) timer expiration event must be
  *	queued. Otherwise this event can be sent to connection state machine.
- *	Queued events will process by process_rxframes_events function after
- *	sending data frame. Returns 0 for success, 1 otherwise.
+ *	Queued events will process by llc_backlog_rcv function after sending
+ *	data frame.
  */
 static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
 {
-	bh_lock_sock(sk);
 	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
 		printk(KERN_WARNING "%s: timer called on closed connection\n",
 		       __FUNCTION__);
 		llc_conn_free_ev(skb);
-		goto out;
-	}
-	if (!sk->lock.users)
-		llc_conn_send_ev(sk, skb);
-	else {
-		llc_set_backlog_type(skb, LLC_EVENT);
-		sk_add_backlog(sk, skb);
+	} else {
+		if (!sk->lock.users)
+			llc_conn_state_process(sk, skb);
+		else {
+			llc_set_backlog_type(skb, LLC_EVENT);
+			sk_add_backlog(sk, skb);
+		}
 	}
-out:
-	bh_unlock_sock(sk);
 }
diff -Nru a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
--- a/net/llc/llc_c_ev.c	Sun Sep 15 19:19:28 2002
+++ b/net/llc/llc_c_ev.c	Sun Sep 15 19:19:28 2002
@@ -241,9 +241,8 @@
 	u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
 		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
 	if (!rc)
-		dprintk(KERN_WARNING "rx_i_cmd_p_bit_set_x_inval_ns matched,"
-			"state = %d, ns = %d, vr = %d\n",
-			llc_sk(sk)->state, ns, vr);
+		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
+			__FUNCTION__, llc_sk(sk)->state, ns, vr);
 	return rc;
 }
 
@@ -317,9 +316,8 @@
 	u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
 		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
 	if (!rc)
-		dprintk(KERN_WARNING "conn_ev_rx_i_rsp_fbit_set_x_inval_ns "
-			"matched : state = %d, ns = %d, vr = %d\n",
-			llc_sk(sk)->state, ns, vr);
+		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
+			__FUNCTION__, llc_sk(sk)->state, ns, vr);
 	return rc;
 }
 
@@ -584,9 +582,8 @@
 	if (!LLC_PDU_IS_CMD(pdu) &&
 	    (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
 	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
-		dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr matched, state = "
-				 "%d, vs = %d, nr = %d\n",
-				 llc_sk(sk)->state, vs, nr);
+		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
+			__FUNCTION__, llc_sk(sk)->state, vs, nr);
 		rc = 0;
 	}
 	return rc;
@@ -604,9 +601,8 @@
 	    (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
 	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
 		rc = 0;
-		dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set_x_inval_nr matched, "
-				 "state = %d, vs = %d, nr = %d\n",
-			llc_sk(sk)->state, vs, nr);
+		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
+			__FUNCTION__, llc_sk(sk)->state, vs, nr);
 	}
 	return rc;
 }
diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c
--- a/net/llc/llc_conn.c	Sun Sep 15 19:19:28 2002
+++ b/net/llc/llc_conn.c	Sun Sep 15 19:19:28 2002
@@ -18,6 +18,7 @@
 #include <net/llc_sap.h>
 #include <net/llc_conn.h>
 #include <net/sock.h>
+#include <linux/tcp.h>
 #include <net/llc_main.h>
 #include <net/llc_c_ev.h>
 #include <net/llc_c_ac.h>
@@ -38,65 +39,149 @@
 /* Offset table on connection states transition diagram */
 static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
 
+static void llc_save_primitive(struct sock *sk, struct sk_buff* skb,
+			       u8 ua, u8 test, u8 xid)
+{
+	struct llc_opt *llc = llc_sk(sk);
+	struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
+
+       /* save primitive for use by the user. */
+	addr->sllc_family = sk->family;
+	addr->sllc_arphrd = skb->dev->type;
+	addr->sllc_test   = test;
+	addr->sllc_xid    = xid;
+	addr->sllc_ua     = ua;
+	addr->sllc_dsap   = llc->sap->laddr.lsap;
+	memcpy(addr->sllc_dmac, llc->laddr.mac, IFHWADDRLEN);
+	addr->sllc_ssap	  = llc->daddr.lsap;
+	memcpy(addr->sllc_smac, llc->daddr.mac, IFHWADDRLEN);
+}
+
 /**
- *	llc_conn_send_event - sends event to connection state machine
+ *	llc_conn_state_process - sends event to connection state machine
  *	@sk: connection
  *	@skb: occurred event
  *
- *	Sends an event to connection state machine. after processing event
+ *	Sends an event to connection state machine. After processing event
  *	(executing it's actions and changing state), upper layer will be
  *	indicated or confirmed, if needed. Returns 0 for success, 1 for
  *	failure. The socket lock has to be held before calling this function.
  */
-int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb)
+int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 {
 	/* sending event to state machine */
 	int rc = llc_conn_service(sk, skb);
 	struct llc_opt *llc = llc_sk(sk);
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 	u8 flag = ev->flag;
+	u8 status = ev->status;
 	struct llc_prim_if_block *ind_prim = ev->ind_prim;
 	struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
 
-	llc_conn_free_ev(skb);
-#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY
-	/* check if the connection was freed by the state machine by
-	 * means of llc_conn_disc */
-	if (rc == 2) {
-		printk(KERN_INFO "%s: rc == 2\n", __FUNCTION__);
-		rc = -ECONNABORTED;
-		goto out;
-	}
-#endif	/* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */
+	/*
+	 * FIXME: this will vanish as soon I get rid of the last prim crap
+	 */
+	if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1 &&
+	    flag != LLC_DISC_PRIM + 1)
+		llc_conn_free_ev(skb);
+	else if (ind_prim && cfm_prim)
+		skb_get(skb);
 	if (!flag)   /* indicate or confirm not required */
 		goto out;
 	rc = 0;
-	if (ind_prim) /* indication required */
-		llc->sap->ind(ind_prim);
+	if (ind_prim) { /* indication required */
+		/*
+		 * FIXME: this will be saner as soon I get rid of the double
+		 *	  sock crap
+		 */
+		switch (flag) {
+		case LLC_DATA_PRIM + 1:
+			llc_save_primitive(sk, skb, 0, 0, 0);
+			if (sock_queue_rcv_skb(sk, skb)) {
+				/*
+				 * FIXME: have to sync the LLC state
+				 *        machine wrt mem usage with
+				 *        sk->{r,w}mem_alloc, will do
+				 *        this soon 8)
+				 */
+				printk(KERN_ERR
+				       "%s: sock_queue_rcv_skb failed!\n",
+				       __FUNCTION__);
+				kfree_skb(skb);
+			}
+			break;
+		case LLC_CONN_PRIM + 1: {
+			struct sock *parent = skb->sk;
+
+			skb->sk = sk;
+			skb_queue_tail(&parent->receive_queue, skb);
+			sk->state_change(parent);
+		}
+			break;
+		case LLC_DISC_PRIM + 1:
+			sock_hold(sk);
+			if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) {
+				sk->shutdown       = SHUTDOWN_MASK;
+				sk->socket->state  = SS_UNCONNECTED;
+				sk->state          = TCP_CLOSE;
+				if (!sk->dead) {
+					sk->state_change(sk);
+					sk->dead = 1;
+				}
+			}
+			kfree_skb(skb);
+			sock_put(sk);
+			break;
+		default:
+			llc->sap->ind(ind_prim);
+		}
+	}
 	if (!cfm_prim)  /* confirmation not required */
 		goto out;
-	/* data confirm has preconditions */
-	if (cfm_prim->prim != LLC_DATA_PRIM) {
+	/* FIXME: see FIXMEs above */
+	switch (flag) {
+	case LLC_DATA_PRIM + 1:
+		if (!llc_data_accept_state(llc->state))
+			/* In this state, we can send I pdu */
+			sk->write_space(sk);
+		else
+			rc = llc->failed_data_req = 1;
+		break;
+	case LLC_CONN_PRIM + 1:
+		if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
+			goto out_kfree_skb;
+		if (status) {
+			sk->socket->state = SS_UNCONNECTED;
+			sk->state         = TCP_CLOSE;
+		} else {
+			sk->socket->state = SS_CONNECTED;
+			sk->state         = TCP_ESTABLISHED;
+		}
+		sk->state_change(sk);
+		break;
+	case LLC_DISC_PRIM + 1:
+		sock_hold(sk);
+		if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) {
+			sock_put(sk);
+			goto out_kfree_skb;
+		}
+		sk->socket->state = SS_UNCONNECTED;
+		sk->state         = TCP_CLOSE;
+		sk->state_change(sk);
+		sock_put(sk);
+		break;
+	default:
 		llc->sap->conf(cfm_prim);
 		goto out;
 	}
-	if (!llc_data_accept_state(llc->state)) {
-		/* In this state, we can send I pdu */
-		/* FIXME: check if we don't need to see if sk->lock.users != 0
-		 * is needed here
-		 */
-		rc = llc->sap->conf(cfm_prim);
-		if (rc) /* confirmation didn't accept by upper layer */
-			llc->failed_data_req = 1;
-	} else
-		llc->failed_data_req = 1;
+out_kfree_skb:
+	kfree_skb(skb);
 out:
 	return rc;
 }
 
 void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
 {
-	llc_sock_assert(sk);
 	/* queue PDU to send to MAC layer */
 	skb_queue_tail(&sk->write_queue, skb);
 	llc_conn_send_pdus(sk);
@@ -109,26 +194,15 @@
  *
  *	Sends received data pdu to upper layer (by using indicate function).
  *	Prepares service parameters (prim and prim_data). calling indication
- *	function will be done in llc_conn_send_ev.
+ *	function will be done in llc_conn_state_process.
  */
 void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-	struct llc_opt *llc = llc_sk(sk);
-	struct llc_sap *sap = llc->sap;
-	struct llc_prim_if_block *prim = &sap->llc_ind_prim;
-	union llc_u_prim_data *prim_data = prim->data;
-
-	prim_data->data.sk   = sk;
-	prim_data->data.pri  = 0;
-	prim_data->data.skb  = skb;
-	prim_data->data.link = llc->link;
-	prim->data	     = prim_data;
-	prim->prim	     = LLC_DATA_PRIM;
-	prim->sap	     = sap;
-	ev->flag	     = 1;
-	/* saving prepd prim in event for future use in llc_conn_send_ev */
-	ev->ind_prim	     = prim;
+
+	/* FIXME: indicate that we should send this to the upper layer */
+	ev->flag     = LLC_DATA_PRIM + 1;
+	ev->ind_prim = (void *)1;
 }
 
 /**
@@ -369,11 +443,10 @@
  *	llc_exec_conn_trans_actions - executes related actions
  *	@sk: connection
  *	@trans: transition that it's actions must be performed
- *	@skb: happened event
+ *	@skb: event
  *
  *	Executes actions that is related to happened event. Returns 0 for
- *	success, 1 to indicate failure of at least one action or 2 if the
- *	connection was freed (llc_conn_disc was called)
+ *	success, 1 to indicate failure of at least one action.
  */
 static int llc_exec_conn_trans_actions(struct sock *sk,
 				       struct llc_conn_state_trans *trans,
@@ -396,7 +469,7 @@
 }
 
 /**
- *	llc_find_sock - Finds connection in sap for the remote/local sap/mac
+ *	llc_lookup_established - Finds connection for the remote/local sap/mac
  *	@sap: SAP
  *	@daddr: address of remote LLC (MAC + SAP)
  *	@laddr: address of local LLC (MAC + SAP)
@@ -405,8 +478,8 @@
  *	mac, remote sap, local mac, and local sap. Returns pointer for
  *	connection found, %NULL otherwise.
  */
-struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
-			   struct llc_addr *laddr)
+struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
+				    struct llc_addr *laddr)
 {
 	struct sock *rc = NULL;
 	struct list_head *entry;
@@ -419,8 +492,8 @@
 
 		if (llc->laddr.lsap == laddr->lsap &&
 		    llc->daddr.lsap == daddr->lsap &&
-		    !memcmp(llc->laddr.mac, laddr->mac, ETH_ALEN) &&
-		    !memcmp(llc->daddr.mac, daddr->mac, ETH_ALEN)) {
+		    llc_mac_match(llc->laddr.mac, laddr->mac) &&
+		    llc_mac_match(llc->daddr.mac, daddr->mac)) {
 			rc = llc->sk;
 			break;
 		}
@@ -433,6 +506,39 @@
 }
 
 /**
+ *	llc_lookup_listener - Finds listener for local MAC + SAP
+ *	@sap: SAP
+ *	@laddr: address of local LLC (MAC + SAP)
+ *
+ *	Search connection list of the SAP and finds connection listening on
+ *	local mac, and local sap. Returns pointer for parent socket found,
+ *	%NULL otherwise.
+ */
+struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
+{
+	struct sock *rc = NULL;
+	struct list_head *entry;
+
+	spin_lock_bh(&sap->sk_list.lock);
+	if (list_empty(&sap->sk_list.list))
+		goto out;
+	list_for_each(entry, &sap->sk_list.list) {
+		struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
+
+		if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN ||
+		    llc->laddr.lsap != laddr->lsap ||
+		    !llc_mac_match(llc->laddr.mac, laddr->mac))
+			continue;
+		rc = llc->sk;
+	}
+	if (rc)
+		sock_hold(rc);
+out:
+	spin_unlock_bh(&sap->sk_list.lock);
+	return rc;
+}
+
+/**
  *	llc_data_accept_state - designates if in this state data can be sent.
  *	@state: state of connection.
  *
@@ -440,10 +546,8 @@
  */
 u8 llc_data_accept_state(u8 state)
 {
-	if (state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
-	    state != LLC_CONN_STATE_REJ)
-		return 1; /* data_conn_refuse */
-	return 0;
+	return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
+	       state != LLC_CONN_STATE_REJ;
 }
 
 /**
diff -Nru a/net/llc/llc_if.c b/net/llc/llc_if.c
--- a/net/llc/llc_if.c	Sun Sep 15 19:19:46 2002
+++ b/net/llc/llc_if.c	Sun Sep 15 19:19:46 2002
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/tcp.h>
 #include <asm/errno.h>
 #include <net/llc_if.h>
 #include <net/llc_sap.h>
@@ -27,42 +28,6 @@
 #include <net/llc_main.h>
 #include <net/llc_mac.h>
 
-static int llc_sap_req(struct llc_prim_if_block *prim);
-static int llc_unitdata_req_handler(struct llc_prim_if_block *prim);
-static int llc_test_req_handler(struct llc_prim_if_block *prim);
-static int llc_xid_req_handler(struct llc_prim_if_block *prim);
-static int llc_data_req_handler(struct llc_prim_if_block *prim);
-static int llc_conn_req_handler(struct llc_prim_if_block *prim);
-static int llc_disc_req_handler(struct llc_prim_if_block *prim);
-static int llc_rst_req_handler(struct llc_prim_if_block *prim);
-static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim);
-static int llc_sap_resp(struct llc_prim_if_block *prim);
-static int llc_conn_rsp_handler(struct llc_prim_if_block *prim);
-static int llc_rst_rsp_handler(struct llc_prim_if_block *prim);
-static int llc_no_rsp_handler(struct llc_prim_if_block *prim);
-
-/* table of request handler functions */
-static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = {
-	[LLC_DATAUNIT_PRIM]	= llc_unitdata_req_handler,
-	[LLC_CONN_PRIM]		= llc_conn_req_handler,
-	[LLC_DATA_PRIM]		= llc_data_req_handler,
-	[LLC_DISC_PRIM]		= llc_disc_req_handler,
-	[LLC_RESET_PRIM]	= llc_rst_req_handler,
-	[LLC_FLOWCONTROL_PRIM]	= llc_flowcontrol_req_handler,
-	[LLC_XID_PRIM]		= llc_xid_req_handler,
-	[LLC_TEST_PRIM]		= llc_test_req_handler,
-};
-
-/* table of response handler functions */
-static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = {
-	[LLC_DATAUNIT_PRIM]	= llc_no_rsp_handler,
-	[LLC_CONN_PRIM]		= llc_conn_rsp_handler,
-	[LLC_DATA_PRIM]		= llc_no_rsp_handler,
-	[LLC_DISC_PRIM]		= llc_no_rsp_handler,
-	[LLC_RESET_PRIM]	= llc_rst_rsp_handler,
-	[LLC_FLOWCONTROL_PRIM]	= llc_no_rsp_handler,
-};
-
 /**
  *	llc_sap_open - open interface to the upper layers.
  *	@nw_indicate: pointer to indicate function of upper layer.
@@ -70,7 +35,7 @@
  *	@lsap: SAP number.
  *	@sap: pointer to allocated SAP (output argument).
  *
- *	Interface function to upper layer. each one who wants to get a SAP
+ *	Interface function to upper layer. Each one who wants to get a SAP
  *	(for example NetBEUI) should call this function. Returns the opened
  *	SAP for success, NULL for failure.
  */
@@ -92,8 +57,6 @@
 		goto err;
 	/* allocated a SAP; initialize it and clear out its memory pool */
 	sap->laddr.lsap = lsap;
-	sap->req = llc_sap_req;
-	sap->resp = llc_sap_resp;
 	sap->ind = nw_indicate;
 	sap->conf = nw_confirm;
 	sap->parent_station = llc_station_get();
@@ -110,7 +73,7 @@
  *	llc_sap_close - close interface for upper layers.
  *	@sap: SAP to be closed.
  *
- *	Close interface function to upper layer. each one who wants to
+ *	Close interface function to upper layer. Each one who wants to
  *	close an open SAP (for example NetBEUI) should call this function.
  */
 void llc_sap_close(struct llc_sap *sap)
@@ -120,142 +83,130 @@
 }
 
 /**
- *	llc_sap_req - Request interface for upper layers
- *	@prim: pointer to structure that contains service parameters.
- *
- *	Request interface function to upper layer. each one who wants to
- *	request a service from LLC, must call this function. details of
- *	requested service is defined in input argument(prim).  Returns 0 for
- *	success, 1 otherwise.
- */
-static int llc_sap_req(struct llc_prim_if_block *prim)
-{
-	int rc = 1;
-
-	if (prim->prim > 8 || prim->prim == 6) {
-		printk(KERN_ERR "%s: invalid primitive %d\n", __FUNCTION__,
-			prim->prim);
-		goto out;
-	}
-	/* receive REQUEST primitive from network layer; call the appropriate
-	 * primitive handler which then packages it up as an event and sends it
-	 * to the SAP or CONNECTION event handler
-	 */
-	if (prim->prim < LLC_NBR_PRIMITIVES)
-	       /* valid primitive; call the function to handle it */
-		rc = llc_req_prim[prim->prim](prim);
-out:
-	return rc;
-}
-
-/**
- *	llc_unitdata_req_handler - unitdata request interface for upper layers
- *	@prim: pointer to structure that contains service parameters
+ *	llc_build_and_send_ui_pkt - unitdata request interface for upper layers
+ *	@sap: sap to use
+ *	@skb: packet to send
+ *	@dmac: destination mac address
+ *	@dsap: destination sap
  *
  *	Upper layers calls this function when upper layer wants to send data
- *	using connection-less mode communication (UI pdu). Returns 0 for
- *	success, 1 otherwise.
- */
-static int llc_unitdata_req_handler(struct llc_prim_if_block *prim)
-{
-	int rc = 1;
-	struct llc_sap_state_ev *ev;
-	/* accept data frame from network layer to be sent using connection-
-	 * less mode communication; timeout/retries handled by network layer;
-	 * package primitive as an event and send to SAP event handler
-	 */
-	struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
+ *	using connection-less mode communication (UI pdu).
+ *
+ *	Accept data frame from network layer to be sent using connection-
+ *	less mode communication; timeout/retries handled by network layer;
+ *	package primitive as an event and send to SAP event handler
+ */
+void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
+			       u8 *dmac, u8 dsap)
+{
+	union llc_u_prim_data prim_data;
+	struct llc_prim_if_block prim;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
+	prim.data = &prim_data;
+	prim.sap  = sap;
+	prim.prim = LLC_DATAUNIT_PRIM;
+
+	prim_data.udata.skb        = skb;
+	prim_data.udata.saddr.lsap = sap->laddr.lsap;
+	prim_data.udata.daddr.lsap = dsap;
+	memcpy(prim_data.udata.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
+	memcpy(prim_data.udata.daddr.mac, dmac, IFHWADDRLEN);
 
-	if (!sap)
-		goto out;
-	ev = llc_sap_ev(prim->data->udata.skb);
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_DATAUNIT_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-	ev->data.prim.data = prim;
-	rc = 0;
-	llc_sap_send_ev(sap, prim->data->udata.skb);
-out:
-	return rc;
+	ev->data.prim.data = &prim;
+	llc_sap_state_process(sap, skb);
 }
 
 /**
- *	llc_test_req_handler - TEST interface for upper layers.
- *	@prim: pointer to structure that contains service parameters.
+ *	llc_build_and_send_test_pkt - TEST interface for upper layers.
+ *	@sap: sap to use
+ *	@skb: packet to send
+ *	@dmac: destination mac address
+ *	@dsap: destination sap
  *
  *	This function is called when upper layer wants to send a TEST pdu.
  *	Returns 0 for success, 1 otherwise.
  */
-static int llc_test_req_handler(struct llc_prim_if_block *prim)
+void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb,
+				 u8 *dmac, u8 dsap)
 {
-	int rc = 1;
-	struct llc_sap_state_ev *ev;
-	/* package primitive as an event and send to SAP event handler */
-	struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
-	if (!sap)
-		goto out;
-	ev = llc_sap_ev(prim->data->udata.skb);
+	union llc_u_prim_data prim_data;
+	struct llc_prim_if_block prim;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
+	prim.data = &prim_data;
+	prim.sap  = sap;
+	prim.prim = LLC_TEST_PRIM;
+
+	prim_data.test.skb        = skb;
+	prim_data.test.saddr.lsap = sap->laddr.lsap;
+	prim_data.test.daddr.lsap = dsap;
+	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
+	memcpy(prim_data.test.daddr.mac, dmac, IFHWADDRLEN);
+	
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_TEST_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-	ev->data.prim.data = prim;
-	rc = 0;
-	llc_sap_send_ev(sap, prim->data->udata.skb);
-out:
-	return rc;
+	ev->data.prim.data = &prim;
+	llc_sap_state_process(sap, skb);
 }
 
 /**
- *	llc_xid_req_handler - XID interface for upper layers
- *	@prim: pointer to structure that contains service parameters.
+ *	llc_build_and_send_xid_pkt - XID interface for upper layers
+ *	@sap: sap to use
+ *	@skb: packet to send
+ *	@dmac: destination mac address
+ *	@dsap: destination sap
  *
  *	This function is called when upper layer wants to send a XID pdu.
  *	Returns 0 for success, 1 otherwise.
  */
-static int llc_xid_req_handler(struct llc_prim_if_block *prim)
+void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
+				u8 *dmac, u8 dsap)
 {
-	int rc = 1;
-	struct llc_sap_state_ev *ev;
-	/* package primitive as an event and send to SAP event handler */
-	struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
+	union llc_u_prim_data prim_data;
+	struct llc_prim_if_block prim;
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
+	prim.data = &prim_data;
+	prim.sap  = sap;
+	prim.prim = LLC_XID_PRIM;
+
+	prim_data.xid.skb        = skb;
+	prim_data.xid.saddr.lsap = sap->laddr.lsap;
+	prim_data.xid.daddr.lsap = dsap;
+	memcpy(prim_data.xid.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
+	memcpy(prim_data.xid.daddr.mac, dmac, IFHWADDRLEN);
 
-	if (!sap)
-		goto out;
-	ev = llc_sap_ev(prim->data->udata.skb);
 	ev->type	   = LLC_SAP_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_XID_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-	ev->data.prim.data = prim;
-	rc = 0;
-	llc_sap_send_ev(sap, prim->data->udata.skb);
-out:
-	return rc;
+	ev->data.prim.data = &prim;
+	llc_sap_state_process(sap, skb);
 }
 
 /**
- *	llc_data_req_handler - Connection data sending for upper layers.
- *	@prim: pointer to structure that contains service parameters
+ *	llc_build_and_send_pkt - Connection data sending for upper layers.
+ *	@sk: connection
+ *	@skb: packet to send
  *
  *	This function is called when upper layer wants to send data using
- *	connection oriented communication mode. during sending data, connection
+ *	connection oriented communication mode. During sending data, connection
  *	will be locked and received frames and expired timers will be queued.
  *	Returns 0 for success, -ECONNABORTED when the connection already
- *	closed. and -EBUSY when sending data is not permitted in this state or
+ *	closed and -EBUSY when sending data is not permitted in this state or
  *	LLC has send an I pdu with p bit set to 1 and is waiting for it's
  *	response.
  */
-static int llc_data_req_handler(struct llc_prim_if_block *prim)
+int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
 {
 	struct llc_conn_state_ev *ev;
 	int rc = -ECONNABORTED;
-	/* accept data frame from network layer to be sent using connection
-	 * mode communication; timeout/retries handled by this layer;
-	 * package primitive as an event and send to connection event handler
-	 */
-	struct sock *sk = prim->data->data.sk;
 	struct llc_opt *llc = llc_sk(sk);
 
-	lock_sock(sk);
 	if (llc->state == LLC_CONN_STATE_ADM)
 		goto out;
 	rc = -EBUSY;
@@ -267,169 +218,121 @@
 		llc->failed_data_req = 1;
 		goto out;
 	}
-	ev = llc_conn_ev(prim->data->data.skb);
-	ev->type		  = LLC_CONN_EV_TYPE_PRIM;
-	ev->data.prim.prim	  = LLC_DATA_PRIM;
-	ev->data.prim.type	  = LLC_PRIM_TYPE_REQ;
-	ev->data.prim.data	  = prim;
-	prim->data->data.skb->dev = llc->dev;
-	rc = llc_conn_send_ev(sk, prim->data->data.skb);
+	ev = llc_conn_ev(skb);
+	ev->type	    = LLC_CONN_EV_TYPE_PRIM;
+	ev->data.prim.prim  = LLC_DATA_PRIM;
+	ev->data.prim.type  = LLC_PRIM_TYPE_REQ;
+	ev->data.prim.data  = NULL;
+	skb->dev	    = llc->dev;
+	rc = llc_conn_state_process(sk, skb);
 out:
-	release_sock(sk);
 	return rc;
 }
 
 /**
- *	llc_confirm_impossible - Informs upper layer about failed connection
- *	@prim: pointer to structure that contains confirmation data.
- *
- *	Informs upper layer about failing in connection establishment. This
- *	function is called by llc_conn_req_handler.
- */
-static void llc_confirm_impossible(struct llc_prim_if_block *prim)
-{
-	prim->data->conn.status = LLC_STATUS_IMPOSSIBLE;
-	prim->sap->conf(prim);
-}
-
-/**
- *	llc_conn_req_handler - Called by upper layer to establish a conn
- *	@prim: pointer to structure that contains service parameters.
+ *	llc_establish_connection - Called by upper layer to establish a conn
+ *	@sk: connection
+ *	@lmac: local mac address
+ *	@dmac: destination mac address
+ *	@dsap: destination sap
  *
  *	Upper layer calls this to establish an LLC connection with a remote
- *	machine. this function packages a proper event and sends it connection
- *	component state machine.  Success or failure of connection
+ *	machine. This function packages a proper event and sends it connection
+ *	component state machine. Success or failure of connection
  *	establishment will inform to upper layer via calling it's confirm
  *	function and passing proper information.
  */
-static int llc_conn_req_handler(struct llc_prim_if_block *prim)
+int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
 {
-	int rc = -EBUSY;
-	struct llc_opt *llc;
-	struct llc_sap *sap = prim->sap;
-	struct sk_buff *skb;
-	struct net_device *ddev = mac_dev_peer(prim->data->conn.dev,
-					       prim->data->conn.dev->type,
-					       prim->data->conn.daddr.mac),
-			  *sdev = (ddev->flags & IFF_LOOPBACK) ?
-				  ddev : prim->data->conn.dev;
+	int rc = -EISCONN;
 	struct llc_addr laddr, daddr;
-	/* network layer supplies addressing required to establish connection;
-	 * package as an event and send it to the connection event handler
-	 */
-	struct sock *sk;
+	struct sk_buff *skb;
+	struct llc_opt *llc = llc_sk(sk);
+	struct sock *existing;
 
-	memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac));
-	laddr.lsap = prim->data->conn.saddr.lsap;
-	memcpy(daddr.mac, prim->data->conn.daddr.mac, sizeof(daddr.mac));
-	daddr.lsap = prim->data->conn.daddr.lsap;
-	sk = llc_find_sock(sap, &daddr, &laddr);
-	if (sk) {
-		llc_confirm_impossible(prim);
-		goto out_put;
-	}
-	rc = -ENOMEM; 
-	if (prim->data->conn.sk) {
-		sk = prim->data->conn.sk;
-		if (llc_sock_init(sk))
-			goto out;
-	} else {
-		sk = llc_sock_alloc();
-		if (!sk) {
-			llc_confirm_impossible(prim);
-			goto out;
-		}
-		prim->data->conn.sk = sk;
+	laddr.lsap = llc->sap->laddr.lsap;
+	daddr.lsap = dsap;
+	memcpy(daddr.mac, dmac, sizeof(daddr.mac));
+	memcpy(laddr.mac, lmac, sizeof(laddr.mac));
+	existing = llc_lookup_established(llc->sap, &daddr, &laddr);
+	if (existing) {
+		if (existing->state == TCP_ESTABLISHED) {
+			sk = existing;
+			goto out_put;
+		} else
+			sock_put(existing);
 	}
 	sock_hold(sk);
-	lock_sock(sk);
-	/* assign new connection to it's SAP */
-	llc_sap_assign_sock(sap, sk);
-	llc = llc_sk(sk);
-	memcpy(&llc->daddr, &daddr, sizeof(llc->daddr));
-	memcpy(&llc->laddr, &laddr, sizeof(llc->laddr));
-	llc->dev     = ddev;
-	llc->link    = prim->data->conn.link;
-	llc->handler = prim->data->conn.handler;
-	skb = alloc_skb(1, GFP_ATOMIC);
+	rc = -ENOMEM;
+	skb = alloc_skb(0, GFP_ATOMIC);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
 		ev->type	   = LLC_CONN_EV_TYPE_PRIM;
 		ev->data.prim.prim = LLC_CONN_PRIM;
 		ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, skb);
-	}
-	if (rc) {
-		llc_sap_unassign_sock(sap, sk);
-		llc_sock_free(sk);
-		llc_confirm_impossible(prim);
+		ev->data.prim.data = NULL;
+		rc = llc_conn_state_process(sk, skb);
 	}
-	release_sock(sk);
 out_put:
 	sock_put(sk);
-out:
 	return rc;
 }
 
 /**
- *	llc_disc_req_handler - Called by upper layer to close a connection
- *	@prim: pointer to structure that contains service parameters.
+ *	llc_send_disc - Called by upper layer to close a connection
+ *	@sk: connection to be closed
  *
  *	Upper layer calls this when it wants to close an established LLC
- *	connection with a remote machine. this function packages a proper event
+ *	connection with a remote machine. This function packages a proper event
  *	and sends it to connection component state machine. Returns 0 for
  *	success, 1 otherwise.
  */
-static int llc_disc_req_handler(struct llc_prim_if_block *prim)
+int llc_send_disc(struct sock *sk)
 {
 	u16 rc = 1;
 	struct llc_conn_state_ev *ev;
 	struct sk_buff *skb;
-	struct sock* sk = prim->data->disc.sk;
 
 	sock_hold(sk);
-	lock_sock(sk);
-	if (llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
+	if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED ||
+	    llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
 	    llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
 		goto out;
 	/*
 	 * Postpone unassigning the connection from its SAP and returning the
 	 * connection until all ACTIONs have been completely executed
 	 */
-	skb = alloc_skb(1, GFP_ATOMIC);
+	skb = alloc_skb(0, GFP_ATOMIC);
 	if (!skb)
 		goto out;
-	ev = llc_conn_ev(skb);
+	sk->state	   = TCP_CLOSING;
+	ev		   = llc_conn_ev(skb);
 	ev->type	   = LLC_CONN_EV_TYPE_PRIM;
 	ev->data.prim.prim = LLC_DISC_PRIM;
 	ev->data.prim.type = LLC_PRIM_TYPE_REQ;
-	ev->data.prim.data = prim;
-	rc = llc_conn_send_ev(sk, skb);
+	ev->data.prim.data = NULL;
+	rc = llc_conn_state_process(sk, skb);
 out:
-	release_sock(sk);
 	sock_put(sk);
 	return rc;
 }
 
 /**
- *	llc_rst_req_handler - Resets an established LLC connection
+ *	llc_build_and_send_reset_pkt - Resets an established LLC connection
  *	@prim: pointer to structure that contains service parameters.
  *
  *	Called when upper layer wants to reset an established LLC connection
- *	with a remote machine. this function packages a proper event and sends
+ *	with a remote machine. This function packages a proper event and sends
  *	it to connection component state machine. Returns 0 for success, 1
  *	otherwise.
  */
-static int llc_rst_req_handler(struct llc_prim_if_block *prim)
+int llc_build_and_send_reset_pkt(struct sock *sk,
+				 struct llc_prim_if_block *prim)
 {
-	struct sk_buff *skb;
 	int rc = 1;
-	struct sock *sk = prim->data->res.sk;
+	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
 
-	lock_sock(sk);
-	skb = alloc_skb(1, GFP_ATOMIC);
 	if (skb) {
 		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
 
@@ -437,87 +340,11 @@
 		ev->data.prim.prim = LLC_RESET_PRIM;
 		ev->data.prim.type = LLC_PRIM_TYPE_REQ;
 		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, skb);
-	}
-	release_sock(sk);
-	return rc;
-}
-
-/* We don't support flow control. The original code from procom has
- * some bits, but for now I'm cleaning this
- */
-static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim)
-{
-	return 1;
-}
-
-/**
- *	llc_sap_resp - Sends response to peer
- *	@prim: pointer to structure that contains service parameters
- *
- *	This function is a interface function to upper layer. each one who
- *	wants to response to an indicate can call this function via calling
- *	sap_resp with proper service parameters. Returns 0 for success, 1
- *	otherwise.
- */
-static int llc_sap_resp(struct llc_prim_if_block *prim)
-{
-	u16 rc = 1;
-	/* network layer RESPONSE primitive received; package primitive
-	 * as an event and send it to the connection event handler
-	 */
-	if (prim->prim < LLC_NBR_PRIMITIVES)
-	       /* valid primitive; call the function to handle it */
-		rc = llc_resp_prim[prim->prim](prim);
-	return rc;
-}
-
-/**
- *	llc_conn_rsp_handler - Response to connect indication
- *	@prim: pointer to structure that contains response info.
- *
- *	Response to connect indication.
- */
-static int llc_conn_rsp_handler(struct llc_prim_if_block *prim)
-{
-	struct sock *sk = prim->data->conn.sk;
-
-	llc_sk(sk)->link = prim->data->conn.link;
-	return 0;
-}
-
-/**
- *	llc_rst_rsp_handler - Response to RESET indication
- *	@prim: pointer to structure that contains response info
- *
- *	Returns 0 for success, 1 otherwise
- */
-static int llc_rst_rsp_handler(struct llc_prim_if_block *prim)
-{
-	int rc = 1;
-	/*
-	 * Network layer supplies connection handle; map it to a connection;
-	 * package as event and send it to connection event handler
-	 */
-	struct sock *sk = prim->data->res.sk;
-	struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
-
-	if (skb) {
-		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-
-		ev->type	   = LLC_CONN_EV_TYPE_PRIM;
-		ev->data.prim.prim = LLC_RESET_PRIM;
-		ev->data.prim.type = LLC_PRIM_TYPE_RESP;
-		ev->data.prim.data = prim;
-		rc = llc_conn_send_ev(sk, skb);
+		rc = llc_conn_state_process(sk, skb);
 	}
 	return rc;
 }
 
-static int llc_no_rsp_handler(struct llc_prim_if_block *prim)
-{
-	return 0;
-}
-
 EXPORT_SYMBOL(llc_sap_open);
 EXPORT_SYMBOL(llc_sap_close);
+EXPORT_SYMBOL(llc_build_and_send_ui_pkt);
diff -Nru a/net/llc/llc_mac.c b/net/llc/llc_mac.c
--- a/net/llc/llc_mac.c	Sun Sep 15 19:20:20 2002
+++ b/net/llc/llc_mac.c	Sun Sep 15 19:20:20 2002
@@ -27,14 +27,17 @@
 #include <net/llc_s_ev.h>
 #include <linux/trdevice.h>
 
-#if 1
+#if 0
 #define dprintk(args...) printk(KERN_DEBUG args)
 #else
 #define dprintk(args...)
 #endif
 
-/* function prototypes */
+u8 llc_mac_null_var[IFHWADDRLEN];
+
 static void fix_up_incoming_skb(struct sk_buff *skb);
+static void llc_station_rcv(struct sk_buff *skb);
+static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb);
 
 /**
  *	mac_send_pdu - Sends PDU to specific device.
@@ -52,7 +55,7 @@
 	int pri = GFP_ATOMIC, rc = -1;
 
 	if (!skb->dev) {
-		dprintk(KERN_ERR "%s: skb->dev == NULL!", __FUNCTION__);
+		dprintk("%s: skb->dev == NULL!", __FUNCTION__);
 		goto out;
 	}
 	if (skb->sk)
@@ -67,29 +70,30 @@
 }
 
 /**
- *	mac_indicate - 802.2 entry point from net lower layers
+ *	llc_rcv - 802.2 entry point from net lower layers
  *	@skb: received pdu
  *	@dev: device that receive pdu
  *	@pt: packet type
  *
  *	When the system receives a 802.2 frame this function is called. It
  *	checks SAP and connection of received pdu and passes frame to
- *	llc_pdu_router for sending to proper state machine. If frame is
- *	related to a busy connection (a connection is sending data now),
- *	function queues this frame in connection's backlog.
+ *	llc_{station,sap,conn}_rcv for sending to proper state machine. If
+ *	the frame is related to a busy connection (a connection is sending
+ *	data now), it queues this frame in the connection's backlog.
  */
-int mac_indicate(struct sk_buff *skb, struct net_device *dev,
+int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 		 struct packet_type *pt)
 {
 	struct llc_sap *sap;
 	struct llc_pdu_sn *pdu;
 	u8 dest;
 
-	/* When the interface is in promisc. mode, drop all the crap that it
+	/*
+	 * When the interface is in promisc. mode, drop all the crap that it
 	 * receives, do not try to analyse it.
 	 */
 	if (skb->pkt_type == PACKET_OTHERHOST) {
-		dprintk(KERN_INFO "%s: PACKET_OTHERHOST\n", __FUNCTION__);
+		dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__);
 		goto drop;
 	}
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -98,17 +102,19 @@
 	fix_up_incoming_skb(skb);
 	pdu = llc_pdu_sn_hdr(skb);
 	if (!pdu->dsap) { /* NULL DSAP, refer to station */
-		if (llc_pdu_router(NULL, NULL, skb, 0))
-			goto drop;
+		dprintk("%s: calling llc_station_rcv!\n", __FUNCTION__);
+		llc_station_rcv(skb);
 		goto out;
 	}
 	sap = llc_sap_find(pdu->dsap);
-	if (!sap) /* unknown SAP */
+	if (!sap) {/* unknown SAP */
+		dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, pdu->dsap);
 		goto drop;
+	}
 	llc_decode_pdu_type(skb, &dest);
 	if (dest == LLC_DEST_SAP) { /* type 1 services */
-		if (llc_pdu_router(sap, NULL, skb, LLC_TYPE_1))
-			goto drop;
+		dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__);
+		llc_sap_rcv(sap, skb);
 	} else if (dest == LLC_DEST_CONN) {
 		struct llc_addr saddr, daddr;
 		struct sock *sk;
@@ -119,34 +125,42 @@
 		llc_pdu_decode_da(skb, daddr.mac);
 		llc_pdu_decode_dsap(skb, &daddr.lsap);
 
-		sk = llc_find_sock(sap, &saddr, &daddr);
-		if (!sk) { /* didn't find an active connection; allocate a
-			    * connection to use; associate it with this SAP
-			    */
-			sk = llc_sock_alloc();
-			if (!sk)
+		sk = llc_lookup_established(sap, &saddr, &daddr);
+		if (!sk) {
+			/*
+			 * Didn't find an active connection; verify if there
+			 * is a listening socket for this llc addr
+			 */
+			struct llc_opt *llc;
+			struct sock *parent;
+			
+			parent = llc_lookup_listener(sap, &daddr);
+
+			if (!parent) {
+				dprintk("llc_lookup_listener failed!\n");
+				goto drop;
+			}
+
+			sk = llc_sk_alloc(parent->family, GFP_ATOMIC);
+			if (!sk) {
+				sock_put(parent);
 				goto drop;
-			memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr));
+			}
+			llc = llc_sk(sk);
+			memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
+			memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
 			llc_sap_assign_sock(sap, sk);
 			sock_hold(sk);
-		}
+			sock_put(parent);
+			skb->sk = parent;
+		} else
+			skb->sk = sk;
 		bh_lock_sock(sk);
 		if (!sk->lock.users) {
-			/* FIXME: Check this on SMP as it is now calling
-			 * llc_pdu_router _with_ the lock held.
-			 * Old comment:
-			 * With the current code one can't call
-			 * llc_pdu_router with the socket lock held, cause
-			 * it'll route the pdu to the upper layers and it can
-			 * reenter llc and in llc_req_prim will try to grab
-			 * the same lock, maybe we should use spin_trylock_bh
-			 * in the llc_req_prim (llc_data_req_handler, etc) and
-			 * add the request to the backlog, well see...
-			 */
-			rc = llc_pdu_router(llc_sk(sk)->sap, sk, skb,
-					    LLC_TYPE_2);
+			/* rc = */ llc_conn_rcv(sk, skb);
+			rc = 0;
 		} else {
-			dprintk(KERN_INFO "%s: add to backlog\n", __FUNCTION__);
+			dprintk("%s: adding to backlog...\n", __FUNCTION__);
 			llc_set_backlog_type(skb, LLC_PACKET);
 			sk_add_backlog(sk, skb);
 			rc = 0;
@@ -191,53 +205,56 @@
 	}
 }
 
+/*
+ *	llc_station_rcv - send received pdu to the station state machine
+ *	@skb: received frame.
+ *
+ *	Sends data unit to station state machine.
+ */
+static void llc_station_rcv(struct sk_buff *skb)
+{
+	struct llc_station *station = llc_station_get();
+	struct llc_station_state_ev *ev = llc_station_ev(skb);
+
+	ev->type            = LLC_STATION_EV_TYPE_PDU;
+	ev->data.pdu.reason = 0;
+	llc_station_state_process(station, skb);
+}
+
+
 /**
- *	llc_pdu_router - routes received pdus to the upper layers
- *	@sap: current sap component structure.
+ *	llc_conn_rcv - sends received pdus to the connection state machine
  *	@sk: current connection structure.
- *	@frame: received frame.
- *	@type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2
+ *	@skb: received frame.
  *
- *	Queues received PDUs from LLC_MAC PDU receive queue until queue is
- *	empty; examines LLC header to determine the destination of PDU, if DSAP
- *	is NULL then data unit destined for station else frame destined for SAP
- *	or connection; finds a matching open SAP, if one, forwards the packet
- *	to it; if no matching SAP, drops the packet. Returns 0 or the return of
- *	llc_conn_send_ev (that may well result in the connection being
- *	destroyed)
- */
-int llc_pdu_router(struct llc_sap *sap, struct sock* sk,
-		   struct sk_buff *skb, u8 type)
-{
-	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
-	int rc = 0;
-
-	if (!pdu->dsap) {
-		struct llc_station *station = llc_station_get();
-		struct llc_station_state_ev *ev = llc_station_ev(skb);
-
-		ev->type	    = LLC_STATION_EV_TYPE_PDU;
-		ev->data.pdu.reason = 0;
-		llc_station_send_ev(station, skb);
-	} else if (type == LLC_TYPE_1) {
-		struct llc_sap_state_ev *ev = llc_sap_ev(skb);
-
-		ev->type	    = LLC_SAP_EV_TYPE_PDU;
-		ev->data.pdu.reason = 0;
-		llc_sap_send_ev(sap, skb);
-	} else if (type == LLC_TYPE_2) {
-		struct llc_conn_state_ev *ev = llc_conn_ev(skb);
-		struct llc_opt *llc = llc_sk(sk);
-
-		if (!llc->dev)
-			llc->dev = skb->dev;
-
-		ev->type	    = LLC_CONN_EV_TYPE_PDU;
-		ev->data.pdu.reason = 0;
-		rc = llc_conn_send_ev(sk, skb);
-	} else
-		rc = -EINVAL;
-	return rc;
+ *	Sends received pdus to the connection state machine.
+ */
+int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
+{
+	struct llc_conn_state_ev *ev = llc_conn_ev(skb);
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (!llc->dev)
+		llc->dev = skb->dev;
+	ev->type	    = LLC_CONN_EV_TYPE_PDU;
+	ev->data.pdu.reason = 0;
+	return llc_conn_state_process(sk, skb);
+}
+
+/**
+ *	llc_sap_rcv - sends received pdus to the sap state machine
+ *	@sap: current sap component structure.
+ *	@skb: received frame.
+ *
+ *	Sends received pdus to the sap state machine.
+ */
+static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb)
+{
+	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
+
+	ev->type	    = LLC_SAP_EV_TYPE_PDU;
+	ev->data.pdu.reason = 0;
+	llc_sap_state_process(sap, skb);
 }
 
 /**
diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c
--- a/net/llc/llc_main.c	Sun Sep 15 19:19:34 2002
+++ b/net/llc/llc_main.c	Sun Sep 15 19:19:34 2002
@@ -52,6 +52,11 @@
 
 static struct llc_station llc_main_station;	/* only one of its kind */
 
+#undef LLC_REFCNT_DEBUG
+#ifdef LLC_REFCNT_DEBUG
+static atomic_t llc_sock_nr;
+#endif
+
 /**
  *	llc_sap_alloc - allocates and initializes sap.
  *
@@ -136,7 +141,7 @@
  *
  *	This function processes frames that has received and timers that has
  *	expired during sending an I pdu (refer to data_req_handler).  frames
- *	queue by mac_indicate function (llc_mac.c) and timers queue by timer
+ *	queue by llc_rcv function (llc_mac.c) and timers queue by timer
  *	callback functions(llc_c_ac.c).
  */
 static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
@@ -146,13 +151,13 @@
 
 	if (llc_backlog_type(skb) == LLC_PACKET) {
 		if (llc->state > 1) /* not closed */
-			rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2);
+			rc = llc_conn_rcv(sk, skb);
 		else
 			kfree_skb(skb);
 	} else if (llc_backlog_type(skb) == LLC_EVENT) {
 		/* timer expiration event */
 		if (llc->state > 1)  /* not closed */
-			rc = llc_conn_send_ev(sk, skb);
+			rc = llc_conn_state_process(sk, skb);
 		else
 			llc_conn_free_ev(skb);
 		kfree_skb(skb);
@@ -165,10 +170,12 @@
 }
 
 /**
- *     llc_sock_init - Initialize a socket with default llc values.
+ *     llc_sk_init - Initializes a socket with default llc values.
  *     @sk: socket to intiailize.
+ *
+ *     Initializes a socket with default llc values.
  */
-int llc_sock_init(struct sock* sk)
+int llc_sk_init(struct sock* sk)
 {
 	struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
 	int rc = -ENOMEM;
@@ -198,61 +205,83 @@
 }
 
 /**
- *	__llc_sock_alloc - Allocates LLC sock
+ *	llc_sk_alloc - Allocates LLC sock
+ *	@family: upper layer protocol family
+ *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
  *
  *	Allocates a LLC sock and initializes it. Returns the new LLC sock
  *	or %NULL if there's no memory available for one
  */
-struct sock *__llc_sock_alloc(void)
+struct sock *llc_sk_alloc(int family, int priority)
 {
-	struct sock *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1, NULL);
+	struct sock *sk = sk_alloc(family, priority, 1, NULL);
 
+	MOD_INC_USE_COUNT;
 	if (!sk)
-		goto out;
-	if (llc_sock_init(sk))
+		goto decmod;
+	if (llc_sk_init(sk))
 		goto outsk;
 	sock_init_data(NULL, sk);
+#ifdef LLC_REFCNT_DEBUG
+	atomic_inc(&llc_sock_nr);
+	printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
+		__FUNCTION__, atomic_read(&llc_sock_nr));
+#endif
 out:
 	return sk;
 outsk:
 	sk_free(sk);
 	sk = NULL;
+decmod:
+	MOD_DEC_USE_COUNT;
 	goto out;
 }
 
 /**
- *	__llc_sock_free - Frees a LLC socket
+ *	llc_sk_free - Frees a LLC socket
  *	@sk - socket to free
  *
  *	Frees a LLC socket
  */
-void __llc_sock_free(struct sock *sk, u8 free)
+void llc_sk_free(struct sock *sk)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
 	llc->state = LLC_CONN_OUT_OF_SVC;
-	/* stop all (possibly) running timers */
+	/* Stop all (possibly) running timers */
 	llc_conn_ac_stop_all_timers(sk, NULL);
-	/* handle return of frames on lists */
-#if 0
+#ifdef DEBUG_LLC_CONN_ALLOC
 	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
 		skb_queue_len(&llc->pdu_unack_q),
 		skb_queue_len(&sk->write_queue));
 #endif
+	skb_queue_purge(&sk->receive_queue);
 	skb_queue_purge(&sk->write_queue);
 	skb_queue_purge(&llc->pdu_unack_q);
-	if (free)
-		sock_put(sk);
+#ifdef LLC_REFCNT_DEBUG
+	if (atomic_read(&sk->refcnt) != 1) {
+		printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
+			sk, __FUNCTION__, atomic_read(&sk->refcnt));
+		printk(KERN_DEBUG "%d LLC sockets are still alive\n",
+			atomic_read(&llc_sock_nr));
+	} else {
+		atomic_dec(&llc_sock_nr);
+		printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
+			__FUNCTION__, atomic_read(&llc_sock_nr));
+	}
+#endif
+	sock_put(sk);
+	MOD_DEC_USE_COUNT;
 }
 
 /**
- *	llc_sock_reset - resets a connection
+ *	llc_sk_reset - resets a connection
  *	@sk: LLC socket to reset
  *
  *	Resets a connection to the out of service state. Stops its timers
  *	and frees any frames in the queues of the connection.
  */
-void llc_sock_reset(struct sock *sk)
+void llc_sk_reset(struct sock *sk)
 {
 	struct llc_opt *llc = llc_sk(sk);
 
@@ -286,8 +315,6 @@
 static int llc_rtn_all_conns(struct llc_sap *sap)
 {
 	int rc = 0;
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
 	struct list_head *entry, *tmp;
 
 	spin_lock_bh(&sap->sk_list.lock);
@@ -296,12 +323,8 @@
 	list_for_each_safe(entry, tmp, &sap->sk_list.list) {
 		struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
 
-		prim.sap = sap;
-		prim_data.disc.sk = llc->sk;
-		prim.prim = LLC_DISC_PRIM;
-		prim.data = &prim_data;
 		llc->state = LLC_CONN_STATE_TEMP;
-		if (sap->req(&prim))
+		if (llc_send_disc(llc->sk))
 			rc = 1;
 	}
 out:
@@ -320,14 +343,14 @@
 }
 
 /**
- *	llc_station_send_ev: queue event and try to process queue.
+ *	llc_station_state_process: queue event and try to process queue.
  *	@station: Address of the station
  *	@skb: Address of the event
  *
  *	Queues an event (on the station event queue) for handling by the
  *	station state machine and attempts to process any queued-up events.
  */
-void llc_station_send_ev(struct llc_station *station, struct sk_buff *skb)
+void llc_station_state_process(struct llc_station *station, struct sk_buff *skb)
 {
 	spin_lock_bh(&station->ev_q.lock);
 	skb_queue_tail(&station->ev_q.list, skb);
@@ -557,13 +580,13 @@
 
 static struct packet_type llc_packet_type = {
 	.type = __constant_htons(ETH_P_802_2),
-	.func = mac_indicate,
+	.func = llc_rcv,
 	.data = (void *)1,
 };
 
 static struct packet_type llc_tr_packet_type = {
 	.type = __constant_htons(ETH_P_TR_802_2),
-	.func = mac_indicate,
+	.func = llc_rcv,
 	.data = (void *)1,
 };
 
@@ -585,7 +608,7 @@
 	skb_queue_head_init(&llc_main_station.mac_pdu_q);
 	skb_queue_head_init(&llc_main_station.ev_q.list);
 	spin_lock_init(&llc_main_station.ev_q.lock);
-	skb = alloc_skb(1, GFP_ATOMIC);
+	skb = alloc_skb(0, GFP_ATOMIC);
 	if (!skb)
 		goto err;
 	llc_build_offset_table();
diff -Nru a/net/llc/llc_pdu.c b/net/llc/llc_pdu.c
--- a/net/llc/llc_pdu.c	Sun Sep 15 19:19:29 2002
+++ b/net/llc/llc_pdu.c	Sun Sep 15 19:19:29 2002
@@ -18,7 +18,7 @@
 #include <net/llc_mac.h>
 #include <net/llc_main.h>
 
-static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
+static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
 static __inline__ int llc_get_hdr_len(u8 pdu_type);
 static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu);
 
@@ -60,9 +60,7 @@
 	u8 pdu_type;
 	struct llc_pdu_sn *pdu;
 
-	if (llc_pdu_decode_pdu_type(skb, &pdu_type))
-		goto out;
-
+	llc_pdu_decode_pdu_type(skb, &pdu_type);
 	pdu = llc_pdu_sn_hdr(skb);
 	
 	switch (pdu_type) {
@@ -74,7 +72,6 @@
 			pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4);
 			break;
 	}
-out:;
 }
 
 /**
@@ -86,15 +83,12 @@
  *	PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In
  *	U pdus p/f bit is fifth bit of third byte.
  */
-int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
+void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
 {
 	u8 pdu_type;
 	struct llc_pdu_sn *pdu;
-	int rc = llc_pdu_decode_pdu_type(skb, &pdu_type);
-
-	if (rc)
-		goto out;
 
+	llc_pdu_decode_pdu_type(skb, &pdu_type);
 	pdu = llc_pdu_sn_hdr(skb);
 
 	switch (pdu_type) {
@@ -106,22 +100,19 @@
 			*pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
 			break;
 	}
-out:
-	return 0;
 }
 
 /**
- *	llc_pdu_decode_cr_bit - extracs command response bit from LLC header
+ *	llc_pdu_decode_cr_bit - extracts command response bit from LLC header
  *	@skb: input skb that c/r bit must be extracted from it.
  *	@cr_bit: command/response bit (0 or 1).
  *
  *	This function extracts command/response bit from LLC header. this bit
  *	is right bit of source SAP.
  */
-int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit)
+void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit)
 {
 	*cr_bit = llc_pdu_un_hdr(skb)->ssap & LLC_PDU_CMD_RSP_MASK;
-	return 0;
 }
 
 /**
@@ -131,13 +122,12 @@
  *
  *	This function extracts source address(MAC) of input frame.
  */
-int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)
+void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)
 {
 	if (skb->protocol == ntohs(ETH_P_802_2))
 		memcpy(sa, ((struct ethhdr *)skb->mac.raw)->h_source, ETH_ALEN);
 	else if (skb->protocol == ntohs(ETH_P_TR_802_2))
 		memcpy(sa, ((struct trh_hdr *)skb->mac.raw)->saddr, ETH_ALEN);
-	return 0;
 }
 
 /**
@@ -147,13 +137,12 @@
  *
  *	This function extracts destination address(MAC) of input frame.
  */
-int llc_pdu_decode_da(struct sk_buff *skb, u8 *da)
+void llc_pdu_decode_da(struct sk_buff *skb, u8 *da)
 {
 	if (skb->protocol == ntohs(ETH_P_802_2))
 		memcpy(da, ((struct ethhdr *)skb->mac.raw)->h_dest, ETH_ALEN);
 	else if (skb->protocol == ntohs(ETH_P_TR_802_2))
 		memcpy(da, ((struct trh_hdr *)skb->mac.raw)->daddr, ETH_ALEN);
-	return 0;
 }
 
 /**
@@ -164,10 +153,9 @@
  *	This function extracts destination SAP of input frame. right bit of
  *	DSAP designates individual/group SAP.
  */
-int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap)
+void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap)
 {
 	*dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE;
-	return 0;
 }
 
 /**
@@ -175,13 +163,12 @@
  *	@skb: input skb that source SAP must be extracted from it.
  *	@ssap: source SAP (output argument).
  *
- *	This function extracts source SAP of input frame. right bit of SSAP is
+ *	This function extracts source SAP of input frame. Right bit of SSAP is
  *	command/response bit.
  */
-int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
+void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
 {
 	*ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE;
-	return 0;
 }
 
 /**
@@ -190,13 +177,12 @@
  *
  *	This function sets third byte of LLC header as a UI PDU.
  */
-int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
+void llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_1_PDU_CMD_UI;
-	return 0;
 }
 
 /**
@@ -206,8 +192,8 @@
  *	This function sets third,fourth,fifth and sixth bytes of LLC header as
  *	a XID PDU.
  */
-int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
-			    u8 rx_window)
+void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
+			     u8 rx_window)
 {
 	struct llc_xid_info *xid_info;
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
@@ -220,7 +206,6 @@
 	xid_info->type	 = svcs_supported;
 	xid_info->rw	 = rx_window << 1;	/* size of recieve window */
 	skb_put(skb, 3);
-	return 0;
 }
 
 /**
@@ -229,14 +214,13 @@
  *
  * 	Sets a PDU as TEST
  */
-int llc_pdu_init_as_test_cmd(struct sk_buff *skb)
+void llc_pdu_init_as_test_cmd(struct sk_buff *skb)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST;
 	pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
-	return 0;
 }
 
 /**
@@ -246,18 +230,17 @@
  *
  *	Builds a pdu frame as a DISC command.
  */
-int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
+void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC;
 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
-	return 0;
 }
 
 /**
- *	pdu_init_as_i_cmd - builds I pdu
+ *	llc_pdu_init_as_i_cmd - builds I pdu
  *	@skb: Address of the skb to build
  *	@p_bit: The P bit to set in the PDU
  *	@ns: The sequence number of the data PDU
@@ -265,7 +248,7 @@
  *
  *	Builds a pdu frame as an I command.
  */
-int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
+void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -274,18 +257,17 @@
 	pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */
 	pdu->ctrl_1 |= (ns << 1) & 0xFE;   /* set N(S) in bits 2..8 */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE;   /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_rej_cmd - builds REJ PDU
+ *	llc_pdu_init_as_rej_cmd - builds REJ PDU
  *	@skb: Address of the skb to build
  *	@p_bit: The P bit to set in the PDU
  *	@nr: The seq. number of the expected I PDU from the remote
  *
  *	Builds a pdu frame as a REJ command.
  */
-int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
+void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -295,18 +277,17 @@
 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_rnr_cmd - builds RNR pdu
+ *	llc_pdu_init_as_rnr_cmd - builds RNR pdu
  *	@skb: Address of the skb to build
  *	@p_bit: The P bit to set in the PDU
  *	@nr: The seq. number of the expected I PDU from the remote
  *
  *	Builds a pdu frame as an RNR command.
  */
-int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
+void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -316,18 +297,17 @@
 	pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_rr_cmd - Builds RR pdu
+ *	llc_pdu_init_as_rr_cmd - Builds RR pdu
  *	@skb: Address of the skb to build
  *	@p_bit: The P bit to set in the PDU
  *	@nr: The seq. number of the expected I PDU from the remote
  *
  *	Builds a pdu frame as an RR command.
  */
-int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
+void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -336,53 +316,50 @@
 	pdu->ctrl_2  = p_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_sabme_cmd - builds SABME pdu
+ *	llc_pdu_init_as_sabme_cmd - builds SABME pdu
  *	@skb: Address of the skb to build
  *	@p_bit: The P bit to set in the PDU
  *
  *	Builds a pdu frame as an SABME command.
  */
-int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
+void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME;
 	pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
-	return 0;
 }
 
 /**
- *	pdu_init_as_dm_rsp - builds DM response pdu
+ *	llc_pdu_init_as_dm_rsp - builds DM response pdu
  *	@skb: Address of the skb to build
  *	@f_bit: The F bit to set in the PDU
  *
  *	Builds a pdu frame as a DM response.
  */
-int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
+void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_DM;
 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
-	return 0;
 }
 
 /**
- *	pdu_init_as_xid_rsp - builds XID response PDU
+ *	llc_pdu_init_as_xid_rsp - builds XID response PDU
  *	@skb: Address of the skb to build
  *	@svcs_supported: The class of the LLC (I or II)
  *	@rx_window: The size of the receive window of the LLC
  *
  *	Builds a pdu frame as an XID response.
  */
-int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
-			    u8 rx_window)
+void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
+			     u8 rx_window)
 {
 	struct llc_xid_info *xid_info;
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
@@ -396,17 +373,16 @@
 	xid_info->type	 = svcs_supported;
 	xid_info->rw	 = rx_window << 1;
 	skb_put(skb, 3);
-	return 0;
 }
 
 /**
- *	pdu_init_as_test_rsp - build TEST response PDU
+ *	llc_pdu_init_as_test_rsp - build TEST response PDU
  *	@skb: Address of the skb to build
  *	@ev_skb: The received TEST command PDU frame
  *
  *	Builds a pdu frame as a TEST response.
  */
-int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
+void llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
 {
 	int dsize;
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
@@ -421,12 +397,11 @@
 		memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize);
 		skb_put(skb, dsize);
 	}
-	return 0;
 }
 
 /**
- *	pdu_init_as_frmr_rsp - builds FRMR response PDU
- *	@pdu_frame: Address of the frame to build
+ *	llc_pdu_init_as_frmr_rsp - builds FRMR response PDU
+ *	@skb: Address of the frame to build
  *	@prev_pdu: The rejected PDU frame
  *	@f_bit: The F bit to set in the PDU
  *	@vs: tx state vari value for the data link conn at the rejecting LLC
@@ -435,8 +410,8 @@
  *
  *	Builds a pdu frame as a FRMR response.
  */
-int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
-			     u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
+void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
+			      u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
 {
 	struct llc_frmr_info *frmr_info;
 	u8 prev_pf = 0;
@@ -460,18 +435,17 @@
 	FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw);
 	FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw);
 	skb_put(skb, 5);
-	return 0;
 }
 
 /**
- *	pdu_init_as_rr_rsp - builds RR response pdu
+ *	llc_pdu_init_as_rr_rsp - builds RR response pdu
  *	@skb: Address of the skb to build
  *	@f_bit: The F bit to set in the PDU
  *	@nr: The seq. number of the expected data PDU from the remote
  *
  *	Builds a pdu frame as an RR response.
  */
-int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
+void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -481,18 +455,17 @@
 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_rej_rsp - builds REJ response pdu
+ *	llc_pdu_init_as_rej_rsp - builds REJ response pdu
  *	@skb: Address of the skb to build
  *	@f_bit: The F bit to set in the PDU
  *	@nr: The seq. number of the expected data PDU from the remote
  *
  *	Builds a pdu frame as a REJ response.
  */
-int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
+void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -502,18 +475,17 @@
 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_rnr_rsp - builds RNR response pdu
- *	@pdu_frame: Address of the frame to build
+ *	llc_pdu_init_as_rnr_rsp - builds RNR response pdu
+ *	@skb: Address of the frame to build
  *	@f_bit: The F bit to set in the PDU
  *	@nr: The seq. number of the expected data PDU from the remote
  *
  *	Builds a pdu frame as an RNR response.
  */
-int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
+void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
@@ -523,24 +495,22 @@
 	pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
 	pdu->ctrl_1 &= 0x0F;    /* setting bits 5..8 to zero(reserved) */
 	pdu->ctrl_2 |= (nr << 1) & 0xFE;  /* set N(R) in bits 10..16 */
-	return 0;
 }
 
 /**
- *	pdu_init_as_ua_rsp - builds UA response pdu
+ *	llc_pdu_init_as_ua_rsp - builds UA response pdu
  *	@skb: Address of the frame to build
  *	@f_bit: The F bit to set in the PDU
  *
  *	Builds a pdu frame as a UA response.
  */
-int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
+void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
 	pdu->ctrl_1  = LLC_PDU_TYPE_U;
 	pdu->ctrl_1 |= LLC_2_PDU_RSP_UA;
 	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
-	return 0;
 }
 
 /**
@@ -548,9 +518,9 @@
  *	@skb: input skb that type of it must be designated.
  *	@type: type of PDU (output argument).
  *
- *	This function designates type of PDU (I,S or U).
+ *	This function designates type of PDU (I, S or U).
  */
-static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
+static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
 {
 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
 
@@ -561,7 +531,6 @@
 			*type = LLC_PDU_TYPE_S;
 	} else
 		*type = LLC_PDU_TYPE_I;
-	return 0;
 }
 
 /**
@@ -571,7 +540,7 @@
  *
  *	This function designates which component of LLC must handle this PDU.
  */
-int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
+void llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
 {
 	u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
@@ -596,7 +565,6 @@
 	}
 out:
 	*dest = type;
-	return 0;
 }
 
 /**
diff -Nru a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c
--- a/net/llc/llc_s_ac.c	Sun Sep 15 19:20:23 2002
+++ b/net/llc/llc_s_ac.c	Sun Sep 15 19:20:23 2002
@@ -57,13 +57,10 @@
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
 			    prim_data->daddr.lsap, LLC_PDU_CMD);
-	rc = llc_pdu_init_as_ui_cmd(skb);
-	if (rc)
-		goto out;
+	llc_pdu_init_as_ui_cmd(skb);
 	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
 	if (!rc)
 		llc_sap_send_pdu(sap, skb);
-out:
 	return rc;
 }
 
@@ -85,13 +82,10 @@
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
 			    prim_data->daddr.lsap, LLC_PDU_CMD);
-	rc = llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
-	if (rc)
-		goto out;
+	llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
 	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
 	if (!rc)
 		llc_sap_send_pdu(sap, skb);
-out:
 	return rc;
 }
 
@@ -118,9 +112,7 @@
 	nskb->dev = skb->dev;
 	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
 			    LLC_PDU_RSP);
-	rc = llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0);
-	if (rc)
-		goto out;
+	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0);
 	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
 		llc_sap_send_pdu(sap, nskb);
@@ -146,13 +138,10 @@
 
 	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
 			    prim_data->daddr.lsap, LLC_PDU_CMD);
-	rc = llc_pdu_init_as_test_cmd(skb);
-	if (rc)
-		goto out;
+	llc_pdu_init_as_test_cmd(skb);
 	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
 	if (!rc)
 		llc_sap_send_pdu(sap, skb);
-out:
 	return rc;
 }
 
@@ -171,9 +160,7 @@
 	nskb->dev = skb->dev;
 	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
 			    LLC_PDU_RSP);
-	rc = llc_pdu_init_as_test_rsp(nskb, skb);
-	if (rc)
-		goto out;
+	llc_pdu_init_as_test_rsp(nskb, skb);
 	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
 		llc_sap_send_pdu(sap, nskb);
diff -Nru a/net/llc/llc_sap.c b/net/llc/llc_sap.c
--- a/net/llc/llc_sap.c	Sun Sep 15 19:20:18 2002
+++ b/net/llc/llc_sap.c	Sun Sep 15 19:20:18 2002
@@ -23,7 +23,6 @@
 #include <net/llc_pdu.h>
 #include <linux/if_tr.h>
 
-static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb);
 static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb);
 static int llc_exec_sap_trans_actions(struct llc_sap *sap,
 				      struct llc_sap_state_trans *trans,
@@ -52,8 +51,7 @@
  *	@sap: SAP
  *	@sk: pointer to connection
  *
- *	This function removes a connection from connection_list of a SAP.
- *	List locking is performed by caller (rtn_all_conns).
+ *	This function removes a connection from sk_list.list of a SAP.
  */
 void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
 {
@@ -64,23 +62,22 @@
 }
 
 /**
- *	llc_sap_send_ev - sends event to SAP state machine
+ *	llc_sap_state_process - sends event to SAP state machine
  *	@sap: pointer to SAP
  *	@skb: pointer to occurred event
  *
  *	After executing actions of the event, upper layer will be indicated
  *	if needed(on receiving an UI frame).
  */
-void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb)
+void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
 {
 	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
 
 	llc_sap_next_state(sap, skb);
-	if (ev->ind_cfm_flag == LLC_IND) {
-		skb_get(skb);
+	if (ev->ind_cfm_flag == LLC_IND)
 		sap->ind(ev->prim);
-	}
-	llc_sap_free_ev(sap, skb);
+	else if (ev->type == LLC_SAP_EV_TYPE_PDU)
+		kfree_skb(skb);
 }
 
 /**
@@ -143,19 +140,6 @@
 }
 
 /**
- *	llc_sap_free_ev - frees an sap event
- *	@sap: pointer to SAP
- *	@skb: released event
- */
-static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb)
-{
-	struct llc_sap_state_ev *ev = llc_sap_ev(skb);
-
-	if (ev->type == LLC_SAP_EV_TYPE_PDU)
-		kfree_skb(skb);
-}
-
-/**
  *	llc_sap_next_state - finds transition, execs actions & change SAP state
  *	@sap: pointer to SAP
  *	@skb: happened event
@@ -206,7 +190,7 @@
 	/* search thru events for this state until list exhausted or until
 	 * its obvious the event is not valid for the current state
 	 */
-	for (next_trans = curr_state->transitions; next_trans [i]->ev; i++)
+	for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
 		if (!next_trans[i]->ev(sap, skb)) {
 			/* got event match; return it */
 			rc = next_trans[i];
diff -Nru a/net/llc/llc_sock.c b/net/llc/llc_sock.c
--- a/net/llc/llc_sock.c	Sun Sep 15 19:19:28 2002
+++ b/net/llc/llc_sock.c	Sun Sep 15 19:19:28 2002
@@ -11,6 +11,7 @@
  *   connections.
  *
  * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ *		 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
  * This program can be redistributed or modified under the terms of the
  * GNU General Public License as published by the Free Software Foundation.
@@ -38,6 +39,7 @@
 #include <net/llc_sap.h>
 #include <net/llc_pdu.h>
 #include <net/llc_conn.h>
+#include <net/llc_mac.h>
 #include <linux/llc.h>
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
@@ -46,7 +48,6 @@
 /* remember: uninitialized global data is zeroed because its in .bss */
 static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
 static u16 llc_ui_sap_link_no_max[256];
-static u8 llc_ui_addrany[IFHWADDRLEN];
 static struct sockaddr_llc llc_ui_addrnull;
 static struct proto_ops llc_ui_ops;
 static struct sock *llc_ui_sockets;
@@ -54,8 +55,16 @@
 
 static int llc_ui_indicate(struct llc_prim_if_block *prim);
 static int llc_ui_confirm(struct llc_prim_if_block *prim);
-static int llc_ui_wait_for_conn(struct sock *sk, int seconds);
-static int llc_ui_wait_for_disc(struct sock *sk, int seconds);
+static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
+static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
+static int llc_ui_wait_for_data(struct sock *sk, int timeout);
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
+
+#if 0
+#define dprintk(args...) printk(KERN_DEBUG args)
+#else
+#define dprintk(args...)
+#endif
 
 /**
  *	llc_ui_next_link_no - return the next unused link number for a sap
@@ -63,64 +72,33 @@
  *
  *	Return the next unused link number for a given sap.
  */
-static inline u16 llc_ui_next_link_no(int sap)
+static __inline__ u16 llc_ui_next_link_no(int sap)
 {
 	return llc_ui_sap_link_no_max[sap]++;
 }
 
 /**
- *	llc_ui_mac_match - determines if two mac addresses are the same
- *	@mac1: First mac address to compare.
- *	@mac2: Second mac address to compare.
- *
- *	Determines if two given mac address are the same.  Returns 0 if there
- *	is not a complete match up to len, 1 if a complete match up to len is
- *	found.
- */
-static inline u8 llc_ui_mac_match(u8 *mac1, u8 *mac2)
-{
-	return !memcmp(mac1, mac2, IFHWADDRLEN);
-}
-
-/**
- *	llc_ui_mac_null - determines if a address is a null mac address
- *	@mac: Mac address to test if null.
+ *	llc_proto_type - return eth protocol for ARP header type
+ *	@arphrd: ARP header type.
  *
- *	Determines if a given address is a null mac address.  Returns 0 if the
- *	address is not a null mac, 1 if the address is a null mac.
+ *	Given an ARP header type return the corresponding ethernet protocol.
  */
-static inline u8 llc_ui_mac_null(u8 *mac)
+static __inline__ u16 llc_proto_type(u16 arphrd)
 {
-	return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN);
+	return arphrd == ARPHRD_IEEE802_TR ?
+		         htons(ETH_P_TR_802_2) : htons(ETH_P_802_2);
 }
 
 /**
  *	llc_ui_addr_null - determines if a address structure is null
  *	@addr: Address to test if null.
  */
-static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr)
+static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
 {
 	return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
 }
 
 /**
- *	llc_ui_protocol_type - return eth protocol for ARP header type
- *	@arphrd: ARP header type.
- *
- *	Given an ARP header type return the corresponding ethernet protocol.
- *	Returns  0 if ARP header type not supported or the corresponding
- *	ethernet protocol type.
- */
-static inline u16 llc_ui_protocol_type(u16 arphrd)
-{
-	u16 rc = htons(ETH_P_802_2);
-
-	if (arphrd == ARPHRD_IEEE802_TR)
-		rc = htons(ETH_P_TR_802_2);
-	return rc;
-}
-
-/**
  *	llc_ui_header_len - return length of llc header based on operation
  *	@sk: Socket which contains a valid llc socket type.
  *	@addr: Complete sockaddr_llc structure received from the user.
@@ -129,7 +107,8 @@
  *	operation the user would like to perform and the type of socket.
  *	Returns the correct llc header length.
  */
-static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
+static __inline__ u8 llc_ui_header_len(struct sock *sk,
+				       struct sockaddr_llc *addr)
 {
 	u8 rc = LLC_PDU_LEN_U;
 
@@ -141,138 +120,31 @@
 }
 
 /**
- *	llc_ui_send_conn - send connect command for new llc2 connection
- *	@sap : Sap the socket is bound to.
- *	@addr: Source and destination fields provided by the user.
- *	@dev : Device which this connection should use.
- *	@link: Link number to assign to this connection.
- *
- *	Send a connect command to the llc layer for a new llc2 connection.
- *	Returns 0 upon success, non-zero if action didn't succeed.
- */
-static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
-			    struct sockaddr_llc *addr,
-			    struct net_device *dev, int link)
-{
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-
-	prim.data		= &prim_data;
-	prim.sap		= sap;
-	prim.prim		= LLC_CONN_PRIM;
-	prim_data.conn.dev	= dev;
-	prim_data.conn.link	= link;
-	prim_data.conn.sk	= NULL;
-	prim_data.conn.handler	= sk;
-	prim_data.conn.pri	= 0;
-	prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap;
-	prim_data.conn.daddr.lsap = addr->sllc_dsap;
-	memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN);
-	memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
-	return sap->req(&prim);
-}
-
-/**
- *	llc_ui_send_disc - send disc command to llc layer
- *	@sk: Socket with valid llc information.
- *
- *	Send a disconnect command to the llc layer for an established
- *	llc2 connection.
- *	Returns 0 upon success, non-zero if action did not succeed.
- */
-static int llc_ui_send_disc(struct sock *sk)
-{
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-	int rc = 0;
-
-	if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
-		goto out;
-	sk->state	    = TCP_CLOSING;
-	prim.data	    = &prim_data;
-	prim.sap	    = llc_ui->sap;
-	prim.prim	    = LLC_DISC_PRIM;
-	prim_data.disc.sk   = llc_ui->core_sk;
-	prim_data.disc.link = llc_ui->link;
-	rc = llc_ui->sap->req(&prim);
-out:
-	return rc;
-}
-
-/**
  *	llc_ui_send_data - send data via reliable llc2 connection
- *	@sap: Sap the socket is bound to.
  *	@sk: Connection the socket is using.
  *	@skb: Data the user wishes to send.
  *	@addr: Source and destination fields provided by the user.
+ *	@noblock: can we block waiting for data?
  *
  *	Send data via reliable llc2 connection.
- *	Returns 0 upon success,  non-zero if action did not succeed.
+ *	Returns 0 upon success, non-zero if action did not succeed.
  */
-static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk,
-			    struct sk_buff *skb, struct sockaddr_llc *addr)
+static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
 {
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-	struct llc_ui_opt* llc_ui = llc_ui_sk(sk);
-	struct llc_opt* llc_core = llc_sk(llc_ui->core_sk);
-	int rc;
+	struct llc_opt* llc = llc_sk(sk);
+	int rc = 0;
 
-	prim.data	   = &prim_data;
-	prim.sap	   = sap;
-	prim.prim	   = LLC_DATA_PRIM;
-	prim_data.data.skb = skb;
-	prim_data.data.pri = 0;
-	prim_data.data.sk  = llc_ui->core_sk;
-	skb->protocol	   = llc_ui_protocol_type(addr->sllc_arphrd);
-	sock_hold(sk);
-try:
-	rc = sap->req(&prim);
-	if (rc != -EBUSY)
-		goto out;
-	rc = wait_event_interruptible(sk->socket->wait, !llc_ui->core_sk ||
-				      !llc_core->failed_data_req);
+	if (llc_data_accept_state(llc->state) || llc->p_flag) {
+		int timeout = sock_sndtimeo(sk, noblock);
+
+		rc = llc_ui_wait_for_busy_core(sk, timeout);
+	}
 	if (!rc)
-		goto try;
-	if (!llc_ui->core_sk)
-		rc = -ENOTCONN;
-out:
-	sock_put(sk);
+		rc = llc_build_and_send_pkt(sk, skb);
 	return rc;
 }
 
 /**
- *	llc_ui_send_llc1 - send llc1 prim data block to llc layer.
- *	@sap      : Sap the socket is bound to.
- *	@skb      : Data the user wishes to send.
- *	@addr     : Source and destination fields provided by the user.
- *	@primitive: Action the llc layer should perform.
- *
- *	Send an llc1 primitive data block to the llc layer for processing.
- *	This function is used for test, xid and unit_data messages.
- *	Returns 0 upon success, non-zero if action did not succeed.
- */
-static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb,
-			    struct sockaddr_llc *addr, int primitive)
-{
-	union llc_u_prim_data prim_data;
-	struct llc_prim_if_block prim;
-
-	prim.data 		  = &prim_data;
-	prim.sap 		  = sap;
-	prim.prim		  = primitive;
-	prim_data.test.skb 	  = skb;
-	prim_data.test.saddr.lsap = sap->laddr.lsap;
-	prim_data.test.daddr.lsap = addr->sllc_dsap;
-	skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd);
-	memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
-	memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
-	return sap->req(&prim);
-}
-
-/**
  *	llc_ui_find_sap - returns sap struct that matches sap number specified
  *	@sap: Sap number to search for.
  *
@@ -280,19 +152,19 @@
  *	structure which matches the sap number the user specified.
  *	Returns llc_sap upon match, %NULL otherwise.
  */
-static inline struct llc_sap *llc_ui_find_sap(u8 sap)
+static __inline__ struct llc_sap *llc_ui_find_sap(u8 sap)
 {
 	struct sock *sk;
 	struct llc_sap *s = NULL;
 
 	read_lock_bh(&llc_ui_sockets_lock);
 	for (sk = llc_ui_sockets; sk; sk = sk->next) {
-		struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+		struct llc_opt *llc = llc_sk(sk);
 
-		if (!llc_ui->sap)
+		if (!llc->sap)
 			continue;
-		if (llc_ui->sap->laddr.lsap == sap) {
-			s = llc_ui->sap;
+		if (llc->sap->laddr.lsap == sap) {
+			s = llc->sap;
 			break;
 		}
 	}
@@ -306,13 +178,13 @@
 	struct sock *sk;
 
 	for (sk = llc_ui_sockets; sk; sk = sk->next) {
-		struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+		struct llc_opt *llc = llc_sk(sk);
 
-		if (llc_ui->addr.sllc_ssap == laddr->lsap &&
-		    llc_ui->addr.sllc_dsap == daddr->lsap &&
-		    llc_ui_mac_null(llc_ui->addr.sllc_mmac) &&
-		    llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac) &&
-		    llc_ui_mac_match(llc_ui->addr.sllc_dmac, daddr->mac))
+		if (llc->addr.sllc_ssap == laddr->lsap &&
+		    llc->addr.sllc_dsap == daddr->lsap &&
+		    llc_mac_null(llc->addr.sllc_mmac) &&
+		    llc_mac_match(llc->addr.sllc_smac, laddr->mac) &&
+		    llc_mac_match(llc->addr.sllc_dmac, daddr->mac))
 			break;
 	}
 	return sk;
@@ -335,31 +207,31 @@
 	struct sock *sk, *tmp_sk;
 
 	for (sk = llc_ui_sockets; sk; sk = sk->next) {
-		struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+		struct llc_opt *llc = llc_sk(sk);
 
-		if (llc_ui->addr.sllc_ssap != laddr->lsap)
+		if (llc->addr.sllc_ssap != laddr->lsap)
 			continue;
-		if (llc_ui_mac_null(llc_ui->addr.sllc_smac)) {
-			if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac) &&
-			    !llc_ui_mac_match(llc_ui->addr.sllc_mmac,
-				    	      laddr->mac))
+		if (llc_mac_null(llc->addr.sllc_smac)) {
+			if (!llc_mac_null(llc->addr.sllc_mmac) &&
+			    !llc_mac_match(llc->addr.sllc_mmac,
+				    	   laddr->mac))
 				continue;
 			break;
 		}
-		if (dev && !llc_ui_mac_null(llc_ui->addr.sllc_mmac) &&
-		    llc_ui_mac_match(llc_ui->addr.sllc_mmac, laddr->mac) &&
-		    llc_ui_mac_match(llc_ui->addr.sllc_smac, dev->dev_addr))
+		if (dev && !llc_mac_null(llc->addr.sllc_mmac) &&
+		    llc_mac_match(llc->addr.sllc_mmac, laddr->mac) &&
+		    llc_mac_match(llc->addr.sllc_smac, dev->dev_addr))
 			break;
 		if (dev->flags & IFF_LOOPBACK)
 			break;
-		if (!llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac))
+		if (!llc_mac_match(llc->addr.sllc_smac, laddr->mac))
 			continue;
 		tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr);
 		if (tmp_sk) {
 			sk = tmp_sk;
 			break;
 		}
-		if (llc_ui_mac_null(llc_ui->addr.sllc_dmac))
+		if (llc_mac_null(llc->addr.sllc_dmac))
 			break;
 	}
 	return sk;
@@ -399,7 +271,7 @@
  *
  *	Insert a socket into the local llc socket list.
  */
-static inline void llc_ui_insert_socket(struct sock *sk)
+static __inline__ void llc_ui_insert_socket(struct sock *sk)
 {
 	write_lock_bh(&llc_ui_sockets_lock);
 	sk->next = llc_ui_sockets;
@@ -417,7 +289,7 @@
  *
  *	Remove a socket from the local llc socket list.
  */
-static inline void llc_ui_remove_socket(struct sock *sk)
+static __inline__ void llc_ui_remove_socket(struct sock *sk)
 {
 	write_lock_bh(&llc_ui_sockets_lock);
 	if (sk->pprev) {
@@ -425,7 +297,8 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		/* this only makes sense if the socket was inserted on the
+		/*
+		 * This only makes sense if the socket was inserted on the
 		 * list, if sk->pprev is NULL it wasn't
 		 */
 		sock_put(sk);
@@ -433,38 +306,13 @@
 	write_unlock_bh(&llc_ui_sockets_lock);
 }
 
-/**
- *	llc_ui_destroy_sk - destroy socket
- *	@data: Socket which is to be destroyed.
- *
- *	Really destroy the socket.
- */
-static void llc_ui_destroy_sk(struct sock *sk)
-{
-	skb_queue_purge(&sk->receive_queue);
-	skb_queue_purge(&sk->write_queue);
-	sock_put(sk);
-	MOD_DEC_USE_COUNT;
-}
-
-/**
- *	llc_ui_destroy_timer - try to destroy socket again
- *	@data: Socket which is to be destroyed.
- *
- *	Attempt to destroy a socket which was previously destroyed but
- *	was still in use at the time.
- */
-static void llc_ui_destroy_timer(unsigned long data)
+static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
 {
-	struct sock *sk = (struct sock *)data;
-
-	if (!atomic_read(&sk->wmem_alloc) &&
-	    !atomic_read(&sk->rmem_alloc) && sk->dead)
-		llc_ui_destroy_sk(sk);
-	else {
-		sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
-		add_timer(&sk->timer);
-	}
+	sk->type   = sock->type;
+	sk->sleep  = &sock->wait;
+	sk->socket = sock;
+	sock->sk   = sk;
+	sock->ops  = &llc_ui_ops;
 }
 
 /**
@@ -479,31 +327,17 @@
 static int llc_ui_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	struct llc_ui_opt *llc_ui;
 	int rc = -ESOCKTNOSUPPORT;
 
-	MOD_INC_USE_COUNT;
-	if (sock->type != SOCK_DGRAM && sock->type != SOCK_STREAM)
-		goto decmod;
-	rc = -ENOMEM;
-	sk = sk_alloc(PF_LLC, GFP_KERNEL, 1, NULL);
-	if (!sk)
-		goto decmod;
-	llc_ui = kmalloc(sizeof(*llc_ui), GFP_KERNEL);
-	if (!llc_ui)
-		goto outsk;
-	memset(llc_ui, 0, sizeof(*llc_ui));
-	rc = 0;
-	sock_init_data(sock, sk);
-	llc_ui_sk(sk) = llc_ui;
-	sock->ops = &llc_ui_ops;
-out:
+	if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
+		rc = -ENOMEM;
+		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
+		if (sk) {
+			rc = 0;
+			llc_ui_sk_init(sock, sk);
+		}
+	}
 	return rc;
-outsk:
-	sk_free(sk);
-decmod:
-	MOD_DEC_USE_COUNT;
-	goto out;
 }
 
 /**
@@ -515,28 +349,26 @@
 static int llc_ui_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui;
+	struct llc_opt *llc;
 
 	if (!sk)
 		goto out;
-	llc_ui = llc_ui_sk(sk);
-	if (llc_ui->core_sk && !llc_ui_send_disc(sk))
-		llc_ui_wait_for_disc(sk, 255);
-	llc_ui_remove_socket(sk);
-	if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap))
-		llc_sap_close(llc_ui->sap);
-	sock_orphan(sk);
-	sock->sk = NULL;
-	if (!atomic_read(&sk->wmem_alloc) &&
-	    !atomic_read(&sk->rmem_alloc) && sk->dead)
-		llc_ui_destroy_sk(sk);
-	else {
-		init_timer(&sk->timer);
-		sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
-		sk->timer.function = llc_ui_destroy_timer;
-		sk->timer.data = (unsigned long)sk;
-		add_timer(&sk->timer);
+	sock_hold(sk);
+	lock_sock(sk);
+	llc = llc_sk(sk);
+	dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
+		llc->laddr.lsap, llc->daddr.lsap);
+	if (!llc_send_disc(sk))
+		llc_ui_wait_for_disc(sk, sk->rcvtimeo);
+	release_sock(sk);
+	if (!sk->zapped) {
+		llc_sap_unassign_sock(llc->sap, sk);
+		llc_ui_remove_socket(sk);
 	}
+	if (llc->sap && list_empty(&llc->sap->sk_list.list))
+		llc_sap_close(llc->sap);
+	sock_put(sk);
+	llc_sk_free(sk);
 out:
 	return 0;
 }
@@ -590,7 +422,7 @@
 static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc = llc_sk(sk);
 	struct llc_sap *sap;
 	struct net_device *dev = NULL;
 	int rc = -EINVAL;
@@ -598,14 +430,14 @@
 	if (!sk->zapped)
 		goto out;
 	/* bind to a specific mac, optional. */
-	if (!llc_ui_mac_null(addr->sllc_smac)) {
+	if (!llc_mac_null(addr->sllc_smac)) {
 		rtnl_lock();
 		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
 		rtnl_unlock();
 		rc = -ENETUNREACH;
 		if (!dev)
 			goto out;
-		llc_ui->dev = dev;
+		llc->dev = dev;
 	}
 	/* bind to a specific sap, optional. */
 	if (!addr->sllc_ssap) {
@@ -626,11 +458,11 @@
 		struct sock *ask;
 
 		rc = -EUSERS; /* can't get exclusive use of sap */
-		if (!dev && llc_ui_mac_null(addr->sllc_mmac))
+		if (!dev && llc_mac_null(addr->sllc_mmac))
 			goto out;
 		memset(&laddr, 0, sizeof(laddr));
 		memset(&daddr, 0, sizeof(daddr));
-		if (!llc_ui_mac_null(addr->sllc_mmac)) {
+		if (!llc_mac_null(addr->sllc_mmac)) {
 			if (sk->type != SOCK_DGRAM) {
 				rc = -EOPNOTSUPP;
 				goto out;
@@ -646,10 +478,16 @@
 			goto out;
 		}
 	}
-	memcpy(&llc_ui->addr, addr, sizeof(*addr));
-	llc_ui->sap = sap;
+	llc->laddr.lsap = addr->sllc_ssap;
+	if (llc->dev)
+		memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
+	llc->daddr.lsap = addr->sllc_dsap;
+	memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
+	memcpy(&llc->addr, addr, sizeof(llc->addr));
 	rc = sk->zapped = 0;
 	llc_ui_insert_socket(sk);
+	/* assign new connection to it's SAP */
+	llc_sap_assign_sock(sap, sk);
 out:
 	return rc;
 }
@@ -678,6 +516,7 @@
 	struct sock *sk = sock->sk;
 	int rc = -EINVAL;
 
+	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
 	if (!sk->zapped || addrlen != sizeof(*addr))
 		goto out;
 	rc = -EAFNOSUPPORT;
@@ -711,9 +550,9 @@
 	rc = -EINVAL;
 	if (how != 2)
 		goto out;
-	rc = llc_ui_send_disc(sk);
+	rc = llc_send_disc(sk);
 	if (!rc)
-		llc_ui_wait_for_disc(sk, 255);
+		rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
 	/* Wake up anyone sleeping in poll */
 	sk->state_change(sk);
 out:
@@ -739,7 +578,7 @@
 			  int addrlen, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc = llc_sk(sk);
 	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
 	struct net_device *dev;
 	int rc = -EINVAL;
@@ -757,14 +596,15 @@
 		if (rc)
 			goto out;
 	}
-	if (!llc_ui->dev) {
+	if (!llc->dev) {
 		rtnl_lock();
 		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
 		rtnl_unlock();
 		if (!dev)
 			goto out;
+		llc->dev = dev;
 	} else
-		dev = llc_ui->dev;
+		dev = llc->dev;
 	if (sk->type != SOCK_STREAM)
 		goto out;
 	rc = -EALREADY;
@@ -772,14 +612,18 @@
 		goto out;
 	sock->state = SS_CONNECTING;
 	sk->state   = TCP_SYN_SENT;
-	llc_ui->link   = llc_ui_next_link_no(llc_ui->sap->laddr.lsap);
-	rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link);
+	llc->link   = llc_ui_next_link_no(llc->sap->laddr.lsap);
+	rc = llc_establish_connection(sk, dev->dev_addr,
+				      addr->sllc_dmac, addr->sllc_dsap);
 	if (rc) {
+		dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
 		sock->state = SS_UNCONNECTED;
 		sk->state   = TCP_CLOSE;
 		goto out;
 	}
-	rc = llc_ui_wait_for_conn(sk, 255);
+	rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
+	if (rc)
+		dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
 out:
 	release_sock(sk);
 	return rc;
@@ -802,7 +646,7 @@
 	if (sock->state != SS_UNCONNECTED)
 		goto out;
 	rc = -EOPNOTSUPP;
-	if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET)
+	if (sk->type != SOCK_STREAM)
 		goto out;
 	rc = -EAGAIN;
 	if (sk->zapped)
@@ -810,8 +654,6 @@
 	rc = 0;
 	if (!(unsigned)backlog)	/* BSDism */
 		backlog = 1;
-	if ((unsigned)backlog > SOMAXCONN)
-		backlog = SOMAXCONN;
 	sk->max_ack_backlog = backlog;
 	if (sk->state != TCP_LISTEN) {
 		sk->ack_backlog = 0;
@@ -823,18 +665,43 @@
 	return rc;
 }
 
-static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
+static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	int rc, timeout = seconds * HZ;
+	int rc;
 
 	add_wait_queue_exclusive(sk->sleep, &wait);
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
 		rc = 0;
-		if (sk->state != TCP_CLOSE)
+		if (sk->state != TCP_CLOSE) {
+			release_sock(sk);
 			timeout = schedule_timeout(timeout);
-		else
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -EAGAIN;
+		if (sk->state == TCP_CLOSE)
 			break;
 		rc = -ERESTARTSYS;
 		if (signal_pending(current))
@@ -842,31 +709,60 @@
 		rc = -EAGAIN;
 		if (!timeout)
 			break;
+		rc = 0;
+		if (sk->state != TCP_ESTABLISHED) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
 	}
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(sk->sleep, &wait);
 	return rc;
 }
 
-static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
+static int llc_ui_wait_for_data(struct sock *sk, int timeout)
 {
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
 	DECLARE_WAITQUEUE(wait, current);
-	int rc, timeout = seconds * HZ;
+	int rc = 0;
 
 	add_wait_queue_exclusive(sk->sleep, &wait);
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
 		rc = 0;
-		if (sk->state != TCP_ESTABLISHED)
+		if (skb_queue_empty(&sk->receive_queue)) {
+			release_sock(sk);
 			timeout = schedule_timeout(timeout);
-		if (sk->state == TCP_ESTABLISHED) {
-			if (!llc_ui->core_sk)
-				rc = -EAGAIN;
+			lock_sock(sk);
+		} else
 			break;
-		}
-		rc = -EAGAIN;
-		if (sk->state == TCP_CLOSE)
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct llc_opt *llc = llc_sk(sk);
+	int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		dprintk("%s: looping...\n", __FUNCTION__);
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -ENOTCONN;
+		if (sk->shutdown & RCV_SHUTDOWN)
 			break;
 		rc = -ERESTARTSYS;
 		if (signal_pending(current))
@@ -874,6 +770,13 @@
 		rc = -EAGAIN;
 		if (!timeout)
 			break;
+		rc = 0;
+		if (llc_data_accept_state(llc->state) || llc->p_flag) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
 	}
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(sk->sleep, &wait);
@@ -892,63 +795,48 @@
 static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	struct sock *sk = sock->sk, *newsk;
-	struct llc_ui_opt *llc_ui, *newllc_ui;
-	struct llc_opt *newllc_core;
+	struct llc_opt *llc, *newllc;
 	struct sk_buff *skb;
 	int rc = -EOPNOTSUPP;
 
+	dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
 	lock_sock(sk);
-	if (sk->type != SOCK_SEQPACKET && sk->type != SOCK_STREAM)
+	if (sk->type != SOCK_STREAM)
 		goto out;
 	rc = -EINVAL;
 	if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN)
 		goto out;
 	/* wait for a connection to arrive. */
-	do {
-		skb = skb_dequeue(&sk->receive_queue);
-		if (!skb) {
-			rc = -EWOULDBLOCK;
-			if (flags & O_NONBLOCK)
-				goto out;
-			interruptible_sleep_on(sk->sleep);
-			rc = -ERESTARTSYS;
-			if (signal_pending(current))
-				goto out;
-		}
-	} while (!skb);
-
-	rc = -EINVAL;
-	if(!skb->sk)
-		goto frees;
-	/* attach connection to a new socket. */
-	rc = llc_ui_create(newsock, sk->protocol);
+	rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
 	if (rc)
+		goto out;
+	dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
+	skb = skb_dequeue(&sk->receive_queue);
+	rc = -EINVAL;
+	if (!skb->sk)
 		goto frees;
 	rc = 0;
-	newsk			= newsock->sk;
+	newsk = skb->sk;
+	/* attach connection to a new socket. */
+	llc_ui_sk_init(newsock, newsk);
 	newsk->pair		= NULL;
-	newsk->socket		= newsock;
-	newsk->sleep		= &newsock->wait;
 	newsk->zapped		= 0;
 	newsk->state		= TCP_ESTABLISHED;
 	newsock->state		= SS_CONNECTED;
-	llc_ui			= llc_ui_sk(sk);
-	newllc_ui		= llc_ui_sk(newsk);
-	newllc_ui->sap		= llc_ui->sap;
-	newllc_ui->dev		= llc_ui->dev;
-	newllc_ui->core_sk	= skb->sk;
-	newllc_core		= llc_sk(newllc_ui->core_sk);
-	newllc_ui->link		= newllc_core->link;
-	newllc_core->handler	= newsk;
-	memcpy(&newllc_ui->addr, &llc_ui->addr, sizeof(newllc_ui->addr));
-	memcpy(newllc_ui->addr.sllc_dmac, newllc_core->daddr.mac, IFHWADDRLEN);
-	newllc_ui->addr.sllc_dsap	= newllc_core->daddr.lsap;
+	llc			= llc_sk(sk);
+	newllc			= llc_sk(newsk);
+	memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
+	memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
+	newllc->addr.sllc_dsap = newllc->daddr.lsap;
+	newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
 
 	/* put original socket back into a clean listen state. */
 	sk->state = TCP_LISTEN;
 	sk->ack_backlog--;
 	llc_ui_insert_socket(newsk);
 	skb->sk = NULL;
+	dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
+		llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
 frees:
 	kfree_skb(skb);
 out:
@@ -973,12 +861,21 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
 	struct sk_buff *skb;
-	int rc = -ENOMEM, copied = 0;
+	int rc = -ENOMEM, copied = 0, timeout;
 	int noblock = flags & MSG_DONTWAIT;
 
+	dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
+		llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
 	lock_sock(sk);
-	skb = skb_recv_datagram(sk, flags, noblock, &rc);
-	if (!skb)
+	timeout = sock_rcvtimeo(sk, noblock);
+	rc = llc_ui_wait_for_data(sk, timeout);
+	if (rc) {
+		dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n",
+			__FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
+		goto out;
+	}
+	skb = skb_dequeue(&sk->receive_queue);
+	if (!skb) /* shutdown */
 		goto out;
 	copied = skb->len;
 	if (copied > size) {
@@ -992,7 +889,7 @@
 		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
 	msg->msg_namelen = sizeof(*uaddr);
 dgram_free:
-	skb_free_datagram(sk, skb); /* Free the datagram. */
+	kfree_skb(skb);
 out:
 	release_sock(sk);
 	return rc ? : copied;
@@ -1012,24 +909,23 @@
 			  struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc = llc_sk(sk);
 	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
 	int flags = msg->msg_flags;
+	int noblock = flags & MSG_DONTWAIT;
 	struct net_device *dev;
 	struct sk_buff *skb;
-	int rc = -EOPNOTSUPP, size = 0;
+	int rc = -EINVAL, size = 0;
 
+	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
 	lock_sock(sk);
-	if (flags & ~MSG_DONTWAIT)
-		goto release;
-	rc = -EINVAL;
 	if (addr) {
 		if (msg->msg_namelen < sizeof(*addr))
 			goto release;
 	} else {
-		if (llc_ui_addr_null(&llc_ui->addr))
+		if (llc_ui_addr_null(&llc->addr))
 			goto release;
-		addr = &llc_ui->addr;
+		addr = &llc->addr;
 	}
 	/* must bind connection to sap if user hasn't done it. */
 	if (sk->zapped) {
@@ -1038,7 +934,7 @@
 		if (rc)
 			goto release;
 	}
-	if (!llc_ui->dev) {
+	if (!llc->dev) {
 		rtnl_lock();
 		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
 		rtnl_unlock();
@@ -1046,43 +942,49 @@
 		if (!dev)
 			goto release;
 	} else
-		dev = llc_ui->dev;
+		dev = llc->dev;
 	size = dev->hard_header_len + len + llc_ui_header_len(sk, addr);
 	rc = -EMSGSIZE;
 	if (size > dev->mtu)
 		goto release;
-	skb = sock_alloc_send_skb(sk, size, flags & MSG_DONTWAIT, &rc);
+	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
 	if (!skb)
 		goto release;
-	skb->sk  = sk;
-	skb->dev = dev;
+	skb->sk	      = sk;
+	skb->dev      = dev;
+	skb->protocol = llc_proto_type(addr->sllc_arphrd);
 	skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr));
 	rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
 	if (rc)
-		goto release;
+		goto out;
 	if (addr->sllc_test) {
-		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM);
+		llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_dmac,
+					    addr->sllc_dsap);
 		goto out;
 	}
 	if (addr->sllc_xid) {
-		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM);
+		llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_dmac,
+					   addr->sllc_dsap);
 		goto out;
 	}
 	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
-		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM);
+		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac,
+					  addr->sllc_dsap);
 		goto out;
 	}
 	rc = -ENOPROTOOPT;
 	if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
 		goto out;
-	rc = -ENOTCONN;
-	if (!llc_ui->core_sk)
-		goto out;
-	rc = llc_ui_send_data(llc_ui->sap, sk, skb, addr);
+	rc = llc_ui_send_data(sk, skb, noblock);
+	if (rc)
+		dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);
 out:
 	if (rc)
-		skb_free_datagram(sk, skb);
+		kfree_skb(skb);
 release:
+	if (rc)
+		dprintk("%s: failed sending from %02X to %02X: %d\n",
+			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
 	release_sock(sk);
 	return rc ? : len;
 }
@@ -1101,7 +1003,7 @@
 {
 	struct sockaddr_llc sllc;
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc = llc_sk(sk);
 	int rc = 0;
 
 	lock_sock(sk);
@@ -1113,20 +1015,19 @@
 		rc = -ENOTCONN;
 		if (sk->state != TCP_ESTABLISHED)
 			goto out;
-		if(llc_ui->dev)
-			sllc.sllc_arphrd = llc_ui->dev->type;
-		sllc.sllc_dsap = llc_sk(llc_ui->core_sk)->daddr.lsap;
-		memcpy(&sllc.sllc_dmac, &llc_sk(llc_ui->core_sk)->daddr.mac,
-		       IFHWADDRLEN);
+		if(llc->dev)
+			sllc.sllc_arphrd = llc->dev->type;
+		sllc.sllc_dsap = llc->daddr.lsap;
+		memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN);
 	} else {
 		rc = -EINVAL;
-		if (!llc_ui->sap)
+		if (!llc->sap)
 			goto out;
-		sllc.sllc_ssap = llc_ui->sap->laddr.lsap;
+		sllc.sllc_ssap = llc->sap->laddr.lsap;
 
-		if (llc_ui->dev) {
-			sllc.sllc_arphrd = llc_ui->dev->type;
-			memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr,
+		if (llc->dev) {
+			sllc.sllc_arphrd = llc->dev->type;
+			memcpy(&sllc.sllc_smac, &llc->dev->dev_addr,
 			       IFHWADDRLEN);
 		}
 	}
@@ -1166,61 +1067,56 @@
 			     char *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
-	struct llc_opt *llc_core;
+	struct llc_opt *llc = llc_sk(sk);
 	int rc = -EINVAL, opt;
 
 	lock_sock(sk);
 	if (level != SOL_LLC || optlen != sizeof(int))
 		goto out;
-	rc = -ENOTCONN;
-	if (!llc_ui->core_sk)
-		goto out;
 	rc = get_user(opt, (int *)optval);
 	if (rc)
 		goto out;
 	rc = -EINVAL;
-	llc_core = llc_sk(llc_ui->core_sk);
 	switch (optname) {
 		case LLC_OPT_RETRY:
 			if (opt > LLC_OPT_MAX_RETRY)
 				goto out;
-			llc_core->n2 = opt;
+			llc->n2 = opt;
 			break;
 		case LLC_OPT_SIZE:
 			if (opt > LLC_OPT_MAX_SIZE)
 				goto out;
-			llc_core->n1 = opt;
+			llc->n1 = opt;
 			break;
 		case LLC_OPT_ACK_TMR_EXP:
 			if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
 				goto out;
-			llc_core->ack_timer.expire = opt;
+			llc->ack_timer.expire = opt;
 			break;
 		case LLC_OPT_P_TMR_EXP:
 			if (opt > LLC_OPT_MAX_P_TMR_EXP)
 				goto out;
-			llc_core->pf_cycle_timer.expire = opt;
+			llc->pf_cycle_timer.expire = opt;
 			break;
 		case LLC_OPT_REJ_TMR_EXP:
 			if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
 				goto out;
-			llc_core->rej_sent_timer.expire = opt;
+			llc->rej_sent_timer.expire = opt;
 			break;
 		case LLC_OPT_BUSY_TMR_EXP:
 			if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
 				goto out;
-			llc_core->busy_state_timer.expire = opt;
+			llc->busy_state_timer.expire = opt;
 			break;
 		case LLC_OPT_TX_WIN:
 			if (opt > LLC_OPT_MAX_WIN)
 				goto out;
-			llc_core->k = opt;
+			llc->k = opt;
 			break;
 		case LLC_OPT_RX_WIN:
 			if (opt > LLC_OPT_MAX_WIN)
 				goto out;
-			llc_core->rw = opt;
+			llc->rw = opt;
 			break;
 		default:
 			rc = -ENOPROTOOPT;
@@ -1246,40 +1142,35 @@
 			     char *optval, int *optlen)
 {
 	struct sock *sk = sock->sk;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
-	struct llc_opt *llc_core;
+	struct llc_opt *llc = llc_sk(sk);
 	int val = 0, len = 0, rc = -EINVAL;
 
 	lock_sock(sk);
 	if (level != SOL_LLC)
 		goto out;
-	rc = -ENOTCONN;
-	if (!llc_ui->core_sk)
-		goto out;
 	rc = get_user(len, optlen);
 	if (rc)
 		goto out;
 	rc = -EINVAL;
 	if (len != sizeof(int))
 		goto out;
-	llc_core = llc_sk(llc_ui->core_sk);
 	switch (optname) {
 		case LLC_OPT_RETRY:
-			val = llc_core->n2;				break;
+			val = llc->n2;				break;
 		case LLC_OPT_SIZE:
-			val = llc_core->n1;				break;
+			val = llc->n1;				break;
 		case LLC_OPT_ACK_TMR_EXP:
-			val = llc_core->ack_timer.expire;		break;
+			val = llc->ack_timer.expire;		break;
 		case LLC_OPT_P_TMR_EXP:
-			val = llc_core->pf_cycle_timer.expire;		break;
+			val = llc->pf_cycle_timer.expire;	break;
 		case LLC_OPT_REJ_TMR_EXP:
-			val = llc_core->rej_sent_timer.expire;		break;
+			val = llc->rej_sent_timer.expire;	break;
 		case LLC_OPT_BUSY_TMR_EXP:
-			val = llc_core->busy_state_timer.expire;	break;
+			val = llc->busy_state_timer.expire;	break;
 		case LLC_OPT_TX_WIN:
-			val = llc_core->k;				break;
+			val = llc->k;				break;
 		case LLC_OPT_RX_WIN:
-			val = llc_core->rw;				break;
+			val = llc->rw;				break;
 		default:
 			rc = -ENOPROTOOPT;
 			goto out;
@@ -1302,7 +1193,7 @@
 {
 	struct llc_prim_test *prim_data = &prim->data->test;
 	struct sk_buff *skb = prim_data->skb;
-	struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+	struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
 	struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
 						 &prim_data->saddr, skb->dev);
 	if (!sk)
@@ -1310,15 +1201,15 @@
 	if (sk->state == TCP_LISTEN)
 		goto out_put;
 	/* save primitive for use by the user. */
-	llc_ui->sllc_family = AF_LLC;
-	llc_ui->sllc_arphrd = skb->dev->type;
-	llc_ui->sllc_test   = 1;
-	llc_ui->sllc_xid    = 0;
-	llc_ui->sllc_ua     = 0;
-	llc_ui->sllc_dsap = prim_data->daddr.lsap;
-	memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
-	llc_ui->sllc_ssap = prim_data->saddr.lsap;
-	memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
+	addr->sllc_family = AF_LLC;
+	addr->sllc_arphrd = skb->dev->type;
+	addr->sllc_test   = 1;
+	addr->sllc_xid    = 0;
+	addr->sllc_ua     = 0;
+	addr->sllc_dsap = prim_data->daddr.lsap;
+	memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+	addr->sllc_ssap = prim_data->saddr.lsap;
+	memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
 	/* queue skb to the user. */
 	if (sock_queue_rcv_skb(sk, skb))
 		kfree_skb(skb);
@@ -1337,7 +1228,7 @@
 {
 	struct llc_prim_xid *prim_data = &prim->data->xid;
 	struct sk_buff *skb = prim_data->skb;
-	struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+	struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
 	struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
 						 &prim_data->saddr, skb->dev);
 	if (!sk)
@@ -1345,15 +1236,15 @@
 	if (sk->state == TCP_LISTEN)
 		goto out_put;
 	/* save primitive for use by the user. */
-	llc_ui->sllc_family = AF_LLC;
-	llc_ui->sllc_arphrd = 0;
-	llc_ui->sllc_test   = 0;
-	llc_ui->sllc_xid    = 1;
-	llc_ui->sllc_ua     = 0;
-	llc_ui->sllc_dsap = prim_data->daddr.lsap;
-	memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
-	llc_ui->sllc_ssap = prim_data->saddr.lsap;
-	memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
+	addr->sllc_family = AF_LLC;
+	addr->sllc_arphrd = 0;
+	addr->sllc_test   = 0;
+	addr->sllc_xid    = 1;
+	addr->sllc_ua     = 0;
+	addr->sllc_dsap = prim_data->daddr.lsap;
+	memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+	addr->sllc_ssap = prim_data->saddr.lsap;
+	memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
 	/* queue skb to the user. */
 	if (sock_queue_rcv_skb(sk, skb))
 		kfree_skb(skb);
@@ -1372,7 +1263,7 @@
 {
 	struct llc_prim_unit_data *prim_data = &prim->data->udata;
 	struct sk_buff *skb = prim_data->skb;
-	struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
+	struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
 	struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
 						 &prim_data->saddr, skb->dev);
 	if (!sk)
@@ -1380,88 +1271,15 @@
 	if (sk->state == TCP_LISTEN)
 		goto out_put;
 	/* save primitive for use by the user. */
-	llc_ui->sllc_family = AF_LLC;
-	llc_ui->sllc_arphrd = skb->dev->type;
-	llc_ui->sllc_test   = 0;
-	llc_ui->sllc_xid    = 0;
-	llc_ui->sllc_ua     = 1;
-	llc_ui->sllc_dsap = prim_data->daddr.lsap;
-	memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
-	llc_ui->sllc_ssap = prim_data->saddr.lsap;
-	memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
-	/* queue skb to the user. */
-	if (sock_queue_rcv_skb(sk, skb))
-		kfree_skb(skb);
-out_put:
-	sock_put(sk);
-out:;
-}
-
-/**
- *	llc_ui_ind_conn - handle CONNECT indication
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle CONNECT indication.
- */
-static void llc_ui_ind_conn(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_conn *prim_data = &prim->data->conn;
-	struct sock* sk;
-	struct sk_buff *skb2;
-
-	llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap;
-	sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr,
-				    &prim_data->saddr, prim_data->dev);
-	if (!sk)
-		goto out;
-	if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN)
-		goto out_put;
-	if (prim->data->conn.status)
-		goto out_put; /* bad status. */
-	/* give this connection a link number. */
-	llc_sk(prim_data->sk)->link =
-			llc_ui_next_link_no(llc_sk(prim_data->sk)->laddr.lsap);
-	skb2 = alloc_skb(0, GFP_ATOMIC);
-	if (!skb2)
-		goto out_put;
-	skb2->sk = prim_data->sk;
-	skb_queue_tail(&sk->receive_queue, skb2);
-	sk->state_change(sk);
-out_put:
-	sock_put(sk);
-out:;
-}
-
-/**
- *	llc_ui_ind_data - handle DATA indication
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle CONNECT indication.
- */
-static void llc_ui_ind_data(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_data *prim_data = &prim->data->data;
-	struct sk_buff *skb = prim_data->skb;
-	struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
-	struct sock* sk = llc_sk(prim_data->sk)->handler;
-
-	if (!sk)
-		goto out;
-	sock_hold(sk);
-	if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
-		goto out_put;
-	/* save primitive for use by the user. */
-	llc_ui->sllc_family = AF_LLC;
-	llc_ui->sllc_arphrd = skb->dev->type;
-	llc_ui->sllc_test   = 0;
-	llc_ui->sllc_xid    = 0;
-	llc_ui->sllc_ua     = 0;
-	llc_ui->sllc_dsap   = llc_ui_sk(sk)->sap->laddr.lsap;
-	memcpy(llc_ui->sllc_dmac, llc_sk(prim_data->sk)->laddr.mac,
-	       IFHWADDRLEN);
-	llc_ui->sllc_ssap = llc_sk(prim_data->sk)->daddr.lsap;
-	memcpy(llc_ui->sllc_smac, llc_sk(prim_data->sk)->daddr.mac,
-	       IFHWADDRLEN);
+	addr->sllc_family = AF_LLC;
+	addr->sllc_arphrd = skb->dev->type;
+	addr->sllc_test   = 0;
+	addr->sllc_xid    = 0;
+	addr->sllc_ua     = 1;
+	addr->sllc_dsap = prim_data->daddr.lsap;
+	memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
+	addr->sllc_ssap = prim_data->saddr.lsap;
+	memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
 	/* queue skb to the user. */
 	if (sock_queue_rcv_skb(sk, skb))
 		kfree_skb(skb);
@@ -1471,35 +1289,6 @@
 }
 
 /**
- *	llc_ui_ind_disc - handle DISC indication
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle DISC indication.
- */
-static void llc_ui_ind_disc(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_disc *prim_data = &prim->data->disc;
-	struct sock* sk = llc_sk(prim_data->sk)->handler;
-
-	if (!sk)
-		goto out;
-	sock_hold(sk);
-	if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
-		goto out_put;
-	llc_ui_sk(sk)->core_sk = NULL;
-	sk->shutdown	   = SHUTDOWN_MASK;
-	sk->socket->state  = SS_UNCONNECTED;
-	sk->state	   = TCP_CLOSE;
-	if (!sk->dead) {
-		sk->state_change(sk);
-		sk->dead = 1;
-	}
-out_put:
-	sock_put(sk);
-out:;
-}
-
-/**
  *	llc_ui_indicate - LLC user interface hook into the LLC layer.
  *	@prim: Primitive block provided by the llc layer.
  *
@@ -1517,92 +1306,24 @@
 		case LLC_DATAUNIT_PRIM:
 			llc_ui_ind_dataunit(prim);	break;
 		case LLC_CONN_PRIM:
-			llc_ui_ind_conn(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
+				"is gone for ->ind()...\n", __FUNCTION__);
+			break;
 		case LLC_DATA_PRIM:
-			llc_ui_ind_data(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
+				"is gone for ->ind()...\n", __FUNCTION__);
+			break;
 		case LLC_DISC_PRIM:
-			llc_ui_ind_disc(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
+				"is gone for ->ind()...\n", __FUNCTION__);
+			break;
 		case LLC_RESET_PRIM:
-		case LLC_FLOWCONTROL_PRIM:
 		default:				break;
 	}
 	return 0;
 }
 
 /**
- *	llc_ui_conf_conn - handle CONN confirm.
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle CONN confirm.
- */
-static void llc_ui_conf_conn(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_conn *prim_data = &prim->data->conn;
-	struct llc_opt *llc_core = llc_sk(prim_data->sk);
-	struct sock* sk = llc_core->handler;
-	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
-
-	if (!sk)
-		goto out;
-	sock_hold(sk);
-	if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
-		goto out_put;
-	if (!prim->data->conn.status) {
-		sk->socket->state = SS_CONNECTED;
-		sk->state	  = TCP_ESTABLISHED;
-		llc_ui->core_sk   = prim_data->sk;
-	} else {
-		sk->socket->state = SS_UNCONNECTED;
-		sk->state	  = TCP_CLOSE;
-		llc_ui->core_sk	  = NULL;
-	}
-	sk->state_change(sk);
-out_put:
-	sock_put(sk);
-out:;
-}
-
-/**
- *	llc_ui_conf_data - handle DATA confirm.
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle DATA confirm.
- */
-static void llc_ui_conf_data(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_data *prim_data = &prim->data->data;
-	struct sock* sk = llc_sk(prim_data->sk)->handler;
-
-	if (sk)
-		wake_up(sk->sleep);
-}
-
-/**
- *	llc_ui_conf_disc - handle DISC confirm.
- *	@prim: Primitive block provided by the llc layer.
- *
- *	handle DISC confirm.
- */
-static void llc_ui_conf_disc(struct llc_prim_if_block *prim)
-{
-	struct llc_prim_disc *prim_data = &prim->data->disc;
-	struct sock* sk = llc_sk(prim_data->sk)->handler;
-
-	if (!sk)
-		goto out;
-	sock_hold(sk);
-	if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING)
-		goto out_put;
-	llc_ui_sk(sk)->core_sk = NULL;
-	sk->socket->state      = SS_UNCONNECTED;
-	sk->state	       = TCP_CLOSE;
-	sk->state_change(sk);
-out_put:
-	sock_put(sk);
-out:;
-}
-
-/**
  *	llc_ui_confirm - LLC user interface hook into the LLC layer
  *	@prim: Primitive block provided by the llc layer.
  *
@@ -1614,14 +1335,20 @@
 {
 	switch (prim->prim) {
 		case LLC_CONN_PRIM:
-			llc_ui_conf_conn(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
+				"is gone for ->conf()...\n", __FUNCTION__);
+			break;
 		case LLC_DATA_PRIM:
-			llc_ui_conf_data(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
+				"is gone for ->conf()...\n", __FUNCTION__);
+			break;
 		case LLC_DISC_PRIM:
-			llc_ui_conf_disc(prim);		break;
+			dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
+				"is gone for ->conf()...\n", __FUNCTION__);
+			break;
 		case LLC_RESET_PRIM:			break;
 		default:
-			printk(KERN_ERR "%s: unknown prim %d\n", __FUNCTION__,
+			printk(KERN_ERR "%s: prim not supported%d\n", __FUNCTION__,
 			       prim->prim);
 			break;
 	}
@@ -1651,46 +1378,42 @@
 	off_t pos = 0;
 	off_t begin = 0;
 	struct sock *s;
-	int len = sprintf(buffer, "SocketID SKt Mc local_mac_sap\t  "
-				  "remote_mac_sap\t tx_queue rx_queue st uid "
-				  "link_no\n");
+	int len = sprintf(buffer, "SKt Mc local_mac_sap        "
+				  "remote_mac_sap       tx_queue rx_queue st uid "
+				  "link\n");
 	/* Output the LLC socket data for the /proc filesystem */
 	read_lock_bh(&llc_ui_sockets_lock);
 	for (s = llc_ui_sockets; s; s = s->next) {
-		struct llc_ui_opt *llc_ui = llc_ui_sk(s);
-		len += sprintf(buffer + len, "%p %02X  %02X ", s, s->type,
-			       !llc_ui_mac_null(llc_ui->addr.sllc_mmac));
-		if (llc_ui->sap) {
-			if (llc_ui->dev &&
-			    llc_ui_mac_null(llc_ui->addr.sllc_mmac))
+		struct llc_opt *llc = llc_sk(s);
+
+		len += sprintf(buffer + len, "%2X  %2X ", s->type,
+			       !llc_mac_null(llc->addr.sllc_mmac));
+		if (llc->sap) {
+			if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
 				llc_ui_format_mac(buffer + len,
-						  llc_ui->dev->dev_addr);
+						  llc->dev->dev_addr);
 			else {
-				if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac))
+				if (!llc_mac_null(llc->addr.sllc_mmac))
 					llc_ui_format_mac(buffer + len,
-							llc_ui->addr.sllc_mmac);
+							  llc->addr.sllc_mmac);
 				else
 					sprintf(buffer + len,
 						"00:00:00:00:00:00");
 			}
 			len += MAC_FORMATTED_SIZE;
 			len += sprintf(buffer + len, "@%02X ",
-					llc_ui->sap->laddr.lsap);
+					llc->sap->laddr.lsap);
 		} else
 			len += sprintf(buffer + len, "00:00:00:00:00:00@00 ");
-		llc_ui_format_mac(buffer + len, llc_ui->addr.sllc_dmac);
+		llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
 		len += MAC_FORMATTED_SIZE;
 		len += sprintf(buffer + len,
-				"@%02X %08d:%08d %02d %-3d ",
-				llc_ui->addr.sllc_dsap,
+				"@%02X %8d %8d %2d %-3d ",
+				llc->addr.sllc_dsap,
 				atomic_read(&s->wmem_alloc),
 				atomic_read(&s->rmem_alloc), s->state,
 				SOCK_INODE(s->socket)->i_uid);
-		if (llc_ui->core_sk)
-			len += sprintf(buffer + len, "%-7d\n",
-					llc_sk(llc_ui->core_sk)->link);
-		else
-			len += sprintf(buffer + len, "no_link\n");
+		len += sprintf(buffer + len, "%-4d\n", llc->link);
 		/* Are we still dumping unwanted data then discard the record */
 		pos = begin + len;
 
@@ -1741,7 +1464,7 @@
 SOCKOPS_WRAP(llc_ui, PF_LLC);
 
 static char llc_ui_banner[] __initdata =
-	KERN_INFO "NET4.0 IEEE 802.2 User Interface SAPs, Jay Schulist, 2001\n";
+	KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
 
 int __init llc_ui_init(void)
 {
diff -Nru a/scripts/mkcompile_h b/scripts/mkcompile_h
--- a/scripts/mkcompile_h	Sun Sep 15 19:20:24 2002
+++ b/scripts/mkcompile_h	Sun Sep 15 19:20:24 2002
@@ -67,8 +67,8 @@
 # first line.
 
 if [ -r $TARGET ] && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
+      grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
+      grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
       cmp -s .tmpver.1 .tmpver.2; then
    echo ' (unchanged)'
    rm -f .tmpcompile
diff -Nru a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
--- a/sound/oss/cs46xx.c	Sun Sep 15 19:19:28 2002
+++ b/sound/oss/cs46xx.c	Sun Sep 15 19:19:28 2002
@@ -1935,12 +1935,12 @@
  */
 static /*const*/ struct file_operations cs_midi_fops = {
 	CS_OWNER	CS_THIS_MODULE
-	llseek:		no_llseek,
-	read:		cs_midi_read,
-	write:		cs_midi_write,
-	poll:		cs_midi_poll,
-	open:		cs_midi_open,
-	release:	cs_midi_release,
+	.llseek		= no_llseek,
+	.read		= cs_midi_read,
+	.write		= cs_midi_write,
+	.poll		= cs_midi_poll,
+	.open		= cs_midi_open,
+	.release	= cs_midi_release,
 };
 
 /*
@@ -3819,14 +3819,14 @@
 
 static /*const*/ struct file_operations cs461x_fops = {
 	CS_OWNER	CS_THIS_MODULE
-	llseek:		no_llseek,
-	read:		cs_read,
-	write:		cs_write,
-	poll:		cs_poll,
-	ioctl:		cs_ioctl,
-	mmap:		cs_mmap,
-	open:		cs_open,
-	release:	cs_release,
+	.llseek		= no_llseek,
+	.read		= cs_read,
+	.write		= cs_write,
+	.poll		= cs_poll,
+	.ioctl		= cs_ioctl,
+	.mmap		= cs_mmap,
+	.open		= cs_open,
+	.release	= cs_release,
 };
 
 /* Write AC97 codec registers */
@@ -4226,10 +4226,10 @@
 
 static /*const*/ struct file_operations cs_mixer_fops = {
 	CS_OWNER	CS_THIS_MODULE
-	llseek:		no_llseek,
-	ioctl:		cs_ioctl_mixdev,
-	open:		cs_open_mixdev,
-	release:	cs_release_mixdev,
+	.llseek		= no_llseek,
+	.ioctl		= cs_ioctl_mixdev,
+	.open		= cs_open_mixdev,
+	.release	= cs_release_mixdev,
 };
 
 /* AC97 codec initialisation. */
@@ -5632,12 +5632,12 @@
 MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
 
 struct pci_driver cs46xx_pci_driver = {
-	name:"cs46xx",
-	id_table:cs46xx_pci_tbl,
-	probe:cs46xx_probe,
-	remove:cs46xx_remove,
-	suspend:CS46XX_SUSPEND_TBL,
-	resume:CS46XX_RESUME_TBL,
+	.name= "cs46xx",
+	.id_table= cs46xx_pci_tbl,
+	.probe= cs46xx_probe,
+	.remove= cs46xx_remove,
+	.suspend= CS46XX_SUSPEND_TBL,
+	.resume= CS46XX_RESUME_TBL,
 };
 
 int __init cs46xx_init_module(void)
diff -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
--- a/sound/pci/cs46xx/cs46xx.c	Sun Sep 15 19:20:24 2002
+++ b/sound/pci/cs46xx/cs46xx.c	Sun Sep 15 19:20:24 2002
@@ -182,13 +182,13 @@
 }
 
 static struct pci_driver driver = {
-	name: "Sound Fusion CS46xx",
-	id_table: snd_cs46xx_ids,
-	probe: snd_card_cs46xx_probe,
-	remove: __devexit_p(snd_card_cs46xx_remove),
+	.name = "Sound Fusion CS46xx",
+	.id_table = snd_cs46xx_ids,
+	.probe = snd_card_cs46xx_probe,
+	.remove = __devexit_p(snd_card_cs46xx_remove),
 #ifdef CONFIG_PM
-	suspend: snd_card_cs46xx_suspend,
-	resume: snd_card_cs46xx_resume,
+	.suspend = snd_card_cs46xx_suspend,
+	.resume = snd_card_cs46xx_resume,
 #endif
 };
 
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	Sun Sep 15 19:19:29 2002
+++ b/sound/pci/cs46xx/cs46xx_lib.c	Sun Sep 15 19:19:29 2002
@@ -1055,17 +1055,17 @@
 	formats:		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
 				 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
-	rates:			SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	rate_min:		5500,
-	rate_max:		48000,
-	channels_min:		1,
-	channels_max:		2,
-	buffer_bytes_max:	(256 * 1024),
-	period_bytes_min:	CS46XX_PERIOD_SIZE,
-	period_bytes_max:	CS46XX_PERIOD_SIZE,
-	periods_min:		CS46XX_FRAGS,
-	periods_max:		1024,
-	fifo_size:		0,
+	.rates			= SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min		= 5500,
+	.rate_max		= 48000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (256 * 1024),
+	.period_bytes_min	= CS46XX_PERIOD_SIZE,
+	.period_bytes_max	= CS46XX_PERIOD_SIZE,
+	.periods_min		= CS46XX_FRAGS,
+	.periods_max		= 1024,
+	.fifo_size		= 0,
 };
 
 static snd_pcm_hardware_t snd_cs46xx_capture =
@@ -1074,18 +1074,18 @@
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
 				 SNDRV_PCM_INFO_RESUME),
-	formats:		SNDRV_PCM_FMTBIT_S16_LE,
-	rates:			SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
-	rate_min:		5500,
-	rate_max:		48000,
-	channels_min:		2,
-	channels_max:		2,
-	buffer_bytes_max:	(256 * 1024),
-	period_bytes_min:	CS46XX_PERIOD_SIZE,
-	period_bytes_max:	CS46XX_PERIOD_SIZE,
-	periods_min:		CS46XX_FRAGS,
-	periods_max:		1024,
-	fifo_size:		0,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+	.rate_min		= 5500,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (256 * 1024),
+	.period_bytes_min	= CS46XX_PERIOD_SIZE,
+	.period_bytes_max	= CS46XX_PERIOD_SIZE,
+	.periods_min		= CS46XX_FRAGS,
+	.periods_max		= 1024,
+	.fifo_size		= 0,
 };
 
 static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
@@ -1141,49 +1141,49 @@
 }
 
 snd_pcm_ops_t snd_cs46xx_playback_ops = {
-	open:			snd_cs46xx_playback_open,
-	close:			snd_cs46xx_playback_close,
-	ioctl:			snd_pcm_lib_ioctl,
-	hw_params:		snd_cs46xx_playback_hw_params,
-	hw_free:		snd_cs46xx_playback_hw_free,
-	prepare:		snd_cs46xx_playback_prepare,
-	trigger:		snd_cs46xx_playback_trigger,
-	pointer:		snd_cs46xx_playback_direct_pointer,
+	.open			= snd_cs46xx_playback_open,
+	.close			= snd_cs46xx_playback_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params		= snd_cs46xx_playback_hw_params,
+	.hw_free		= snd_cs46xx_playback_hw_free,
+	.prepare		= snd_cs46xx_playback_prepare,
+	.trigger		= snd_cs46xx_playback_trigger,
+	.pointer		= snd_cs46xx_playback_direct_pointer,
 };
 
 snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = {
-	open:			snd_cs46xx_playback_open,
-	close:			snd_cs46xx_playback_close,
-	ioctl:			snd_pcm_lib_ioctl,
-	hw_params:		snd_cs46xx_playback_hw_params,
-	hw_free:		snd_cs46xx_playback_hw_free,
-	prepare:		snd_cs46xx_playback_prepare,
-	trigger:		snd_cs46xx_playback_trigger,
-	copy:			snd_cs46xx_playback_copy,
-	pointer:		snd_cs46xx_playback_indirect_pointer,
+	.open			= snd_cs46xx_playback_open,
+	.close			= snd_cs46xx_playback_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params		= snd_cs46xx_playback_hw_params,
+	.hw_free		= snd_cs46xx_playback_hw_free,
+	.prepare		= snd_cs46xx_playback_prepare,
+	.trigger		= snd_cs46xx_playback_trigger,
+	.copy			= snd_cs46xx_playback_copy,
+	.pointer		= snd_cs46xx_playback_indirect_pointer,
 };
 
 snd_pcm_ops_t snd_cs46xx_capture_ops = {
-	open:			snd_cs46xx_capture_open,
-	close:			snd_cs46xx_capture_close,
-	ioctl:			snd_pcm_lib_ioctl,
-	hw_params:		snd_cs46xx_capture_hw_params,
-	hw_free:		snd_cs46xx_capture_hw_free,
-	prepare:		snd_cs46xx_capture_prepare,
-	trigger:		snd_cs46xx_capture_trigger,
-	pointer:		snd_cs46xx_capture_direct_pointer,
+	.open			= snd_cs46xx_capture_open,
+	.close			= snd_cs46xx_capture_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params		= snd_cs46xx_capture_hw_params,
+	.hw_free		= snd_cs46xx_capture_hw_free,
+	.prepare		= snd_cs46xx_capture_prepare,
+	.trigger		= snd_cs46xx_capture_trigger,
+	.pointer		= snd_cs46xx_capture_direct_pointer,
 };
 
 snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = {
-	open:			snd_cs46xx_capture_open,
-	close:			snd_cs46xx_capture_close,
-	ioctl:			snd_pcm_lib_ioctl,
-	hw_params:		snd_cs46xx_capture_hw_params,
-	hw_free:		snd_cs46xx_capture_hw_free,
-	prepare:		snd_cs46xx_capture_prepare,
-	trigger:		snd_cs46xx_capture_trigger,
-	copy:			snd_cs46xx_capture_copy,
-	pointer:		snd_cs46xx_capture_indirect_pointer,
+	.open			= snd_cs46xx_capture_open,
+	.close			= snd_cs46xx_capture_close,
+	.ioctl			= snd_pcm_lib_ioctl,
+	.hw_params		= snd_cs46xx_capture_hw_params,
+	.hw_free		= snd_cs46xx_capture_hw_free,
+	.prepare		= snd_cs46xx_capture_prepare,
+	.trigger		= snd_cs46xx_capture_trigger,
+	.copy			= snd_cs46xx_capture_copy,
+	.pointer		= snd_cs46xx_capture_indirect_pointer,
 };
 
 static void snd_cs46xx_pcm_free(snd_pcm_t *pcm)
@@ -1266,20 +1266,20 @@
 
 static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 {
-	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
-	name: "DAC Volume",
-	info: snd_cs46xx_vol_info,
-	get: snd_cs46xx_vol_get,
-	put: snd_cs46xx_vol_put,
-	private_value: BA1_PVOL,
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "DAC Volume",
+	.info = snd_cs46xx_vol_info,
+	.get = snd_cs46xx_vol_get,
+	.put = snd_cs46xx_vol_put,
+	.private_value = BA1_PVOL,
 },
 {
-	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
-	name: "ADC Volume",
-	info: snd_cs46xx_vol_info,
-	get: snd_cs46xx_vol_get,
-	put: snd_cs46xx_vol_put,
-	private_value: BA1_CVOL,
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "ADC Volume",
+	.info = snd_cs46xx_vol_info,
+	.get = snd_cs46xx_vol_get,
+	.put = snd_cs46xx_vol_put,
+	.private_value = BA1_CVOL,
 }};
 
 int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
@@ -1465,16 +1465,16 @@
 
 static snd_rawmidi_ops_t snd_cs46xx_midi_output =
 {
-	open:           snd_cs46xx_midi_output_open,
-	close:          snd_cs46xx_midi_output_close,
-	trigger:        snd_cs46xx_midi_output_trigger,
+	.open           = snd_cs46xx_midi_output_open,
+	.close          = snd_cs46xx_midi_output_close,
+	.trigger        = snd_cs46xx_midi_output_trigger,
 };
 
 static snd_rawmidi_ops_t snd_cs46xx_midi_input =
 {
-	open:           snd_cs46xx_midi_input_open,
-	close:          snd_cs46xx_midi_input_close,
-	trigger:        snd_cs46xx_midi_input_trigger,
+	.open           = snd_cs46xx_midi_input_open,
+	.close          = snd_cs46xx_midi_input_close,
+	.trigger        = snd_cs46xx_midi_input_trigger,
 };
 
 int __devinit snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
@@ -1628,7 +1628,7 @@
 }
 
 static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
-	read: snd_cs46xx_io_read,
+	.read = snd_cs46xx_io_read,
 };
 
 static int __devinit snd_cs46xx_proc_init(snd_card_t * card, cs46xx_t *chip)
@@ -2271,7 +2271,7 @@
 	struct cs_card_type *cp;
 	u16 ss_card, ss_vendor;
 	static snd_device_ops_t ops = {
-		dev_free:	snd_cs46xx_dev_free,
+		.dev_free	= snd_cs46xx_dev_free,
 	};
 	
 	*rchip = NULL;
